Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plugin accessories not updating after refresh, need development guidance. #3529

Closed
mrjackyliang opened this issue Jan 5, 2024 · 25 comments
Closed
Labels

Comments

@mrjackyliang
Copy link

Current Situation

Hello, I am re-writing a security system plugin and what I noticed is that all the accessories don't update until I close the Home app, or switch pages and have the app refresh itself. I tried a few methods, both with no luck.

Methods I've used:

  • onGet()
  • on('get')
  • updateValue()
  • updateCharacteristic()

A small snippet on how I fetch contact sensors:

this.#services.Primary.getCharacteristic(this.#characteristic.ContactSensorState)
  .onGet(async () => this.getSensorStatus('status', context));

A small snippet on how I set the security panel:

this.#services.Primary.getCharacteristic(this.#characteristic.SecuritySystemTargetState)
  .onSet(async (value) => this.setPanelStatus(value, context));

If anyone has come across this issue, please do let me know, thanks! Or if you require more code, please do let me know!

Logs

N/A

Configuration

N/A

Environment

  • OS: Sonoma 14.2.1
  • Homebridge: 1.7.0
  • Node: 18.19.0
  • npm: 10.2.3

Process Supervisor

not applicable

Additional Context

No response

@NorthernMan54
Copy link
Contributor

@mrjackyliang I use this feature with most of my plugins, and to enable it, do not implement the onGet() and on('get') interface and only use updateValue() or updateCharacteristic()

@mrjackyliang
Copy link
Author

Will try this method out, thank you!!

@mrjackyliang
Copy link
Author

@NorthernMan54 Just to further clarify, will I continue to to use the onSet method, or change that as well?

Would be awesome if I can see an example

@NorthernMan54
Copy link
Contributor

onSet is fine

An example - https://github.com/NorthernMan54/homebridge-tasmota/blob/473f4e593ff3d8d92710e9aa4b318f9dd7946f29/src/tasmotaSensorService.ts#L264

@mrjackyliang
Copy link
Author

Thanks! Will close this off for now, and if there are more issues, I'll ask here :)

@mrjackyliang
Copy link
Author

I made the changes, but this didn't seem to work. My accessories remain in a frozen state. If I change the system from Off to Home, the Security Panel remains at Off. Weird.

@NorthernMan54
Copy link
Contributor

If you enable HAP-NodeJS debug mode, you can see the messages between the Home App and HomeKit, this may help with digging into the issue

HAP-NodeJS DEBUG mode is explained here https://github.com/homebridge/HAP-NodeJS/wiki/FAQ

@mrjackyliang
Copy link
Author

Will read through it, thanks!

@mrjackyliang
Copy link
Author

So I'm looking through the logs, not sure what I'm looking for, but this seems interesting:

  HAP-NodeJS:EventedHTTPServer [::ffff:10.20.10.216] Muting event '3.11' notification for this connection since it originated here. +47ms
  HAP-NodeJS:EventedHTTPServer [::ffff:10.20.10.216] Muting event '3.12' notification for this connection since it originated here. +0ms
  HAP-NodeJS:EventedHTTPServer [::ffff:10.20.10.216] Muting event '5.13' notification for this connection since it originated here. +0ms

This happened after a force refresh when I didn't see the system armed. Now the question is, why isn't HomeKit getting notifications?

I also see this happening all the time, right after it finishes retrieving:

  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:10.20.10.216] HTTP Response is finished +15ms
  HAP-NodeJS:EventedHTTPServer Currently 1 hap connections open: ::ffff:10.20.10.216:53537 +4s
  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:10.20.10.216] Client connection closed +5s
  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:10.20.10.216] HTTP server was closed +2ms
  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:10.20.10.216] HTTP connection was closed +0ms
  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:10.20.10.216] HTTP server was closed +0ms

@NorthernMan54
Copy link
Contributor

Here is a sample debug log from my Tasmota plugin when I locally control the light switch. The relevant line of code is here - https://github.com/NorthernMan54/homebridge-tasmota/blob/473f4e593ff3d8d92710e9aa4b318f9dd7946f29/src/tasmotaLightService.ts#L221


  HAP-NodeJS:HAPServer [AA:BB:CC:DD:EE:02] HAP Request: PUT /characteristics +4ms
  HAP-NodeJS:Accessory [Heisenberg 1F10] Processing characteristic set: {"characteristics":[{"aid":41,"iid":10,"ev":true},{"aid":41,"iid":11,"ev":true},{"aid":41,"iid":12,"ev":true}]} +3ms
  HAP-NodeJS:Accessory [::ffff:192.168.1.29] Registered Characteristic "On" on "Heisenberg 1F10" for events +0ms
  HAP-NodeJS:Accessory [::ffff:192.168.1.29] Registered Characteristic "Configured Name" on "Heisenberg 1F10" for events +0ms
  HAP-NodeJS:Accessory [::ffff:192.168.1.29] Registered Characteristic "Brightness" on "Heisenberg 1F10" for events +0ms
  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:192.168.1.29] HTTP Response is finished +0ms

  Tasmota:mqtt emit tele/tasmota_CDBE79/STATE {"Time":"2024-01-09T03:23:30","Uptime":"43T11:51:20","UptimeSec":3757880,"Heap":25,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":99,"MqttCount":47,"POWER":"OFF","Dimmer":43,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"67 Bonacres","BSSId":"6C:70:9F:EB:06:40","Channel":1,"Mode":"11n","RSSI":80,"Signal":-60,"LinkCount":38,"Downtime":"0T00:02:29"}} +3m
  Tasmota:light statusUpdate tele/tasmota_CDBE79/STATE {"Time":"2024-01-09T03:23:30","Uptime":"43T11:51:20","UptimeSec":3757880,"Heap":25,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":99,"MqttCount":47,"POWER":"OFF","Dimmer":43,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"67 Bonacres","BSSId":"6C:70:9F:EB:06:40","Channel":1,"Mode":"11n","RSSI":80,"Signal":-60,"LinkCount":38,"Downtime":"0T00:02:29"}} +3m
[Tasmota] Updating 'Kitchen Table' to OFF
[Tasmota] Updating 'Kitchen Table' Brightness to 43
  Tasmota:light statusUpdate tele/tasmota_CDBE79/STATE {"Time":"2024-01-09T03:23:30","Uptime":"43T11:51:20","UptimeSec":3757880,"Heap":25,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":99,"MqttCount":47,"POWER":"OFF","Dimmer":43,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"67 Bonacres","BSSId":"6C:70:9F:EB:06:40","Channel":1,"Mode":"11n","RSSI":80,"Signal":-60,"LinkCount":38,"Downtime":"0T00:02:29"}} +5ms
[Tasmota] Updating 'Kitchen Table' to OFF
[Tasmota] Updating 'Kitchen Table' Brightness to 43
  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:192.168.1.29] Sending HAP event notifications [ { aid: 48, iid: 10, value: 0 } ] +23s

  Tasmota:mqtt emit tele/tasmota_CDBE79/STATE {"Time":"2024-01-09T03:23:45","Uptime":"43T11:51:35","UptimeSec":3757895,"Heap":25,"SleepMode":"Dynamic","Sleep":10,"LoadAvg":21,"MqttCount":47,"POWER":"ON","Dimmer":43,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"67 Bonacres","BSSId":"6C:70:9F:EB:06:40","Channel":1,"Mode":"11n","RSSI":82,"Signal":-59,"LinkCount":38,"Downtime":"0T00:02:29"}} +15s
  Tasmota:light statusUpdate tele/tasmota_CDBE79/STATE {"Time":"2024-01-09T03:23:45","Uptime":"43T11:51:35","UptimeSec":3757895,"Heap":25,"SleepMode":"Dynamic","Sleep":10,"LoadAvg":21,"MqttCount":47,"POWER":"ON","Dimmer":43,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"67 Bonacres","BSSId":"6C:70:9F:EB:06:40","Channel":1,"Mode":"11n","RSSI":82,"Signal":-59,"LinkCount":38,"Downtime":"0T00:02:29"}} +15s
[Tasmota] Updating 'Kitchen Table' to ON
[Tasmota] Updating 'Kitchen Table' Brightness to 43
  Tasmota:light statusUpdate tele/tasmota_CDBE79/STATE {"Time":"2024-01-09T03:23:45","Uptime":"43T11:51:35","UptimeSec":3757895,"Heap":25,"SleepMode":"Dynamic","Sleep":10,"LoadAvg":21,"MqttCount":47,"POWER":"ON","Dimmer":43,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"67 Bonacres","BSSId":"6C:70:9F:EB:06:40","Channel":1,"Mode":"11n","RSSI":82,"Signal":-59,"LinkCount":38,"Downtime":"0T00:02:29"}} +5ms
[Tasmota] Updating 'Kitchen Table' to ON
[Tasmota] Updating 'Kitchen Table' Brightness to 43
  HAP-NodeJS:EventedHTTPServer:Connection [::ffff:192.168.1.29] Sending HAP event notifications [ { aid: 48, iid: 10, value: 1 } ] +15s

For this I created a simple Home in the home app with only one accessory, a lamp.

@mrjackyliang
Copy link
Author

I have a feeling I need to read into MQTT first. Something is causing the connection between HAP and the Homebridge server to close.

@NorthernMan54
Copy link
Contributor

The MQTT here is just the messages received between my device and plugin, and is only relevant to see what is happening there. Besides that detail, it can be ignored.

If the connection is closing you may have a local network issue or iPhone sleeping or ? Typically the Home app drops the connection when the app closes etc, and opens it again when then the app opens.

@mrjackyliang
Copy link
Author

mrjackyliang commented Jan 9, 2024

Which is weird, you know. The app is open next to me, and the app doesn't change at all until I close and open it.

However, I haven't tried all of the scenarios yet (like keeping the app closed, my phone asleep, and changing my security system through an external source). But for local network issues, any pointers for what I should be looking for?

@NorthernMan54
Copy link
Contributor

NorthernMan54 commented Jan 9, 2024

I think you may have a fundamental design issue with your plugin

How does your plugin receive status updates from the device, and what does it do with the data ?

There are two design patterns for plugins, one for devices that push status changes ( my tasmota plugin ) and one the pulls or polls the status from the device. What does your device/plugin do ?

With updateValue, this needs to put into the status change code, and the updated value pushed to HomeKit.

@mrjackyliang
Copy link
Author

mrjackyliang commented Jan 9, 2024

I don't doubt that. There's always something missing somewhere🥲

The plugin starts with the platform, where the plugin initializes the API, and starts the syncing. The information is pulled based on the sync code changes, and all of that information is stored in the platform's "state" (some object in that class).

Once that's done, the plugin determines if the current accessory exists or not. If it doesn't, it executes addAccessory(). If it does, it executes updateAccessory(). I did have a hunch that I might not properly be sending updates correctly, and that problem might be in the updateAccessory().

Both add and update accessories initiate an instance of an Accessory class just like how the examples do it.

I just get stuck wondering if I might need some public method to force accessories to update.

@NorthernMan54
Copy link
Contributor

It should be simple, does you plugin pull status updates or does the device push status updates ?

If it pulls, then as part of the pull polling loop you need to updateValue for each change. If it pushes, then as part of the push event listener, once you determine which accessory it is, then updateValue.

@mrjackyliang
Copy link
Author

In the process of implementing the methods!

@mrjackyliang
Copy link
Author

mrjackyliang commented Jan 9, 2024

Yeah implementing the updateValue didn't work. What I did notice is this:

  • If I set the security panel remotely, Home app doesn't update until I force refresh.
  • If i set the security panel through the Home app, it successfully arms the system, but Home app would immediately display Off or become stuck in Arming..., and doesn't update any further until I force refresh.

@mrjackyliang
Copy link
Author

If you can help me point out what I'm not doing correctly, here's the latest updated file: https://github.com/mrjackyliang/homebridge-adt-pulse/blob/main/src/lib/accessory.ts

@mrjackyliang
Copy link
Author

Actually it seems to work now. Okay, I don't know what went wrong, but I literally tried everything!

@mrjackyliang
Copy link
Author

So what I discovered from all this is every time I fetch a status, I need to use both onGet and the updateValue methods. The onGet method is for grabbing initial states, while the updateValue is used to send push events when a status changes.

The onSet method remains the same, but I separated it away from both the get methods just for clarity.

I think the part why updateValue didn't work initially was I found out when I'm updating the accessory, I wasn't actually fetching for statuses, that's why the statuses only update when I closed/opened the Home app. That causes the onGet method to fire up.

But so far, I seem to understand Homebridge more now, and this can be used as a reference who happen to come across the same problem as me!

Thanks for the guidance, @NorthernMan54!

@NorthernMan54
Copy link
Contributor

One other comment, updateValue caches the value within Homebridge ( actually HAP-NodeJS ), and when the Home App is closed/opened the cached values are returned. Greatly increasing the overall response time of the plugin.

You should be able to architect the plugin to not use onGet, and just have the initial state value load push the status using updateValue.

@mrjackyliang
Copy link
Author

I did try removing onGet earlier, it returned mixed responses (sometimes it would show the status, sometimes it won't). As far as I know, it should simply return the cached value, but for some reason, updateValue works if the onGet is there as well.

@mrjackyliang
Copy link
Author

mrjackyliang commented Jan 13, 2024

@NorthernMan54 Just coming back to tell you the plugin now works without onGet! Not sure what happened there, but I tried it this morning, all tests passed!

Thank you!!

@NorthernMan54
Copy link
Contributor

That is awesome, Tks for adding this to the available plugins

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants