dhewg / esphome-miot

ESPHome components for MIoT devices
Other
16 stars 8 forks source link

Add "Event Component" support #16

Open cristianchelu opened 3 months ago

cristianchelu commented 3 months ago

Add full support for event_occured mcu messages via the new "Event Component" introduced in ESPHome 2024.5 and Home Assistant 2024.5, fixing #4.

As of today, 2024-05-02, this PR only works with latest esphome:dev. Expected esphome stable release is on 15th of may (cadence is every third Wednesday of the month). I have also tested this branch with ESPHome 2024.4 and it compiles & works ok, sans the actual event component.

Limitations & considerations

event_type is a requirement

As far as I have seen, Home Assistant requires an event_type label for every event entity, to distinguish what exactly happened. The example given is for a Button Pressed event, the type can be single_press, long_press, double_press etc. ESPHome also follows this pattern, and requires both a list of all possible event_types when creating the event, as well as the event_type when the event is triggered.

As MIoT events don't map to this pattern and only have one "type" per event, I have chosen to add a single event_type required string to the YAML definition and send this with each event trigger. For the strings, the event name as it appears in the miot-specs seems the most sensible option.

MIoT event properties

ESPHome does not allow for attributes on events so an alternative is required to expose properties related to events.

I think the best approach is to consider the properties as normal sensors, just with poll disabled. This allows for re-use of the existing update_properties function (even if it complicates it a bit more), as well as keeping the simple PID definition syntax.

The only downside is that if the same miot event id produces a variable amount of properties each time it's emitted, we can't easily say which props exactly were part of the event. However, it seems that this is not the case so far.

Automations

Automations also come by default with the event component, via the on_event trigger.

Example usage

Minimal example:

event:
  - platform: "miot"
    miot_siid: 4
    miot_eiid: 1
    event_type: some_miot_event
sensor: 
  - platform: "miot" # Some PID updated as part of an event
    miot_siid: 4
    miot_piid: 2
    miot_poll: false

Complex example:

event:
  - platform: "miot"
    miot_siid: 4
    miot_eiid: 1
    id: feedsuccess_event
    event_type: feedsuccess
    internal: true
    on_event:
      - event.trigger:
          id: feed_event
          event_type: "finished"
      - globals.set: 
          id: portions_dispensed_today
          value: !lambda return id(portions_dispensed_today) + id(outfood_num).state;
      - component.update:
          id: portions_dispensed_today_sensor
  - platform: "miot"
    miot_siid: 4
    miot_eiid: 2
    id: feedstats_event
    event_type: feedstats
    internal: true
    on_event:
      - event.trigger:
          id: feed_event
          event_type: "stats"
  - platform: "miot"
    miot_siid: 4
    miot_eiid: 3
    id: feedstart_event
    event_type: feedstart
    internal: true
    on_event:
      - event.trigger:
          id: feed_event
          event_type: "start"
# Multiple related MIoT events combined into a single template event
  - platform: "template"
    name: 'Feed Event'
    id: feed_event
    event_types:
      - 'start'
      - 'stats'
      - 'finished'

Example device entry for above complex event: Screenshot from 2024-05-02 18-12-01

Why it's needed.

On some (like mmgg.feeder.fi) devices that have properties attached to events in the spec, the properties themselves cannot be read directly as they produce garbage data, but they are only updated as part of an event message.

Example: SIID 4 PIID 4 and SIID 4 PIID 5 always return 5 when directly read, but correct data as part of an event:

// Event
[13:43:40][V][miot:095]: Received MCU message 'event_occured 4 2 4 1 5 255'

[13:43:40][V][miot.sensor:011]: MCU reported sensor 4:4 is: 1.000000
[13:43:40][V][sensor:043]: 'Last Feed Portions': Received new state 1.000000

[13:43:40][V][miot.text_sensor:011]: MCU reported text sensor 4:5 is: 255
[13:43:40][V][text_sensor:013]: 'Last Feed Source': Received new state 255

[13:43:40][V][miot:095]: Received MCU message 'event_occured 4 1 4 1 5 255'

[13:43:40][V][miot.sensor:011]: MCU reported sensor 4:4 is: 1.000000
[13:43:40][V][sensor:043]: 'Last Feed Portions': Received new state 1.000000

[13:43:40][V][miot.text_sensor:011]: MCU reported text sensor 4:5 is: 255
[13:43:40][V][text_sensor:013]: 'Last Feed Source': Received new state 255

// Read directly afterwards
[13:46:40][V][miot:189]: Sending reply 'down get_properties 4 4 4 5' to MCU
[13:46:40][V][miot:095]: Received MCU message 'result 4 4 0 5 4 5 0 5 get_down'

[13:46:40][V][miot.sensor:011]: MCU reported sensor 4:4 is: 5.000000
[13:46:40][V][sensor:043]: 'Last Feed Portions': Received new state 5.000000

[13:46:40][V][miot.text_sensor:011]: MCU reported text sensor 4:5 is: 5
[13:46:40][V][text_sensor:013]: 'Last Feed Source': Received new state 5