Petsafe Smart Feed 2.0

I finally figured out a way to create sensors for my Smart Feed Automatic Dog and Cat Feeder, 2nd Generation pet feeder.

I used this PetSafe Smart Feed - Python API to create some curl commands to request the required token and device id, and then created some {{REST}} sensors. If you dig around in the devices.py and api.py you will see you can do a lot more than just create sensors if you want to.

To get started:

You first need to request a code from PetSafe. Just replace [email protected] with the email address you have registered email with PetSafe and request the following POST: (You may need to create a single-line curl command to get it to work, remove the \ and return.)

curl --request POST \
  --url https://users-api.ps-smartfeed.cloud.petsafe.net/users/ \
  --header 'Content-Type: application/json' \
  --data '{ "email": "[email protected]" }'

You will very quickly receive an email from PetSafe with your code:

It should look something like this:

[email protected]

**400-632** is your code

Now replace [email protected] with your registered email address and replace the XXX-XXX with the code PetSafe sent:

curl --request POST \
  --url https://users-api.ps-smartfeed.cloud.petsafe.net/users/tokens \
  --header 'Content-Type: application/json' \
  --data '{ "email": "[email protected]", "code": "XXX-XXX" }'

The response should look somethis like this:

{
“identityId”: “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”,
“accessToken”: “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
“refreshToken”: “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx” ,
“deprecatedToken”: “xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx”
}

Copy the “deprecatedToken” and save it in Secrets.yaml as smartfeed_token: xxxxxx…

Next you need to get the feeder id (PetSafe calls it thing_name) to work with the feeder. You can use another curl command or create a sensor with the information you have to retrive the “thing_name”.

Replace the yourtoken with the deprecatedToken.

curl --request GET \
  --url https://api.ps-smartfeed.cloud.petsafe.net/api/v2/feeders \
  --header 'Content-Type: application/json' \
  --header 'Token: yourtoken'

Using the curl command, the response should look something like this:

[
  {
    "id": 29066,
    "serial": null,
    "thing_name": "**x-XXXXXXXXXXXX**",
    "battery_voltage": "40",
    "region": "",
    "connection_status": 2,
    "is_food_low": 0,
    "is_adapter_installed": true,
    "is_batteries_installed": false,
    "firmware_version": "V2.2.0",
    "product_name": "SmartFeed_2.0",
    "revision_desired": 56,
    "revision_reported": 56,
    "food_sensor_current": 0,
    "food_sensor_reference": 0,
    "network_rssi": -63,
    "network_snr": 24,
    "connection_status_timestamp": "2021-03-14 21:39:19",
    "created_at": "2020-01-05 20:47:35",
    "deleted_at": null,
    "settings": {
      "friendly_name": "Smart Feed",
      "paused": false,
      "slow_feed": true,
      "child_lock": false,
      "notify_on_feed": true,
      "notify_on_connection_state_change": true,
      "notify_on_low_food": true,
      "notify_on_empty_food": true,
      "notify_on_error": true,
      "notify_on_community_message": true,
      "timezone": "America\/New_York",
      "ssid": null,
      "pet_type": "cat",
      "updated_at": "2020-12-25 14:28:43"
    },
    "schedules": [
      {
        "time": "7:00",
        "amount": 1,
        "id": 501089,
        "updated_at": "2021-03-14 07:17:35"
      },
      {
        "time": "17:00",
        "amount": 2,
        "id": 501090,
        "updated_at": "2021-03-14 07:17:35"
      }
    ]
  }
]

This includes the complete response. You need the “thing_name” to get information from an individual feeder.

Instead, If you want to you can set up a sensor to start using it in HA. In my configuration.yaml file I created the sensor “smartfeed_feeders”. In this example I only set up json_attributes for 3 items: thing_name, settings, and schedules. You could also include any of the other attributes you might want.

  - platform: rest
    name: smartfeed_feeders
    method: GET
    json_attributes:
      - data
    resource: https://api.ps-smartfeed.cloud.petsafe.net/api/v2/feeders/
    headers:
      Content-Type: application/json
      token: !secret smartfeed_token
    value_template: "{{ states.sensor.smartfeed_feeders.attributes['thing_name'] }}"
    json_attributes:
      - thing_name
      - settings
      - schedules

The sensor.smartfeed_feeders in the Development Tools - STATES looks like this:

thing_name: x-XXXXXXXXXXXX
settings:
  friendly_name: Smart Feed
  paused: false
  slow_feed: true
  child_lock: false
  notify_on_feed: true
  notify_on_connection_state_change: true
  notify_on_low_food: true
  notify_on_empty_food: true
  notify_on_error: true
  notify_on_community_message: true
  timezone: America/New_York
  ssid: null
  pet_type: cat
  updated_at: '2020-12-25 14:28:43'
schedules:
  - time: '7:00'
    amount: 1
    id: 501089
    updated_at: '2021-03-14 07:17:35'
  - time: '17:00'
    amount: 2
    id: 501090
    updated_at: '2021-03-14 07:17:35'
friendly_name: smartfeed_feeders

After getting the “thing_name”, I setup another sensor to retrieve data from the individual feeder. On the resource line replace x-XXXXXXXXXXXX with your retrieved “thing_name”.

  - platform: rest
    name: smartfeed_last_messages
    method: GET
    json_attributes:
      - data
    resource: https://api.ps-smartfeed.cloud.petsafe.net/api/v2/feeders/x-XXXXXXXXXXXX/messages?days=1
    headers:
      Content-Type: application/json
      token: !secret smartfeed_token
    value_template: "{{ states.sensor.smartfeed_last_messages.attributes['message_type'] }}"
    json_attributes:
      - "message_type"
      - "created_at"
      - "payload"

The sensor.smartfeed_last_messages will look like this in Development Tools - STATES:

message_type: FEED_DONE
created_at: '2021-03-15 11:00:06'
payload:
  isFoodLow: 0
  amount: 1
  source: schedule
  h: 11
  m: 0
  sensorReading1Infrared: 29537
  sensorReading2Infrared: 29534
  time: 1615806006
friendly_name: smartfeed_last_messages

The “created_at” is UTC and the “time” is EPOCH.

You will need to play around with the Developer Tools - TEMPLATE to work with the data, as an example:

{{ states.sensor.smartfeed_last_messages.attributes[‘payload’][‘time’] }} = 1615806006

{{ states.sensor.smartfeed_last_messages.attributes[‘payload’][‘time’] | timestamp_local}} = 2021-03-15 18:00:07

I just discovered the api a few days ago and just started working with it. I know an integration could probably be created by someone.

4 Likes

This is really great work. Thank you!

Had to set up some sensor templates/calculations to get battery % to show up as a usable attribute. Hoping someone can take your work and build an official integration.

Here’s my code donation for anyone that wants their feeder battery to read as a normal 1-100% and as its own sensor:

platform: template
  sensors:
    dog_feeder_battery:
      value_template: "{{ ((state_attr('sensor.dog_feeder', 'battery_voltage') | int - 26000) / 3124 * 100) | round(0) }}"
      friendly_name: 'Dog Feeder Battery'
1 Like

This is great! Actually bought one yesterday and was sad to learn that this was not yet integrated with HA until I saw your post!

Your sensors work perfectly and with some templates and integration with history/record this can definitely be something!

Don’t know how to create comands or anything but I think to add even more value to this is to be able to at least create a command to start a feed, if any of you is able to create one that would be perfect. I will look into it on my spare time (completely noob here thou, so it will take some time).

Ok guys! Wow! Really impressed with myself! I know zero about python or sending curls but with all of what you’ve shared above I managed to find the curl command to do the feeding!

Now need to convert to a Rest command (will post it later). The below curl will make your feeder, feed 1/8 cup at normal speed:

  curl --request POST \
  --url https://api.ps-smartfeed.cloud.petsafe.net/api/v2/feeders/THING_NAME/meals \
  --header 'Content-Type: application/json' \
  --header 'Token: YOURTOKEN'
  --data '{ "amount": "1", "slow_feed": "False"}'

To increase the “amount” you feed you just need to change the “amount” number to 1, 2, 3, etc. (not sure yet what is the max) and it increments 1/8 every time you increase a level ie. 1=1/8, 2=1/4, 3=3/8, etc. You can also switch the “slow_feed” on by changing to “True”.

Hope this helps.

Here you go, merry xmas! Made it so you can edit the amount and slow_feed when calling the service:

rest_command: 
 feed_the_tigers:
    method: post
    verify_ssl: false
    url: "https://api.ps-smartfeed.cloud.petsafe.net/api/v2/feeders/THING_NAME/meals"
    headers:
      Content-Type: application/json
      token: YOURTOKEN
    payload: '{"amount": "{{ amount }}", "slow_feed": "{{ slow_feed }}"}'

It would interesting to see if there a way to use this same method for the ScoopFree litter boxes. Time to do some testing and reading.

Ia that the second gen? As I had the 1st and it wasn’t smart. You should be able to query the API as above. One thing I found recently is that you have to limit any queries to a 5 min period, less then that you will be locked out and will have to request petsafe to unlock your account.

I think they are both second generations. They have wifi and I can use the app to check on usage and trigger the rake.

Then you should defo be able to do something!

It appears to be a different url for the litter boxes…

https://api.ps-smartfeed.cloud.petsafe.net

how did you discover the root API URL?

Oh! Well on the first post it quotes this GitHub - Techzune/petsafe_smartfeed: Connect and control a PetSafe Smart Feed device using the PetSafe-SmartFeed API.

but only refers to smart feeders I’m afraid. You probably need to do a bit more research…did you try to run the above get commands to see what would happen?

Thanks for posting this, just wondering what I am doing wrong though:

Template variable warning: 'mappingproxy object' has no attribute 'thing_name' when rendering '{{ states.sensor.smartfeed_feeders.attributes['thing_name'] }}'
Template variable warning: 'mappingproxy object' has no attribute 'message_type' when rendering '{{ states.sensor.smartfeed_last_messages.attributes['message_type'] }}'

I am able to get the same json output from curl as you, so I know my tokens are working.

Thanks!

Can you post your config?

I’m using the sensors as-is at the moment, the error comes from the smartfeed_feeders rest sensor. My configuration check is successful with no noted problems.

I remember now! I had the same issue a while ago, for some reason rest sensor stopped working, tried to debug it but ended up migrating all sensors to node red.

ah ok, yeah I can see that; it’s really annoying to debug in hass itself. Do you mind sharing your flow? If not, no worries and thanks for the tip.

No worries! I’ll send it tomorrow morning!

Here you go:

There are 2 flows, one to GET the information from the pet feeder limited to every 5 min, not less otherwise they will block your account from making calls to the API (the sensor for home assistant is called “Notification” on my example and it’s only extracting the last entry of the payload which has ‘message_type’, ‘created_at’ and ‘payload’, you may want to extract other details):

NOTE: Don’t try to import the below as is as I have deleted sensitive information, you should be able to extract the details you need for each node thou. Let me know if you bump into any troubles, however I must warn you I just follow whatever google tells me to do :sweat_smile:

    {
        "id": "2ab418687c942886",
        "type": "inject",
        "z": "d115cf7e9caa769f",
        "name": "",
        "props": [],
        "repeat": "310",
        "crontab": "",
        "once": true,
        "onceDelay": "5",
        "topic": "",
        "x": 180,
        "y": 160,
        "wires": 
    },
    {
        "id": "c90afe3171260e8a",
        "type": "change",
        "z": "d115cf7e9caa769f",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "method",
                "pt": "msg",
                "to": "get",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "https://api.ps-smartfeed.cloud.petsafe.net/api/v2/feeders/REPLACE WITH THING NAME/messages?days=1",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "headers.content-type",
                "pt": "msg",
                "to": "application/json",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "headers.Token",
                "pt": "msg",
                "to": "REPLACE WITH TOKEN",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 340,
        "y": 160,
        "wires": [
            [
                "21ae8f3f9a748e7b"
            ]
        ]
    },
    {
        "id": "21ae8f3f9a748e7b",
        "type": "http request",
        "z": "d115cf7e9caa769f",
        "name": "",
        "method": "use",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 510,
        "y": 160,
        "wires": [
            [
                "c85fbe275197f4d7"
            ]
        ]
    },
    {
        "id": "c85fbe275197f4d7",
        "type": "ha-entity",
        "z": "d115cf7e9caa769f",
        "name": "Notification",
        "server": "xxxxxxxxxxxxxx",
        "version": 1,
        "debugenabled": false,
        "outputs": 1,
        "entityType": "sensor",
        "config": [
            {
                "property": "name",
                "value": "petsafe_notification"
            },
            {
                "property": "device_class",
                "value": ""
            },
            {
                "property": "icon",
                "value": "mdi:message"
            },
            {
                "property": "unit_of_measurement",
                "value": ""
            }
        ]

2nd flow is to send a POST curl to feed one amount (you can change the amount by changing the number here: “{“amount”:“1”}”,). The ‘rest_command’ I had created before and described above stopped working as well, so I created this 2nd flow using a Webhook and changing my previous ‘rest_command’ to POST to this webhook which is in Node red as per below:

Rest command under ‘configuration.yaml’:

rest_command:
  feed_the_tigers:
    method: post
    verify_ssl: false
    url: "https://HOST.IP/api/webhook/WEBHOOKID"

Webhook flow on Node Red:

    {
        "id": "993cfddc34d192ce",
        "type": "change",
        "z": "d115cf7e9caa769f",
        "name": "",
        "rules": [
            {
                "t": "set",
                "p": "method",
                "pt": "msg",
                "to": "post",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "{\"amount\":\"1\"}",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "url",
                "pt": "msg",
                "to": "https://api.ps-smartfeed.cloud.petsafe.net/api/v2/feeders/REPLACE WITH THING NAME/meals",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "headers.content-type",
                "pt": "msg",
                "to": "application/json",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "headers.Token",
                "pt": "msg",
                "to": "REPLACE WITH TOKEN",
                "tot": "str"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 380,
        "y": 260,
        "wires": [
            [
                "51b2d73356c191cf"
            ]
        ]
    },
    {
        "id": "51b2d73356c191cf",
        "type": "http request",
        "z": "d115cf7e9caa769f",
        "name": "",
        "method": "use",
        "ret": "obj",
        "paytoqs": "query",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "authType": "",
        "senderr": false,
        "x": 550,
        "y": 260,
        "wires": [
            []
        ]
    },
    {
        "id": "81be5a797785faa6",
        "type": "ha-webhook",
        "z": "d115cf7e9caa769f",
        "name": "Feed the tigers",
        "server": "xxxxxxxxxxxxxx",
        "version": 1,
        "outputs": 1,
        "webhookId": "YOUR WEBHOOKID",
        "outputProperties": [],
        "x": 200,
        "y": 260,
        "wires": [
            [
                "993cfddc34d192ce"
            ]
        ]

Hope this helps.

Awesome, thank you so much!

I tried this today with my new Smart Feeder gen 2 and the initial token request works but when I use the token to try and get the thing_name for my feeder the api responds with: “The Smartfeed App is no longer supported. Please use the My PetSafe app.”

Has anyone else seen this? Looks to me like they’re deprecating the old api endpoints, sad. Hopefully I’m wrong though. Thanks!

Next step if I want to dig into this more I guess is trying to do a Wireshark session on the iOS app and see if I can deduce what the new commands are. Please let me know if anyone has tried this.