Feeder
Feeder
Product ID = 4
All the non-Pet Door devices have common messages
All the non Pet Door devices have a consistent messaging format with the message types 126 and 127.
| Type | Feeder | Cat Flap | Poseidon | Description |
|---|---|---|---|---|
00 |
Acknowledgement Command Message to Status Message | |||
01 |
Get Command Message to retrieve message state | |||
07 |
Set Time Command Message to set device time | |||
09 |
Device settings parameters | |||
0b |
0b Boot Status Message | |||
0c |
Battery Status Message | |||
10 |
10 Boot Status Message | |||
11 |
Tag Provision Command Message to Status Message | |||
12 |
Set Cat Flap Curfew Command message | |||
13 |
Cat Movement through cat flap status message | |||
17 |
17 Unknown message | |||
18 |
Feeding status message | |||
0d |
Cat Flap Curfew Status messages | |||
0d |
Zero Feeder Scales | |||
1b |
Drinking status message |
126 Messages
These are the status message where multiple messages can all be sent in a single payload from the device. Directly after the 126 the message length in hex, then the message type, and the payload. At the end of the payload an additional message can be sent. Again the length then message type until the end of the payload. The first byte after the timestamp is the same hub counter message as already talked about 0xx0 above. That is consistent for all messages.
This means a message can look like:
tttttttt 0010 126 0d 09 00 01 00 9f cc 42 59 0c 02 00 00 00
| | | | | --+-- -----+----- | +----------
| | | | | | | | +- Bowl Count = 2
| | | | | | | +--- SubType = C
| | | | | | +----------- Timestamp
| | | | | +-------------------- Counter
| | | | +---------------------------- Message Type
| | | +------------------------------- Length
| | +---------------------------------- Message Type 126
| +--------------------------------------- Hub Counter Status Message
+---------------------------------------------- Hub UTC Hex Timestamp
The above secnario the message is a single message length is 0d bytes long. The message type is a 09 and the payload is 00 01 00 9f cc 42 59 0c 02 00 00 00.
tttttttt 0xx0 126 0d 09 00 01 00 9f cc 42 59 0c 02 00 00 00 0d 09 00 02 00 9f cc 42 59 0a 88 13 00 00
Similar to the above, the first message is the same message above, the second message is also 0d bytes long and a message type 09 with the payload 00 02 00 9f cc 42 59 0a 88 13 00 00.
127 Messages
The 127 messages are command messages either sent from the cloud service to change something, such as locking the cat flap or provisioning a new tag to the device. Because they are command messages they will always be 1000, but they are a single message so do not include the length so you need to just know how long the message you want to send is and just start with the message type immedateily after 127 ie
tttttttt 1000 127 09 00 01 00 9f cc 42 59 0c 01 00 00 00
| | | | --+-- -----+----- | +----------
| | | | | | | +- Bowl Count = 1
| | | | | | +--- SubType = C
| | | | | +----------- Timestamp
| | | | +-------------------- Counter
| | | +---------------------------- Message Type
| | +------------------------------- Message Type 126
| +------------------------------------ Command Message
+------------------------------------------- Hub UTC Hex Timestamp
The above is setting the Bowl Count to 1.
Message Counter
Directly after the message type is a 00, then a two byte little endian byte counter which counts from 0 to 65534 before cycling back to 0. This is so the cloud knows the current state of the devices and if messages are lost as if the hub is offline or disconnected from the internet none of the messsages are retained. Typical messages:
There is also a send a retrive counter, which are generated and increment independently. As each end have their own sent counter
tttttttt 0xx0 126 09 01 00 01 00 9e cc 42 59 11 11 - Device Counter = 1
tttttttt 1000 127 01 00 02 f2 9e cc 42 59 11 11 - Cloud Counter = F202 = 61954
Message Timestamp
After the counter is a 4 byte timestamp of the event. This is used by the device to set the time of it, and report back the timestamp of the device if there is any skew. The time is stored in UTC, but instead of using the UTC Timestamp they have their own custom rolled timestamp using bitwise operators as shown below which bits are converted into numbers. This is calculated in function devicetimestamp in message.py
def devicetimestamp(hexts, time_zone, tz_format):
""" Convert device hex timestamp into something human readable """
timestamp_int = int.from_bytes(hexts, byteorder='little')
year = int(f'20{timestamp_int >> 26:02}') # Year - 6 Bits, prepending 20 for 4 digit year
month = timestamp_int >> 22 & 0xf # Month - 4 Bits
day = timestamp_int >> 17 & 0x1f # Day - 5 Bits
hour = timestamp_int >> 12 & 0x1f # Hour - 5 Bits
minute = timestamp_int >> 6 & 0x3f # Minute - 6 Bits
second = timestamp_int & 0x3f # Second - 6 Bits
Example Conversion
Using the example timestamp `9e cc 42 59`
9e cc 42 59 -> Little Endian -> 5942CC9E -> Integer = 1497549982
1497549982 -> Binary 01011001010000101100110010011110
First 6 Bits 010110 -> 22 Year, so prepent 20 to 2022.
Next 4 Bits 0101 -> 5 Month
Next 5 Bits 00001 -> 1 Day
Next 5 Bits 01100 -> 12 Hour
Next 6 Bits 110010 -> 50 Minute
Next 6 Bits 011110 -> 30 Second
UTC Time = 2022-05-01 12:50:30
And since this is UTC time, it needs to be converted into local time.
Acknowledgement
Message Type: 00
Message Length: 07
Every status message needs to be acknowledged back using a 127 and a message type of 00 once it has been processed by the other end. This is sent with the same send counter, but the timestamp of the sending host, and include the message type and two bytes of 00 ie 01 00 00 being acknowledged.
Hub to Cloud -> tttttttt 0xx0 126 07 01 00 02 11 9e cc 42 59 11 22 33 44 55
Cloud to Hub -> tttttttt 1000 127 00 00 02 11 9f cc 42 59 01 00 00
Get State
Message Type: 01
Message Length = N/A as Command only, and varaible length.
To retrieve the current status of a message type a 01 command message is sent to the device.
Cloud to Hub -> tttttttt 1000 127 01 00 01 00 9f cc 42 59 09 00 ff # Boot message 09
Cloud to Hub -> tttttttt 1000 127 01 00 02 00 9f cc 42 59 0b 00 # Unknown 0b
Cloud to Hub -> tttttttt 1000 127 01 00 03 00 9f cc 42 59 0c 00 # Battery state
Cloud to Hub -> tttttttt 1000 127 01 00 04 00 9f cc 42 59 0d 00 # Lock state
Cloud to Hub -> tttttttt 1000 127 01 00 05 00 9f cc 42 59 10 00 # Boot message 10
Cloud to Hub -> tttttttt 1000 127 01 00 06 00 9f cc 42 59 11 00 ff # Tag provisioned
Cloud to Hub -> tttttttt 1000 127 01 00 07 00 9f cc 42 59 12 00 # Curfew state
Cloud to Hub -> tttttttt 1000 127 01 00 08 00 9f cc 42 59 17 00 00 # Boot message 17
Cloud to Hub -> tttttttt 1000 127 01 00 09 00 9f cc 42 59 1b 00 # Water state
Set Device Time
Message Type: 07
Command message to set the time of the device in UTC. As all the time is in UTC the device timestamp value needs to be set to UTC time.
Cloud to Hub -> tttttttt 1000 127 01 00 01 00 9f cc 42 59 00 00 00 00 07 # Sets the device time to 2022-05-01 12:50:30
Device settings messages
Message Type: 09
Messages Length: 0d
This is used for setting device settings. Such as custom modes and bowl counts for the feeder. The sub-type messages vary depending on the device and have a byte after the timestamp for the sub-type, then little endian 4 byte word for the value of the sub-type.
Status 09 Example:
0d 09 00 01 00 9f cc 42 59 0c 02 00 00 00
| | --+-- -----+----- | -----+-----
| | | Bowl Count = 2
| | +--- SubType = C
| +---------------------------- Message Type
+------------------------------- Length
Boot Device Information
Message Type 0b
The boot device message length is 43 and the figured fields defined message
elif value[0] == 0x0b: # Status - Boot Device Information
frame_response.Operation = "DeviceInfo"
frame_response.Hardware = b2is(value[8:12])
frame_response.Firmware = b2is(value[12:16])
frame_response.EntityType = EntityType(value[64]).name
frame_response.Val1 = b2is(value[16:20]) # **TODO Some value
frame_response.HexTS = value[20:28].hex()
frame_response.SerialHex = value[36:45].hex() # **TODO Serial Number calc somehow
Battery Information
Message Type 0c
Message length = 18
The battery information in the message
The 4 byte word after the timestamp is the battery value with 3 decimal places of accuracy as reported in the app.
126 18 0c 00 01 00 9f cc 42 59 b8 14 00 00 dd 0c 00 00 25 01 00 00 00 00 00 00
b8 14 00 00 -> Hex 14B8 -> Decimal 5304 / 1000 -> Battery voltage 5.304
Code:
elif value[0] == 0x0c: # Status - Battery state for four bytes
frame_response.Operation = 'Battery'
battery = str(round(int(b2is(value[8:12])) / 1000, 4))
frame_response.Battery = battery
frame_response.Value2 = str(int(b2is(value[12:16]))) # **TODO Not sure what this value is.
frame_response.Value3 = str(int(b2is(value[16:20]))) # **TODO Or this one
frame_response.BatteryTime = devicetimestamp(value[20:24], time_zone, '') # **TODO Last time the time was set?
Some boot message
Message type: 10
Message length: 18
The Boot in the message No idea what is in the message.
Message 11 - Tag Provisioning
Message Length = 12
This is used to and and remove tags to the device. The Tag Calculation is completely different from the Pet Door as it is little endian. This is also used to set lock state on the Cat Flap on Tag 00.
Example Message:
126 12 11 00 01 00 9f cc 42 59 4a 2a 86 48 d7 f9 01 02 01 00
| --+-- -----+----- --------+-------- | | | +- Always 0
| | | | +---- Tag Offset starting with 1
| | | +------- Tag State, 02 = Normal
| | +---------- Tag Type `01` for FDX-B
| +-------------------- Tag Value
+---------------------------------------------------- Message Type 11
There are 2 types of tags:
- Tag
01is a FDX-B tag with the numberingxxx.xxxxxxxxxxdecimal value 3 + 10 digits - Tag
03is a HDX tag which is presented as 5 bytes of hexhhhhhhhhhh
FDX-B Tag Conversion:
4a 2a 86 48 d7 f9 -> Little endian hex F9D748862A4A -> Int 274703030037066
274703030037066 -> Binary 111110011101011101001000100001100010101001001010
First 10 Bytes are Country Code = 11111001110 = 999
38 Bytes are National Code = 1011101001000100001100010101001001010 = 100001000010
FDX-B Tag = 999.100001000010
HDX Tag:
11 22 33 44 55 00 -> Direct translation of the hex to the tag and the last byte is always 00
Tag State is either 02 for active/normal, 06 for disabled, or 03 if it is a CatFlap and the Tag is set to Keep In
Tag Offset starts at 1, and supports up to 32 aka 1f tags on the device. Tag Offset 0 is used on the Cat Flap to set door locking state.
Message 09 - Feeder Messages
Status -> 09 00 01 00 9f cc 42 59 05 00 00 00 00 # Training Mode
Status or Command -> 09 00 02 00 9f cc 42 59 0a 88 13 00 00 # Get/Set Left Weight if two bowls or if 1 bowl target weight to 50.00 grams
Status or Command -> 09 00 03 00 9f cc 42 59 0b 70 17 00 00 # Get/Set Right Weight if two bowls to 60.00 grams
Status or Command -> 09 00 04 00 9f cc 42 59 0c 02 00 00 00 # Get/Set Bowl Count either 1 or 2
Status or Command -> 09 00 05 00 9f cc 42 59 0d a0 0f 00 00 # Get/Set Lid Close Delay 4 Seconds - 0(fast) or 4000(normal) or 20000(slow) decimal values
Status or Command -> 09 00 06 00 9f cc 42 59 14 80 00 00 00 # Get/Set Custom Mode, refer to enum for values
Status -> 09 00 07 00 9f cc 42 59 17 f9 10 00 00 # Zero left scales absolute weight result = 4345
Status -> 09 00 08 00 9f cc 42 59 18 66 0e 00 00 # Zero right scales absolute weight result = 3686
Target Weights
Target weights are 0a and 0b sub-types. If bowls = 1 then only 0a is set. If bowls = 2 then 0a is the left target weight and 0b is the right target weight.
Like all weights it is grams and 2 decimal places of accuracy. So to set 50 grams as the target weight:
50 * 100 = 5000 = Hex 1388 = Little endian word 88 13 00 00
Lid Close Delay
The values that can be set are specified is in enums
class FeederCloseDelay(SureEnum):
""" Feeder Close Delay Speed """
FAST = 0 # Fast delay - 0 Seconds
NORMAL = 4000 # Normal delay - 4 Seconds
SLOW = 20000 # Slow delay - 20 Seconds
Cat Flap Custom Modes
The values that can be set are specified is in enums
Non-Connect Feeder Custom Modes... May be aligned to the Connect version with a bitwise operator.?
-- Order of flashing light when selecting the custom mode.
- 0 - Static Red
- 1 - Static Green
- 2 - Static Orange
- 3 - Flashing Red
- 4 - Flashing Green
- 5 - Flashing Orange
| Custom Mode | Name | Description | YouTube Link |
|---|---|---|---|
| Mode I | 0-Static Red | Extended Mode | https://www.youtube.com/watch?v=pYyNOvLfu6A |
| Mode I | 4-Flashing Green | German Funk antenna custom mode | https://www.youtube.com/watch?v=PIe0OwpC8QY |
| Mode I | 5-Flash Orange | Metal Mode |
https://www.youtube.com/watch?v=hQ7aQ1S61w8 |
| Mode II | 0-Static Red | Non Selective Feeding Mode | https://www.youtube.com/watch?v=Ifu7SQ0hWz4 |
| Mode II | 3-Flash Red | Multi-Scan Custom Mode | https://www.youtube.com/watch?v=k2YZewDOG6A |
| Mode II | 4-Flashing Green | Intruder Training Mode | https://www.youtube.com/watch?v=a_IgU4q5E1A or https://www.youtube.com/watch?v=BewTCQ0lbso |
class FeederCustomMode(SureFlag):
""" Custom Modes on the Feeder """
Disabled = 0 # All custom modes disabled
NonSelective = 0x40 # Bit7 - Non-selective Entry - Allow any animal who breaks the infrared link to open feeder
GeniusCat = 0x80 # Bit8 - Genius Cat Mode - Disable open/close button as Genius Cat has figured out how to open the feeder by pressing button.
Intruder = 0x100 # Bit9 - Intruder Mode - Close lid when another non-provisioned tag turns up
Message 0d - Feeder Zero Scales Command
This command is sent to the Feeder when you Zero Scales command from the app.
- FeederZeroScales FeederState enums 01 - Zero Left, 02 - Zero Right, 03 - Zero Both
127 0d 00 26 00 9f cc 42 59 00 19 00 00 00 03 00 00 00 00 01 03
+- Zero Both Feeders
The response is a number of different acknowledgements including sending the scales state.
126 0d 09 00 15 0e 9f cc 42 59 12 f4 01 00 00 0b 00 00 23 00 9f cc 42 59 09 00 00 0b 00 00 24 00 9f cc 42 59 0d 00 00 0d 09 00 16 0e 9f cc 42 59 17 3c 0c 00 00 0d 09 00 17 0e 9f cc 42 59 18 ad 0d 00 00
Mult-message broken into:
0d 09 00 15 0e 9f cc 42 59 12 f4 01 00 00 - 09 Sub-Value 12, always 500
0b 00 00 23 00 9f cc 42 59 09 00 00 - Ack of Message 09
0b 00 00 24 00 9f cc 42 59 0d 00 00 - Act of Message 0d
0d 09 00 16 0e 9f cc 42 59 17 3c 0c 00 00 - 09 Sub-Value 17 - Left absolute weight 3132 = 31.32g
0d 09 00 17 0e 9f cc 42 59 18 ad 0d 00 00 - 09 Sub-Value 18 - Right absolute weight 3501 = 35.01g
Feeder Status
126 29 18 00 18 0e 9f cc 42 59 01 02 03 04 05 06 07 06 00 00 02 00 00 00 00 05 00 00 00 00 00 00 00 f8 ff ff ff f9 00 22 01 00 00
+ --+-- -----+----- +------------------- | +---------- +----------
+ Feeder Message + Tag 1234567 + Action 6 Zero Scales + Left Weight = 0.05g + Right Weight = -0.08g
Message 18 - Feeder Messages
Message length = 29
The format is:
- 7 Bytes Animal Tag or all 0's if manually opened
- 1 Byte Bowl Action FeederState enums Animal Open 0, Animal Closed = 1...
- 2 Bytes Time open in seconds
- 4 Bytes Left Bowl Start weight to 2 decimal places, or all bowls if single bowl
- 4 Bytes Left Bowl End weight to 2 decimal places or all zeros if opening
- 4 Bytes Right Bowl Start weight to 2 decimal places
- 4 Bytes Right Bowl End weight to 2 decimal places or all zeros if opening
It's a signed integer so you can get negative values if the zeroing of the scales had something in the scales so when you remove it a negative value is returned.
Example Message
126 29 18 00 01 00 9f cc 42 59 4a 2a 86 48 d7 f9 01 01 44 01 02 5c 05 00 00 6d 03 00 00 8e 0d 00 00 a1 06 00 00 ea 00 24 01 00 00
+ --+-- -----+----- ---------+---------- | --+-- | -----+----- -----+----- -----+----- -----+----- --+-- +----------
| | | | | | | | | + Unsure
| | | | | | | | +---- Counter
| | | | | | | +------------- Closing Right Weight To
| | | | | | +------------------------- Opening Right Weight From
| | | | | +------------------------------------- Closing Left Weight To, or Total if 1 Bowl
| | | | +------------------------------------------------- Opening Left Weight From, or Total if 1 Bowl
| | | +--------------------------------------------------------- Bowl Count(?) = 2
| | +------------------------------------------------------------- Open Seconds, or 0 if Opening not closing
| +------------------------------------------------------------------ Feeder Bowl Action, as per above
+------------------------------------------------------------------------------ Tag = 999.100001000010
Other observations is if the Custom Mode is set to Intruder then the opening tag is the correct animal able to open the feeder, and the closing message is the intruder.