Local Deployment for SureFlap / SurePetCare Connect using only local MQTT Broker

That would be awesome! In my case, the cats sometimes go in and out with us. I also have a Google hub near the door. It would be super nice to just check them out on the display.

Any chance there would be a way to lock a specific pet in/out at certain times with this somehow? I have a cat that I don’t want coming inside when I’m not home. :smiley:

Been working on curfews and now realise that the cat flap has the ability to have 4 curfews whereas the pet door only supports one. So now need to refactor the database for the doors table to no longer have start/end time but a curfews column, and then in that column have “HH:MM-HH:MM,HH:MM-HH:MM” if you have two curfews set on the cat flap. Also added tests in using pytest so trying to avoid breaking changes when I refactor stuff like the curfews.
Also was playing with the datetime control so you should be able to at least set one curfew in HA itself as per this post: Triggers Actions from a single MQTT event updating datetime
Another interesting quirk between the cat flap and pet door is the pet door has a locking mode of normal (0), keepin (1), keepout (2) , locked (3) and curfew 4, whereas the cat flap the locking mode and if a curfew is set are independent.
Depending on time this week hope to commit something that should work.

Lastly there seems to be a stack of custom modes on the Feeder, not sure if it supports rechargeable batteries or not but they have modes like:
German Funk Antenna, Non Selective Mode, Genius Cat Mode, Extended Mode and Intruder mode. If you can MITM the traffic and log a case with surepet it would be super interesting to see what setting gets changed to enable these features. I love the idea of Genius Cat Mode and wonder what that mode is all about.

1 Like

You are a wizard.

1 Like

I just updated all this and got an error because I didn’t have the curfew stuff in the DB. So I reran mkpetlocaldb.py. As a suggestion, would it be a good idea to update that script so that it grabs credentials from the config.ini file? That way I don’t have to edit the file, or create the variables, since I’ll need it in the file anyway.

edit: And as of this morning, I’m seeing this error and getting red ears

web       | /usr/local/lib/python3.8/site-packages/urllib3/connectionpool.py:1013: InsecureRequestWarning: Unverified HTTPS request is being made to host 'hub.api.surehub.io'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings
web       |   warnings.warn(
web       | [2021-06-16 11:46:39,678] ERROR in app: Exception on /api/credentials [POST]
web       | Traceback (most recent call last):
web       |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 2051, in wsgi_app
web       |     response = self.full_dispatch_request()
web       |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1501, in full_dispatch_request
web       |     rv = self.handle_user_exception(e)
web       |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1499, in full_dispatch_request
web       |     rv = self.dispatch_request()
web       |   File "/usr/local/lib/python3.8/site-packages/flask/app.py", line 1485, in dispatch_request
web       |     return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
web       |   File "app.py", line 73, in credentials
web       |     dlfirmware(request.form['serial_number'],0)
web       |   File "app.py", line 52, in dlfirmware
web       |     response.raise_for_status() # ensure we notice bad responses
web       |   File "/usr/local/lib/python3.8/site-packages/requests/models.py", line 943, in raise_for_status
web       |     raise HTTPError(http_error_msg, response=self)
web       | requests.exceptions.HTTPError: 405 Client Error: Method Not Allowed for url: https://hub.api.surehub.io:443/api/firmware
web       | 192.168.1.121 - - [16/Jun/2021 11:46:39] "POST /api/credentials HTTP/1.1" 500 -


@peterl I disabled firmware backups, thinking maybe that was the issue, but its still crashing. Does this mean its actually trying to download a firmware update? If so, is there anything I can do to help?

If it matters, I got an app update a couple of days ago as well.

I’ll try this morning if I have some time as it was working for me but I haven’t tested against the cloud service for a while.
One thing I might need to do is sometimes they rebuild the IP addresses of their backend cloud API service and I have it hard coded in the INI file.
What I should just do is have a python DNS client to then query 8.8.8.8 and get the entries that way as I know I can’t rely on local DNS as you need to redirect the DNS to get the hub to work.
Just been insanely busy with work and kids things that my time has been limited.

1 Like

Of course that was it. I updated the IP and it worked perfectly.

1 Like

I just realized that this doesn’t seem to be reporting any changes from the cat door up to the Sure Pet servers, nor vice-versa. I also don’t get any green ears when a cat comes through the door.

Long time no updating… :slight_smile:
Been super busy with work and haven’t been working on the code much as it is mostly stable for me, added support for custom modes from the feeders including Intruder Mode and Genius Cat Mode. Also fixed up some of the logic how I ack messages back as I wasn’t sending the correct counter back to the feeder.
Made a database change so that now custommodes is a column in the devices table rather than specific for doors or feeders as all devices seem to have custom modes. Created a updatedb.sql to update the database, which should just require the following two lines to adjust the tables.

ALTER TABLE devices ADD COLUMN custommode INTEGER;
UPDATE devices SET custommode=0;

Lastly have curfews mostly sorted, just need to make a few more changes to the Home Assistant to pethub path as my hope to have mqtt discovery for everything can’t be done because MQTT discovery doesn’t support adding automations or datetime. So it will require adding the following updates:

configuation.yaml

input_datetime:
  pethub_curfew_start:
    name: Curfew Start
    has_time: true
    #initial: '06:00:00'
    icon: mdi:clock-start

  pethub_curfew_end:
    name: Curfew End
    has_time: true
    #initial: '10:00:00'
    icon: mdi:clock-end

And the automation to send mqtt messages

automations.yaml

- id: curfewtomqtt
  alias: "Pet Hub Curfew to MQTT"
  trigger:
    platform: state
    entity_id:
      - input_datetime.pethub_curfew_start
      - input_datetime.pethub_curfew_end
  action:
    - service: mqtt.publish
      data:
        topic: homeassistant/datetime/pethub/curfew/set
        payload_template: "{{ states('input_datetime.pethub_curfew_start')[0:5] }}-{{ states('input_datetime.pethub_curfew_end')[0:5] }}"


- id: mqtttocurfew
  alias: "MQTT to Pet Hub Curfew"
  trigger:
    - platform: mqtt
      topic: 'homeassistant/datetime/pethub/curfew/state'
  action:
    - service: input_datetime.set_datetime
      target:
        entity_id: input_datetime.pethub_curfew_start
      data:
        time: "{{ trigger.payload.split('-')[0] }}"
    - delay: '00:00:01'
    - service: input_datetime.set_datetime
      target:
        entity_id: input_datetime.pethub_curfew_end
      data:
        time: "{{ trigger.payload.split('-')[1] }}"
1 Like

While not totally related to this, I’d still really love the ability to set states from HA. Any idea if I could do some sort of CURL call to the API to set states?

There is the command line “cli.py” you can set pretty much everything. I can throw that into the web server to also support curls, the generatemessage does the heavy lifting in pethubpacket.py but:

python3 cli.py **MACADDRESS** Get Config

Should do much of what you want… have a look around:

for the things that can be sent.

1 Like

Do I somehow do that inside the docker container, or can it be run from the OS? Apologies in advance for the dumb questions.

edit: I can’t seem to get a bash prompt inside the docker, and cli.py doesn’t seem to work outside of it.

It will work outside of the docker vm on your host as long as you have python3.6 or so installed. Just change pip3 for pip depending on if it is a debian/ubuntu host as they use pip3 since regular pip is for python2. You just need to install the dependent packages once into your local python instance which is done by docker.

cd docker/pethub
pip3 install -r packages.txt
cd ../source
python3 cli.py **MACADDRESS** SetTime

That will set the time based on your local time for the pet door, and for the feeder / cat flap set UTC time.
You can do the same within docker exec using:

docker exec -it pethub sh -c 'python cli.py **MACADDRESS** SetTime'

As Alpine has python as the python3 interpreter.

I get this. I tried the MAC with and without colons (in case that was the issue).

ubuntu@ubuntu:~/pethublocal/docker/source$ python3 cli.py **MAC** SetTime
Traceback (most recent call last):
  File "cli.py", line 59, in <module>
    if setvalue:
NameError: name 'setvalue' is not defined

Are you sure you have the correct mac address and format?

echo 'select * from devices' | sqlite3 pethublocal.db

The first column is your mac address for the device.

Apparently not. There are two MACs in there. I got different errors from both of them. I don’t have the DNS redirection on right now (because at last check, it didn’t pass on reports to SurePet). Does that need to be in place?

ubuntu@ubuntu:~/pethublocal/docker/source$ python3 cli.py *** Get Config
arg length 4
Traceback (most recent call last):
  File "cli.py", line 56, in <module>
    setvalue = p.generatemessage(sys.argv[1], sys.argv[2],status)
  File "/home/ubuntu/pethublocal/docker/source/pethubpacket.py", line 1116, in generatemessage
    elif hb(int(state)) in operations[operation].validate.values(): #Has value that exists in validation dictionary
ValueError: invalid literal for int() with base 10: 'Config'

ubuntu@ubuntu:~/pethublocal/docker/source$ python3 cli.py *** Get Config
arg length 4
{'error': 'Unknown message'}
HAMQTTIP from config.ini
Connecting to 192.168.1.3
HAMQTT Host: 192.168.1.3
HAMQTT Port: 1883
Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.8/site-packages/box/box.py", line 461, in __getitem__
    return super().__getitem__(item)
KeyError: 'topic'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.8/site-packages/box/box.py", line 487, in __getattr__
    value = self.__getitem__(item, _ignore_default=True)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/box/box.py", line 482, in __getitem__
    raise BoxKeyError(str(err)) from _exception_cause(err)
box.exceptions.BoxKeyError: "'topic'"

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/ubuntu/.local/lib/python3.8/site-packages/box/box.py", line 489, in __getattr__
    value = object.__getattribute__(self, item)
AttributeError: 'Box' object has no attribute 'topic'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "cli.py", line 92, in <module>
    ret=mc.publish(setvalue.topic,setvalue.msg,qos=1)
  File "/home/ubuntu/.local/lib/python3.8/site-packages/box/box.py", line 501, in __getattr__
    raise BoxKeyError(str(err)) from _exception_cause(err)
box.exceptions.BoxKeyError: "'Box' object has no attribute 'topic'"

For the local service to connect back to the surepet cloud service you need to get the password for the certificate which requires soldering on a TTL serial console to the hub and doing a firmware upgrade / reflash of the current firmware as the certificate password is only sent on the console and only sent when doing a firmware upgrade.
IMHO it’s well worth doing but plenty of warning around bricking your hub if you don’t solder it on correctly.
And the “ears” flashing 3 times is a command that is sent from the cloud service after certain events. I didn’t bother doing it as I find it annoying in a dark room it is bright even with the ears turned off. But can easily re-add flashing ears on commands

Do I literally have to solder it? I have tremors that would prevent that.

Or may I just pick your brain since you probably know the most about it, outside of Surepet employees? Our cats often times go out the door when we do, but I’d still like to keep tabs on who is home and who isn’t. So I need to be able to set them home/away, preferably from HA (the Surepet app sucks). Can you think of an ‘easy’ way to do that?

Yes. The only way to get the certificate password is to solder a TTL serial console on it and do a firmware update or if you are super lucky and can find an older model hub serial H008 or older and hasn’t been connected to the internet before and firmware updated itself then the certificate password is sent as the long_serial the during the first boot.


This is the required connection.