esphome-miot icon indicating copy to clipboard operation
esphome-miot copied to clipboard

Add example `mmgg.feeder.fi1` config

Open cristianchelu opened this issue 1 year ago • 4 comments

This PR adds complete support for mmgg.feeder.fi1 Pet Feeder.

It requires the Event Component PR (#16) to achieve feature parity with the stock firmware, so please review that before merging this.

I'll describe the Miot services first one at a time, and afterwards go through what I've had to do to replicate features implemented in the xiaomi cloud instead of on-device.

For the future

The only things remaining that I'd like implemented, but can be handled outside this PR are:

  1. Automatic DST time-zone adjustment of the schedule. When daylight savings is in effect, the phon-timezone (SIID9/PIID12) can be updated by automation in order to preserve the preset dispense times. This is something that also the stock setup tries to handle (horribly, it required a factory reset each spring/autumn), but I've left a TODO comment about this for the future. Not doing anything about DST is already an improvement. More details in the corresponding service sections.
  2. HomeAssistant UI control of feeding schedule. There isn't a "standard" ESPHome <--> HomeAssistant UX for controlling daily scheduled events in a nice way, so I've opted to leave the schedule format (feddplan-string) untouched and handle display and editing of feeding times to a custom HA card. Again, more details in the proper section.

ESP8266 UART Quirk

This devices uses an ESP8266, which can't reliably handle 2 UARTs at the same time. The built-in serial logger must be disabled

logger:
  baud_rate: 0

in order to avoid occasional errors like this:

Timeout while receiving from MCU, dropping message 'get_do???'

Mi IoT Spec implementation

General observation: Parameters that are listed as input or output of actions are not usable by themselves. They only appear in the result message of an action or used in the action message.

Device Info (SIID: 1)

Nothing is sent on 1:1 ~ 1:5 on power cycle.

Feeder (SIID: 2)

Properties

  1. fault works as expected
  2. feeding-measure Can be read, but produces garbage. Writing to it directly has no effect. Used as input for the pet-food-out action.
  3. pet-food-left-level Works as expected

Actions

  1. pet-food-out Works as expected. Dispenses the specified portions immediately. Optional feeding-measure parameter; if left out, dispenses one portion.

Indicator Light (SIID: 3)

Properties

  1. on Read/Write works as expected

Feed Service (SIID: 4)

Properties

  1. outfood-num. Number of dispensed portions in last event. Specs say this is read|notify, but really it's only notify. The feed started|status|successful events use this to communicate what happened
  2. outfood-id. Index of scheduled feed that dispensed outfood-num portions in last event, or 255 if a manual feed. Specs say this is read|notify, but really it's only notify. The feed started|status|successful events use this to communicate what happened
  3. outletstatus. There is a motorized door protecting the dispensing outlet, "for freshness". Can be read. Is notified by properties_changed, but only after it's closed; there's no notification when it's opened, not even in the "Feeding Started" event.
  4. doorstatus. Top Lid of the device. Works as expected, thankfully.

Events

  1. feedsuccess when feeding is done, with outfood-id representing the trigger and outfood-num the total.
  2. feedstats repeatedly while dispensing, with outfood-id representing the trigger and outfood-num the current progress of portions.
  3. feedstart when starting the feed, with only outfood-id updated.

Feeding Schedule (SIID: 5)

There's a 10 slot schedule stored on device for offline / battery powered dispensing, controlled by this service, in combination with the phon-timezone property of the device control service.

One slot is sent as [int id],[int hour],[int minute],[int portions],[int status] where:

  • id - 0-9 - ID of the slot
  • hour - 0-23 - Hour of the slot, as UTC+phon-timezone (e.g. if phon-timezone is 2, a value of 12 here means 10 UTC).
  • minute - 0-59 Minute of the slot
  • portions - 1-30 Number of portions to be dispensed
  • status - Status of the slot at the time of querying. Observed values:
    • 0 Dispensed successfully.
    • 1 Failed to dispense (food stuck, etc.)
    • 254 Dispensing in progress.
    • 255 Pending.

An empty slot is returned as [int id],255,255,255,255

Every day at midnight all statuses reset from 0 Dispensed/1 Failed back to 255 Pending. I didn't have a chance to check if this happens in UTC or UTC+phon_timezone

Example: 2,12,30,5,0 - Slot 2, at 12:30 dispense 5 portions, dispensed successfuly for today.

The time order of the slots does not matter, i.e. slot 1 can be 1pm while slot 2 9am, and 2 will be dispensed before 1.

There can be empty slots between filled slots without errors.

Ther entire schedule can be queried in two steps by the getfeedplan action.

Properties

  1. feedplan-contr. Enable or disable the automatic feeding schedule. Works as expected.
  2. feedplan-hour - named parameter for feedlist{add,edit,del} actions
  3. feedplan-min - named parameter for feedlist{add,edit,del} actions
  4. feedplan-unit - portions to be dispensed, named parameter for feedlist{add,edit,del} actions
  5. feedplan-stat - unused. Seems to be the status of the schedule item, but setting it in a feedlist- action does not override the item's status.
  6. feedplan-id - named parameter for feedlist{add,edit,del} actions
  7. getfeedplan-num - named parameter for getfeedplan action to control which "page" to return
  8. feddplan-string - named return value of the getfeedplan action.

Actions

  1. stopfeed. Unknown, didn't try. Marks feedplan-contr as named parameter, but the control is switchable by itself, making this action redundant.

  2. getfeedplan - Get schedule. Usage action 5 6 11 0 or action 5 6 11 1, and returns the first 5 or last 5 schedules in the feddplan-string property as output. Example:

    // Get page 0 of schedule. (schedules 0-4)
    [15:04:28][V][miot:189]: Sending reply 'down action 5 6 11 0' to MCU
    [15:04:28][V][miot:095]: Received MCU message 'result 5 6 0 12 "0,6,0,5,0,1,10,0,5,0,2,255,255,255,255,3,255,255,255,255,4,255,255,255,255"'
    
    // Get page 1 of schedule. (schedules 5-9)
    [15:05:06][V][miot:189]: Sending reply 'down action 5 6 11 1' to MCU
    [15:05:06][V][miot:095]: Received MCU message 'result 5 6 0 12 "5,255,255,255,255,6,255,255,255,255,7,255,255,255,255,8,255,255,255,255,9,255,255,255,255"'
    

    In order to expose all 10 slots in one sensor, I keep each individual slot in a global std::map<std::string, std::string>, updated whenever the feddplan-string changes, and reconstruct the full string from it in the raw_feed_plan template sensor. I also exclude the empty slots from it for brevity's sake.

    Also, to always have the statuses up to date, I refresh this sensor at the feedstart and feedsuccess events and after midnight.

    • Also exposed to HA as refresh_feed_plan service
  3. feedlistadd - add a new schedule to slot feedplan-id. Specifying an already occupied slot id edits it without an error.

    • exposed to HA as add_scheduled_feed service
  4. feedlistedit - edit the schedule in slot feedplan-id

    • exposed to HA as edit_scheduled_feed service
  5. feedlistdel - clear the schedule in slot feedplan-id.

    • exposed to HA as remove_scheduled_feed service

Child Lock (SIID: 6)

Everything works as expected.

Cleaning Reminder (SIID: 8)

Everything works as expected.

Device Control (SIID:9)

Properties

  1. factory-result. Did not test. Specs say read|notify but I expect is only an output for the prtest action

  2. phon-time-zone. GMT offset in hours of the schedule times. It's effectively the "Device time zone".

    Changing this number does not also modify the hour numbers set in the schedule, but affects the actual dispensing time.

    Also, since this is an integer, users in countries with 30/45 minute TZ offet will never see the proper time.

  3. countrycode. Unknown if this is useful. Possibly related to the server (de/cn/us/etc) and region-locking. Values unknown, mine returns to 3 after a minute whatever I set it to read|write|notify works.

Actions

  1. prtest did not test. I didn't want to risk damage to my device, as I don't know under what conditions this needs to be performed in the factory.
  2. set-phone-time-zone did not test. The mentioned phon-time-zone can be set directly.
  3. set-countrycode has the same effect as setting the countrycode directly, and for my device it always returns to 3 eventually.

Events

  1. wifioff wall power loss, ESP will be powered off in 30s to preserve battery.

    If the power is restored within the 30s there is no further event sent and nothing happens.

    I tried making use of this to gracefully shutdown the esp, but if the power is restored before it's powered off it would be stuck in the poweroff state.

Replace Dessicant Reminder (SIID: 11)

Everything works as expected.

Extra features

I've added a dispense_food_portions template number to control how much is dispensed by the dispense_food button, for easier usage.

Also available in HA as a dispense_food service

The Portions Dispensed Today total counter is also implemented on-device. After each feedsuccess event the counter is incremented, and reset at midnight.

Device Screenshots

mmgg feeder fi1 control mmgg feeder fi1 sensor mmgg feeder fi1 events
mmgg feeder fi1 diagnostics mmgg feeder fi1 configuration mmgg feeder fi1 example

The last screenshot demonstrates a HA-side custom card to view/edit the schedule in the UI.

I'll try to publish it separately once it's finished, but with this, the device should be fully controllable in Home Assistant.

cristianchelu avatar Mar 16 '24 13:03 cristianchelu

Sorry for the delay, I'm a bit swamped right now. I'll try to look at this soon ;)

dhewg avatar Apr 10 '24 07:04 dhewg

Sorry for the delay, I'm a bit swamped right now. I'll try to look at this soon ;)

Don't worry about it, we're not on a deadline :)

I hope you don't mind me editing this and the event_occurred PR with new functionality in the meantime, I ironed out some more kinks.

I'll keep this as a draft a bit more as I add the final missing pieces for 100% feature parity.

cristianchelu avatar May 02 '24 16:05 cristianchelu

Hey @dhewg , I hope you're doing well.

I finally had some time to finish the code, and more importantly the mountain of text in the PR.

Sorry about that, but it's a large change after all, and I tried to document the implementation as best as possible.

It's ready for review when you have time.

Cheers!

cristianchelu avatar Aug 04 '24 19:08 cristianchelu

Hey there, things are slowly getting back to normal, sorry for the massive delay! I'll hope to look at the open PRs soon, thanks for keeping to work on it!

dhewg avatar Aug 07 '24 06:08 dhewg

Hm, that github web interface thingy to resolve the conflics didn't work somehow...

Anyway, I finally merged this. Thanks for the work and especially for the patience!

The events are a little hacky, but if we get a nicer event component we can adapt this config afterwards

dhewg avatar Sep 26 '24 04:09 dhewg