raetha / wyzesense2mqtt

Configurable WyzeSense to MQTT Gateway intended for use with Home Assistant or other platforms that use MQTT discovery mechanisms.
MIT License
79 stars 22 forks source link

Add debouncing for state events #35

Open dale3h opened 4 years ago

dale3h commented 4 years ago

Is your feature request related to a problem? Please describe.

Yes. Sometimes a state event is sent twice.

Describe the solution you'd like

Some implementation of debouncing to prevent identical state events from being handled twice.

Additional context

Here are some (custom) debug logs that show multiple state events being handled simultaneously:

Jul 23 01:46:46 wyzesense2mqtt python3[18592]: sensor_mac: 77800DFB
Jul 23 01:46:46 wyzesense2mqtt python3[18592]: State event data: [2020-07-23 01:46:45][77800DFB]StateEvent: sensor_type=motion, state=active, battery=96, signal=89
Jul 23 01:46:46 wyzesense2mqtt python3[18592]: [TRACE] sensor_state: active
Jul 23 01:46:46 wyzesense2mqtt python3[18592]: [TRACE] event.MAC: 77800DFB
Jul 23 01:46:46 wyzesense2mqtt python3[18592]: [TRACE] invert_state: False
Jul 23 01:46:46 wyzesense2mqtt python3[18592]: {'available': True, 'mac': '77800DFB', 'device_class': 'motion', 'last_seen': 1595486805.816, 'last_seen_iso': '2020-07-23T01:46:45.816000', 'signal_strength': -89, 'battery': 96, 'name': 'Garage Motion', 'state': 1}

Jul 23 01:47:01 wyzesense2mqtt python3[18592]: sensor_mac: 77836170
Jul 23 01:47:01 wyzesense2mqtt python3[18592]: State event data: [2020-07-23 01:47:00][77836170]StateEvent: sensor_type=switch, state=close, battery=97, signal=85
Jul 23 01:47:01 wyzesense2mqtt python3[18592]: [TRACE] sensor_state: close
Jul 23 01:47:01 wyzesense2mqtt python3[18592]: [TRACE] event.MAC: 77836170
Jul 23 01:47:01 wyzesense2mqtt python3[18592]: [TRACE] invert_state: True
Jul 23 01:47:01 wyzesense2mqtt python3[18592]: {'available': True, 'mac': '77836170', 'device_class': 'opening', 'last_seen': 1595486820.137, 'last_seen_iso': '2020-07-23T01:47:00.137000', 'signal_strength': -85, 'battery': 97, 'name': 'Doorbell', 'state': 0}

Jul 23 01:47:04 wyzesense2mqtt python3[18592]: sensor_mac: 77A5E27A
Jul 23 01:47:04 wyzesense2mqtt python3[18592]: State event data: [2020-07-23 01:47:03][77A5E27A]StateEvent: sensor_type=motion, state=inactive, battery=93, signal=54
Jul 23 01:47:04 wyzesense2mqtt python3[18592]: [TRACE] sensor_state: inactive
Jul 23 01:47:04 wyzesense2mqtt python3[18592]: [TRACE] event.MAC: 77A5E27A
Jul 23 01:47:04 wyzesense2mqtt python3[18592]: [TRACE] invert_state: False
Jul 23 01:47:04 wyzesense2mqtt python3[18592]: {'available': True, 'mac': '77A5E27A', 'device_class': 'motion', 'last_seen': 1595486823.058, 'last_seen_iso': '2020-07-23T01:47:03.058000', 'signal_strength': -54, 'battery': 93, 'name': 'Back Porch Motion', 'state': 0}

>>> This is the first event of the duplicated state events. <<<
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: sensor_mac: 77836170
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: State event data: [2020-07-23 01:47:09][77836170]StateEvent: sensor_type=switch, state=open, battery=99, signal=88
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: [TRACE] sensor_state: open
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: [TRACE] event.MAC: 77836170
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: [TRACE] invert_state: True
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: {'available': True, 'mac': '77836170', 'device_class': 'opening', 'last_seen': 1595486829.336, 'last_seen_iso': '2020-07-23T01:47:09.336000', 'signal_strength': -88, 'battery': 99, 'name': 'Doorbell', 'state': 0}

>>> This is the second event of the duplicated state events. <<<
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: sensor_mac: 77836170
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: State event data: [2020-07-23 01:47:09][77836170]StateEvent: sensor_type=switch, state=open, battery=99, signal=88
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: [TRACE] sensor_state: open
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: [TRACE] event.MAC: 77836170
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: [TRACE] invert_state: True
Jul 23 01:47:10 wyzesense2mqtt python3[18592]: {'available': True, 'mac': '77836170', 'device_class': 'opening', 'last_seen': 1595486829.336, 'last_seen_iso': '2020-07-23T01:47:09.336000', 'signal_strength': -88, 'battery': 99, 'name': 'Doorbell', 'state': 0}

Jul 23 01:47:26 wyzesense2mqtt python3[18592]: sensor_mac: 77800DFB
Jul 23 01:47:26 wyzesense2mqtt python3[18592]: State event data: [2020-07-23 01:47:23][77800DFB]StateEvent: sensor_type=motion, state=inactive, battery=96, signal=89
Jul 23 01:47:26 wyzesense2mqtt python3[18592]: [TRACE] sensor_state: inactive
Jul 23 01:47:26 wyzesense2mqtt python3[18592]: [TRACE] event.MAC: 77800DFB
Jul 23 01:47:26 wyzesense2mqtt python3[18592]: [TRACE] invert_state: False
Jul 23 01:47:26 wyzesense2mqtt python3[18592]: {'available': True, 'mac': '77800DFB', 'device_class': 'motion', 'last_seen': 1595486843.947, 'last_seen_iso': '2020-07-23T01:47:23.947000', 'signal_strength': -89, 'battery': 96, 'name': 'Garage Motion', 'state': 0}
raetha commented 4 years ago

I’m not sure why something would be sending twice, but I like the idea of preventing it. I wonder if this will be easy to implement after adding the birth/will support I just logged. Once that is done, we’d be storing the last state value Which would make for an easy comparison before sending again.

Did you have an idea here on how you wanted to implement this?

dale3h commented 4 years ago

There have been quite a few things in this project that have sent me for a puzzled brain, but I refuse to give up on it. Like I said before, it is far more stable than the HA custom integration.

Apparently I am the "rare case" for every scenario that we've found yet, but that is a good thing because I am willing to speaking up about my experience with the software.

I honestly have no clue where to begin to implement this. Might it be possible to keep a global variable of event payloads and skip publishing if the timestamp matches? I just don't know enough about the underlying asynchronous nature of the script to understand the best place to address this issue.

raetha commented 4 years ago

Here's what I propose on this one. Assuming you are able to pick up another bridge soon, lets see if this repeats with a second bridge. It's possible this is a side effect of whatever is causing the bridge/USB disconnect issues.

If it does stick around, lets start by adding a SENSOR_STATES dict (like what I'm talking about in the HA birth/will issue), and compare the major values in the event to that, in particular the state and timestamp values. We could just start with that living in memory and determine if we want to store it later, but would give us a relatively quick way to test for the duplicates without having to settle on a storage option for now.

Sound good?