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

Good news!

I hope we can have the same thing with the cat flap soon :slight_smile:

@peterl, I sent you a few frames I captured with my CC2531 sniffer yesterday.
Do not hesitate to tell me if you need more (or something different).

Thanks

K.

1 Like

Support for locking the cat door is on my todo for tonight if time permits around the family.

2 Likes

@peterl

Some thoughts after running this for a while.

  1. Probably need to look at resending (publishing) the home assistant auto config messages to mqtt on a regular interval. Running local_pethub for a few hours, my sensors in home assistant go unavailable. Restarting local_pethub fixes this.

  2. Would be nice if the settings are read from environment variables. That will allow one to put the settings like the ip address of the mqtt server in a .env file, same folder as docker-compose.yaml which can be added to .gitignore. Will be much easier each time to apply updates from github for users.

  3. I can think of a few architecture changes going forward, to make this easier and simpler. Like it would be nice to have a webui to configure pets and hub names in the sqlite db. Another option is, to combine the mkdb part with local_pethub, and then if the .db file doesnt exist but the username/password exist in environment variables then create the db before launching the mqtt processor. Kinda like a first run setup. But I am guessing most of this will be long term ideas after most of the functionality for the messages (like cat flap) is figured out and working.

2 Likes

Completely agree with everything you’ve said and variables was high up on my priority but I have just worked out the cat door locking and it has meant I had to deal with the feeder/flap counter issue where each message to the feeder and cat flap has a counter… so need to store and iterate that.
So database change unfortunately and I think I might refactor to get rid of zigsniff and move that to the to folder and have local at the docker level. Then add a script to start it pulling in an env file. Time is short and the list of things to add is long.

1 Like

Have the cat flap send logic sorted, just need to get the current state in… but this is what I have figured out.
Going to commit the code which may break stuff, but off to bed now.

    elif devicetype=="catflap":
        if operation == "dumpstate": #Dump all memory registers from 0 to 630
            msgstr = "TBC"
        if operation == "inbound" or operation == "outbound":
            curs.execute('select mac_address, lockingmode from devices join doors using (mac_address) where name like (?)', ([device]))
            lockingmode = curs.fetchone()
            #print("Current locking mode: " + lockingmode[0])
            if (operation == "outbound" and state == "OFF" and lockingmode[1] == 1) or (operation == "inbound" and state == "OFF" and lockingmode[1] == 2):
                #Going to Lock State 0 - Unlocked
                msgstr = "11 00 CC 00 TT TT TT TT 00 00 00 00 00 00 07 06 00 02"
            elif (operation == "outbound" and state == "ON" and lockingmode[1] == 0) or (operation == "inbound" and state == "OFF" and lockingmode[1] == 3):
                #Going to Lock State 1 - Keep pets in
                msgstr = "11 00 CC 00 TT TT TT TT 00 00 00 00 00 00 07 03 00 02"
            elif (operation == "outbound" and state == "OFF" and lockingmode[1] == 3) or (operation == "inbound" and state == "ON" and lockingmode[1] == 0):
                #Going to Lock State 2 - Keep pets out
                msgstr = "11 00 CC 00 TT TT TT TT 00 00 00 00 00 00 07 05 00 02"
            elif (operation == "outbound" and state == "ON" and lockingmode[1] == 2) or (operation == "inbound" and state == "ON" and lockingmode[1] == 1):
                #Going to Lock State 3 - Lock both ways
                msgstr = "11 00 CC 00 TT TT TT TT 00 00 00 00 00 00 07 04 00 02"
            else:
                msgstr = "11 00 CC 00 TT TT TT TT 00 00 00 00 00 00 07 06 00 02"
            hubts = feedertimestampfromnow()
            devcounter = devicecounter(lockingmode[0],"-1","-2") #Iterate the send counter for the device
            msgstr = msgstr.replace('CC', hb(devcounter['send'])) # Replace device counter in the record
            msgstr = msgstr.replace('TT TT TT TT', " ".join(hubts[i:i+2] for i in range(0, len(hubts), 2))) # Timestamp
            return {"topic":"pethublocal/messages/"+lockingmode[0], "msg":buildmqttsendmessage(msgstr)}
        return buildmqttsendmessage(msgstr)

Need a new table:

CREATE TABLE devicecounter(mac_address TEXT, send INTEGER, retrieve INTEGER );
INSERT INTO devicecounter VALUES('macaddy',0,0);
2 Likes

Thanks! I will try this and will give you some feedback.

K.

I haven’t yet added everything into pethubmqtt.py yet so it won’t work as it won’t create the topics required for listening and I haven’t mapped the incoming messages to the mqtt topics for status responses. But you could try poking the messages to the door directly using a send command:

import pethubpacket as p
import paho.mqtt.client as mqtt

resp = p.generatemessage("catflap", "Kitchen", "outbound", "ON")
print(resp)

mqtthost = 'hubmq'
mqttport = 1883

mc = mqtt.Client()
mc.connect(mqtthost, mqttport, 30)

ret=mc.publish(resp['topic'],resp['msg'],qos=1)
print(ret)

That should work in the pethub directory with your db and associated bits.
Edit. Just pushed to include the 127 message type prefix… should look good now:

python3 send.py
{'topic': 'pethublocal/messages/xx', 'msg': '606d57f7 1000 127 11 00 07 00 7a 6e 10 55 00 00 00 00 00 00 07 06 00 02'}

@peterl, if you implement this, please also add environment variables for user/password authentication on the main mqtt broker.

The credentials can be passed to the paho-mqtt connection using username_pw_set(username="xxx",password="xxx") and will have to be added to the mosquitto.conf file as well (remote_username/remote_password).

With all variables set in the .env file, it’s perfect!

Impressive job anyway! Thanks!

K.

If time permits over the next few days I will look to do some refactoring and move the following around as that makes sense if I clean things up and improve the deployment process.

  • /docker/zigsniff -> /zigsniff
  • /docker/local/*-> /docker
  • /PetHub -> /docker/source
  • Change the compose containers to use a shared volume of /pethub/source mapped to /docker/source that way you don’t need to keep on copying the files in
  • Add /docker/.env environmental file and then apply using those variables across the containers

I will also look to collapse web and pethub containers into a single container so then a single web flask + paho-mqtt container on 80 & 443 so it can service the hub credentials request and be a web server for end users to configure the database and configure infrequent activity that doesn’t logically sit or easily work within home assistant such as the device adoption process and managing provisioned pets on the devices… that will be a longer term activity once the core functionality is sorted.

2 Likes

Done, moved everything around so now /docker is only the docker compose, there is now a .env for the environment file and in my .gitignore.
Also moved /PetHub to /docker/source and now that is a volume to mount rather than needed to be included in the image.
“Works for me™”
It may be easier to just checkout the whole repo again, copy your pethublocal.db into /docker/source, edit the .env for your needs and start docker-compose up --build in /docker.

2 Likes

Thanks! I rebuilt my docker stack from a new checkout of the updated structure without any issue.

But if I’m not wrong, the mosquitto.conf file cannot use the variables from .env, so the file must be modified manually to add the correct address of the MQTT broker (and authentication if needed).

I also added the missing part for the MQTT username/password in pethubmqtt.py

    hamqttuser = os.environ.get('HAMQTTUSERNAME')
    hamqttpass = os.environ.get('HAMQTTPASSWORD')
    ......
    if hamqttuser is not None:
        mc.username_pw_set(username=hamqttuser,password=hamqttpass)
    mc.connect(mqtthost, mqttport, 30)

K.

I added checking for the IP/ username/password to the MQTT docker entry point script updating the config file if the environment variables were set so it should have updated the file but I didn’t test it too much but that is how I’m updating the broker IP too so that approach works imho.

But I will also add the same to the pethubmqtt py too as I missed that by accident.

Glad it worked for the most part OOTB. Not going to do much over the next few days as have a crazy weekend.

Hum. The bridge was not connected until I manually updated the configuration the first time.

I rolled back to the default config file from git and tried again… and it worked this time.

Sorry, then. You think about everything!

K.

1 Like

Awesome:)

Next I plan to add downloading the registers from all the devices and storing that into the database as that is useful for knowing the state and the cloud service does that each time the hub reconnects.
Should also find the battery and rssi values, and I am 99.9% sure they are part of the hourly 132 messages that come off the hub and just need to decode them but haven’t taken the time to figure them out.

Small update tonight but logging the hub boot messages to the db as that might be useful in the future, going to log all the other states from all devices there too.
So a small change to the database:

drop table devicestate;
CREATE TABLE devicestate(mac_address TEXT, offset INTEGER, length INTEGER, data TEXT, UNIQUE (mac_address, offset, length) ON CONFLICT REPLACE );

And just reformatting of the feeder send messages… next steps the cat flap lock state properly working for @kimagure

2 Likes

@peterl

Just want to thank you for all the awesome work you have done on this so far!

3 Likes

Hi Peter,

I see you renamed the .env file to config.ini and added it to the docker-compose file.

This is great, it’s easier to “see” this file, but can you rename the sample file provided in the repo to “config.ini.sample” or “config.ini.dist”, and add config.ini to .gitignore ?

This would make it possible to easily refresh our local sources using git pull without getting an error message and having to reapply the changes manually.

Thanks for the updates anyway!

K.

1 Like

Minor updates to support the cat flap further to handle the double byte of the cat byte.
Hope to spent a bit more time over the next few days cleaning up the cat flap locking.

1 Like

The child in me is laughing at the ‘cat byte’.

Any chance there’s a setup for morons available yet. I’ve finally gotten around to setting up local DNS so that I can redirect the DNS calls.