Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Petkit Water Fountain Support #28

Open
cjattard opened this issue Nov 24, 2022 · 25 comments
Open

Feature Request: Petkit Water Fountain Support #28

cjattard opened this issue Nov 24, 2022 · 25 comments

Comments

@cjattard
Copy link

cjattard commented Nov 24, 2022

Hello, I have this service up and running on my Pura X litterbox and petkit feeder - it's probably the killer integration for me for home assistant! so Thankyou.

I have recently bought the Petkit EVERSWEET 3 PRO water fountain, the API is exposing the following information:

  • desiccant
  • feed_amount
  • feed_times
  • state
  • food_state
  • feeding

I presume these attributes would need assigning some form of type to be able to be used by home assistant.

full disclosure I am a novice at coding but anything I can do to help provide support or diagnostics guidance I would be more than up for learning here.

Thanks

@cjattard
Copy link
Author

{"result":[{"breakdownWarning":0,"createdAt":"2022-11-23T14:43:13.000Z","expectedCleanWater":0,"expectedUseElectricity":0.0,"filterExpectedDays":0,"filterPercent":94,"filterUpdatedAt":"2022-11-25T09:27:07.000Z","filterWarning":0,"firmware":47,"hardware":2,"id":100027248,"isNightNoDisturbing":0,"lackWarning":0,"mac":"xxxxxxxxxx","mode":2,"name":"Water Bowl","powerStatus":1,"recordAutomaticAddWater":0,"relation":{"userId":"10022xxxx"},"runStatus":0,"secret":"c1b6f470c84c","settings":{"disturbConfig":2,"disturbMultiTime":[{"repeats":"1,2,3,4,5,6,7","time":[1320,360]}],"lampRingBrightness":1,"lampRingGoOutTime":1440,"lampRingLightUpTime":0,"lampRingSwitch":1,"lightConfig":2,"lightMultiTime":[{"repeats":"1,2,3,4,5,6,7","time":[360,1320]}],"noDisturbingEndTime":360,"noDisturbingStartTime":1320,"noDisturbingSwitch":0,"smartSleepTime":1,"smartWorkingTime":2},"sn":"31220321S3xxxx","timezone":0.0,"todayCleanWater":0,"todayPumpRunTime":33619,"todayUseElectricity":0.0,"typeCode":4,"updateAt":"2022-11-25T09:27:07.000Z","userId":"10022xxxx","voltage":-1,"waterPumpRunTime":151118}]}

@cjattard
Copy link
Author

img5.petkit.cn/discovery/2022/8/17/62fc9686c09fd9000d48ab48Zxxxxxx","maintenanceMode":"http://img5.petkit.cn/discovery/2022/8/17/62fc973ec09fd9000d48ab5eixxxxxx"}},"w5":{"deviceData":{"recordAutomaticAddWater":1,"timezone":0,"updateAt":"2022-08-08T07:26:28.000Z","secret":"c4dadxxxxxx","mac":"a4c1xxxxxx","relation":{"petIds":["1331669"],"userId":"596381"},"mode":2,"waterPumpRunTime":4064239,"createdAt":"2022-03-14T01:55:44.000Z","expectedCleanWater":-1,"powerStatus":1,"breakdownWarning":0,"id":-1,"sn":"31220226S30041","filterWarning":0,"firmware":36,"lackWarning":0,"runStatus":1,"hardware":2,"settings":{"smartSleepTime":1,"noDisturbingEndTime":360,"noDisturbingStartTime":1320,"noDisturbingSwitch":0,"smartWorkingTime":3,"lampRingLightUpTime":0,"lampRingBrightness":2,"lampRingGoOutTime":1440,"lampRingSwitch":1},"isNightNoDisturbing":0,"todayPumpRunTime":23040,"filterUpdatedAt":"2022-08-08T07:26:28.000Z","todayCleanWater":500,"todayUseElectricity":0.0048,"userId":"596381","typeCode":4,"voltage":0,"filterExpectedDays":15,"filterPercent":37.5,"name":"\u667A\u80FD\u996E\u6C34\u673A","expectedUseElectricity":0.0048},"shareUrl":{"url":"https://bit.ly/3SYYQEq"},"gifs":{"springWater":"http://img5.petkit.cn/discovery/2022/8/17/62fc99f7c09fd9000xxxxxx","stopWater":"http://img5.petkit.cn/discovery/2022/8/23/6304bbec102cc8000dexxxxxx","smartMode":"http://img5.petkit.cn/discovery/2022/8/29/630c2baee3bc46000d3xxxxxx"}},

@tobycth3
Copy link

+1

@al-one
Copy link
Contributor

al-one commented Jan 14, 2023

Need more packet capture records.

@tobycth3
Copy link

'devices': [{'type': 'W5', 'data': {'mode': 1, 'createdAt': '2023-01-09T23:21:36.000Z', 'settings': {'disturbConfig': 2, 'disturbMultiTime': [], 'lampRingBrightness': 1, 'lampRingGoOutTime': 1320, 'lampRingLightUpTime': 480, 'lampRingSwitch': 1, 'lightConfig': 2, 'lightMultiTime': [], 'noDisturbingEndTime': 360, 'noDisturbingStartTime': 1320, 'noDisturbingSwitch': 0, 'smartSleepTime': 3, 'smartWorkingTime': 3}, 'name': 'EVERSWEET', 'id': xxxxxx, 'filterWarning': 0, 'lackWarning': 0, 'runStatus': 1, 'relation': {'petIds': ['xxxx', 'xxxxx'], 'userId': 'xxxx'}, 'typeCode': 4}},

I think the key items are
'filterWarning': 0, 'lackWarning': 0, 'runStatus': 1

@tobycth3
Copy link

tobycth3 commented Jan 15, 2023

Quick and dirty fix to get the status if the device is running or needs water. In init.py change line 335:

@property
def state(self):
    sta = self.data.get('state') or 0
    dic = {
        '1': 'online',
        '2': 'offline',
        '3': 'feeding',
        '4': 'mate_ota',
        '5': 'device_error',
        '6': 'battery_mode',
    }
    if self.device_type == 'w5':
        sta = self.data.get('lackWarning')
        dic = {
            '0': 'OK',
            '1': 'ERROR',
        }
    return dic.get(f'{sta}'.strip(), sta)

@cjattard
Copy link
Author

Quick and dirty fix to get the status if the device is running or needs water. In init.py change line 335:

@property
def state(self):
    sta = self.data.get('state') or 0
    dic = {
        '1': 'online',
        '2': 'offline',
        '3': 'feeding',
        '4': 'mate_ota',
        '5': 'device_error',
        '6': 'battery_mode',
    }
    if self.device_type == 'w5':
        sta = self.data.get('lackWarning')
        dic = {
            '0': 'OK',
            '1': 'ERROR',
        }
    return dic.get(f'{sta}'.strip(), sta)

Thankyou, just added this workaround and it works a treat. thank you.

@al-one
Copy link
Contributor

al-one commented Jan 16, 2023

Added in 86b0fe0

@yieldhog
Copy link

yieldhog commented Jan 17, 2023

Hi, I purchased a new Petkit EVERSWEET 3 PRO water fountain today. The updated integration is able to pull it in, but, the data seems off. Fountain is full, new filter, etc. working in the official app. The HACS integration pulls in the following:

binary_sensor.w5_1XXXXXX95_food_state = on [device class problem, therefore saying its empty? It's full]
sensor.w5_1XXXXXX95_state = off [the fountain is on and functioning]

I did notice that the sensors are > 1 hr old, maybe not picking it up? Is there a way to force an update? Everything is functional on the official app. Happy to help troubleshoot, US [Americas] based. I have a feeder and litterbox both working well.

Thanks

@RobertD502
Copy link

@yieldhog Regarding the water fountain status - this is due to how Petkit handles updating the data. I've had this problem for months now as I originally integrated the water fountain via Node Red. If a compatible feeder/petkit device with bluetooth is paired to the water fountain (for remote access), the associated device doesn't seem to be periodically polling the water fountain to update its status on PetKit's servers. Updating the status requires you to open up the PetKit app which will then initiate updating the data (either via direct bluetooth connection from your phone or the remote access initiating the associated device to start a bluetooth connection to the water fountain).

It is a big flaw in how they have the system set up right now and I've complained to them about this months ago - Even using their own app, there is no way of knowing the water is out via a notification from the PetKit app unless you manually open up the PetKit app and start the bluetooth connection one way or the other (via direct connection or via associated device during remote access).

I'll have to sniff around and see if something is sent during remote access that can be replicated as a means of getting associated devices to connect to the water fountain to poll for an update.

@RobertD502
Copy link

@al-one I have been able to sniff out the ble endpoints needed to force an associated device to poll the water fountain for updates.

Step 1: A POST request is made to the ble/connect endpoint:

POST /latest/ble/connect HTTP/1.1
Host: api.petkt.com
X-Session: <Redacted>
Content-Type: application/x-www-form-urlencoded
Accept: */*
X-Location: <Redacted>
Proxy-Connection: keep-alive
X-Timezone: -5.0
F-Session: <Redacted>
Accept-Language: en-US;q=1, it-US;q=0.9
Accept-Encoding: gzip, deflate
X-Api-Version: 8.28.0
X-Client: ios(15.1;iPhone14,3)
Content-Length: 40
User-Agent: PETKIT/8.28.0 (iPhone; iOS 15.1; Scale/3.00)
Connection: keep-alive
X-TimezoneId: America/New_York
X-Img-Version: 1
X-Locale: en_US

The body is a URLEncoded form as seen below:

bleId=<Water Fountain ID>
mac=<Water Fountain MAC>
type=<Explained Below>

Regarding the type field: This is a combination of the "typeCode" of the device that is associated with the Water Fountain and the "typeCode" of the Water Fountain - For example, the D4 feeder that I have linked to my Water Fountain has a typeCode of 1 and the Water Fountain has a typeCode of 4. So, in the URLEncoded form above I'd set the type to 14 to get the D4 feeder to initiate a BLE connection to the W5 Water Fountain.

If the connection is successful the response body is as follows:

{
    "result": {
        "state": 1
    }
}

Step 2: A POST request is made to the ble/poll endpoint:

The requests is the exact same as in Step 1, except to the poll endpoint instead of connect endpoint. Note this requests also sends a URLEncoded form with the bleId, mac, and type.

The response to this call is as follows:

{
    "result": 0
}

If the device fails to connect and the connection is timed out, the response is as follows:

{
    "result": -1
}

At this point, data for the water fountain should reflect up-to-date data. Having polled the device, we can then close the connection.

Step 3: Close the BLE connection by making a POST request to the ble/cancel endpoint:

The requests is the exact same format as seen in step one and uses the same URLEncoded form.
If we don't disconnect then the connection will eventually time out.

Determine if user has set up BLE relay:

In order to determine if polling the Water Fountain via a BLE connection is even possible, we first need to determine if a user has set up the relay function. This can be easily done by looking at the response from the http://api.petkt.com/latest/discovery/device_roster endpoint. If a relay is set up, the key hasRelay is set to True.

Determine the associated device:

In order to compose the correct type to be sent for the BLE connection, we need to know what device is being connected to the Water Fountain. One way to do this is to send a POST request to http://api.petkt.com/latest/ble/ownSupportBleDevices with no content. The response contains a list of devices that support a remote connection and can be used to connect to the Water Fountain.

Since I only have one, my response looks like this:

{
    "result": [
        {
            "id": Redacted,
            "lowVersion": 0,
            "mac": "Redacted",
            "name": "Milo’s Feeder",
            "pim": 1,
            "sn": "Redacted",
            "typeId": 11
        }
    ]
}

We can use this endpoint to look up the device, by id, and fetch its typeCode. This can then be used to create the correct type to be sent to the ble/connect and ble/poll endpoints.

Only issue I can see with this is a scenario where a user has multiple supported BLE relay devices, so, we'd need to see the response that would be generated there and how the BLE connection is handled in such a scenario.

Hope this helps!

@al-one
Copy link
Contributor

al-one commented Jan 31, 2023

Can these APIs be called through service: petkit.request_api in automation ?

@RobertD502
Copy link

It could, but there are a few problems that would need to be addressed:

  1. The request header currently doesn't specify the content-type
  2. Users would need to manually figure out the codeType of the devices.

I wouldn't have a problem doing this on my install, but it may be beyond reach for every day HA users. Handling this internally in the integration would be more user friendly.

@yieldhog
Copy link

@yieldhog Regarding the water fountain status - this is due to how Petkit handles updating the data. I've had this problem for months now as I originally integrated the water fountain via Node Red. If a compatible feeder/petkit device with bluetooth is paired to the water fountain (for remote access), the associated device doesn't seem to be periodically polling the water fountain to update its status on PetKit's servers. Updating the status requires you to open up the PetKit app which will then initiate updating the data (either via direct bluetooth connection from your phone or the remote access initiating the associated device to start a bluetooth connection to the water fountain).

It is a big flaw in how they have the system set up right now and I've complained to them about this months ago - Even using their own app, there is no way of knowing the water is out via a notification from the PetKit app unless you manually open up the PetKit app and start the bluetooth connection one way or the other (via direct connection or via associated device during remote access).

I'll have to sniff around and see if something is sent during remote access that can be replicated as a means of getting associated devices to connect to the water fountain to poll for an update.

@RobertD502 Thanks, I think that's exactly right. My water fountain ran out a couple of times and I wasn't notified until I actually opened the app and checked, defeating the entire purpose of the system. This is beyond my scope in terms of programming, but I'm happy to test any possible solutions.

@yieldhog
Copy link

@RobertD502 would it matter if I only have one BLE device? I have a Feeder Mini (wifi, works great w/ this integration) and Pura X litter box (wifi, also works great).

al-one added a commit that referenced this issue Jan 31, 2023
@RobertD502
Copy link

@RobertD502 would it matter if I only have one BLE device? I have a Feeder Mini (wifi, works great w/ this integration) and Pura X litter box (wifi, also works great).

Do you have the relay set up in the app (I don't own one, but I believe the Pura X is compatible and can be used as a relay for the water fountain)? I have two feeder minis, but had to get a third (D4 - I think it is the fresh element solo) because the mini can't be used as a relay for the water fountain.

@cjattard
Copy link
Author

cjattard commented Jan 31, 2023

I have the Pura x so happy to help with any testing if it’s useful.

I was wondering. In the config in this amazing repo we can specify the refresh / polling rate. (Mine is currently 3 mins) could there be the ability to include the app code in that module - tricking Petkit into thinking the app was opened?

@RobertD502
Copy link

I'm not quite sure what you mean by my app.

@RobertD502
Copy link

@cjattard The stuff that I posted was to showcase how the BLE relay works. It most certainly can be implemented. However, it looks like the original author prefers to have users make undefined API calls via the service in this integration. The downside to that is that you have to figure out the typeCodes of the two devices (the main device and the water fountain) on your own in order to construct the proper type key that is sent.

@yieldhog
Copy link

yieldhog commented Feb 1, 2023

@RobertD502 I took a look at the Petkit app and it appears to be periodically relaying .. unfortunately my devices are probably 30' apart so they may not have a great BLE connection. I am happy to try and test using the service call, but, I'm not exactly sure what commands to send. For example, I tried one of your urls above and received {"error":{"code":5,"msg":"Login session expired. Please log in again."}} -- not exactly sure how to format to login.

@RobertD502
Copy link

If you took a look at the PETKIT app (opened it) then it automatically turned on the relay at that time, which would falsely be perceived as the relay periodically turning on and updating data.

Regarding using the endpoints: that I would take up with the original author. I've deleted the integration as I'm not a fan of how sensors are handled/not grouped by device and implemented my own way of pulling in data.

@RobertD502
Copy link

RobertD502 commented Feb 3, 2023

@yieldhog Just got done with the initial code for the backend library. It is limited to D4 feeders, mini feeders, and w5 water fountains at this moment. I'll get to work on building out the integration starting tomorrow and will definitely need some testers / access to litter boxes to get them integrated properly.

@yieldhog
Copy link

yieldhog commented Feb 3, 2023

@RobertD502 very cool, I’m happy to help test

@cjattard
Copy link
Author

cjattard commented Feb 3, 2023

i'm happy to test too, got the Pura X litter box, Fresh Element feeder, and the w5 water bowl.

@RobertD502
Copy link

If either of you use discord, you can reach me at the Home Assistant PetKit server. I can keep you updated on there/discuss questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants