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

Change updateValue to return not responding status #556

Merged
merged 1 commit into from
Feb 5, 2018
Merged

Change updateValue to return not responding status #556

merged 1 commit into from
Feb 5, 2018

Conversation

NorthernMan54
Copy link
Contributor

I have been moving my plugins away from using getValue to return the current accessory state, and switching to a event based model, and having the plugin push state via updateValue or setValue. ( I'm switching to this event based model, to improve the responsiveness of the Home app and reduce the lagging caused by the callouts to remote devices to return state. ) While this works really well, what is lacking is the ability to deal with accessories that are not responding for various reasons, as the updateValue and setValue don't accept a value of 'Error'. And I'm not aware of any way to set a 'Not Responding' for an accessory either thru a characteristic or the HAP event interface, except as a response to "GET /characteristics".

Creates a characteristic level status 'this.status' - Value is null or the Error returned by the callback.

Changes updateValue and setValue to accept "Error" as a newValue, and update the status.

Changes getValue to include status as part of the response when there are no listeners to the get event

To use the feature, have the value updated by updateValue or setValue be an instance of Error. During the next get characteristics request, the accessory will display 'Not responding'. When the device starts responding again, sending a valid value, that is not an instance of 'Error' will clear the 'Not responding' message after the next get characteristics.

ie use this for updateValue

Accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).updateValue(new Error("Polling failed"));

Optional additional functionality

If you want to set a particular HAP return code, have the error be the HAP return code.

ie use this instead for updateValue

Accessory.getService(Service.Outlet).getCharacteristic(Characteristic.On).updateValue(new Error(HAPServer.Status.SERVICE_COMMUNICATION_FAILURE));

To gain access to the HAPServer Status codes, add these 2 HAPServer lines to the start of your plugin.

var Accessory, Service, Characteristic, UUIDGen, HAPServer;

module.exports = function(homebridge) {

Accessory = homebridge.platformAccessory;
Service = homebridge.hap.Service;
Characteristic = homebridge.hap.Characteristic;
UUIDGen = homebridge.hap.uuid;
HAPServer = homebridge.hap.HAPServer;

homebridge.registerPlatform("homebridge-ecoplugs", "EcoPlug", EcoPlugPlatform);
}

@NorthernMan54
Copy link
Contributor Author

@KhaosT @ebaauw @pdlove

This replaces my previous pull request, as it was significantly out of date with the current master, and I couldn't easily rebase my fork.

@KhaosT KhaosT merged commit 6b14886 into homebridge:master Feb 5, 2018
@KhaosT
Copy link
Contributor

KhaosT commented Feb 5, 2018

Looks good to me :)

@NorthernMan54
Copy link
Contributor Author

NorthernMan54 commented Feb 5, 2018 via email

@NorthernMan54 NorthernMan54 deleted the valueUpdate branch March 6, 2018 01:58
kauberry added a commit to kauberry/HAP-NodeJS that referenced this pull request Aug 22, 2018
* 'master' of github.com:KhaosT/HAP-NodeJS: (58 commits)
  0.4.47
  Add ability to pass in mdns config.
  Add setupURI to the TypeScript def for Accessory (homebridge#594)
  Update bonjour dependency to resolve a crash caused by state management of mdns announcement.
  Fix the issue where we incorrectly removed pairing information on closing connection.
  0.4.44
  Remove the duplicated `start`
  0.4.43
  Ensure the uniqueness of service name
  0.4.42
  Legacy Dictionary Fixes (homebridge#569)
  Create Sprinkler_accessory.js (homebridge#585)
  Fix Node v10 support
  Update Light_accessory.js (homebridge#583)
  Update SSRC generation.
  Use Int32 instead of UInt32 for ssrc.
  Changes SSRC to be random per prepareStream, not always 1 (homebridge#558)
  0.4.41
  Change updateValue to handle not responding status (homebridge#556)
  Add max, min and valid values to the new services (homebridge#551)
  ...

# Conflicts:
#	accessories/Light_accessory.js
#	lib/gen/HomeKitTypes.js
#	package.json
@aboulfad
Copy link

To use the feature, have the value updated by updateValue or setValue be an instance of Error. During the next get characteristics request, the accessory will display 'Not responding'. When the device starts responding again, sending a valid value, that is not an instance of 'Error' will clear the 'Not responding' message after the next get characteristics.

I know this is an old post, but checking HAP Node git master and this commit, shows the changes are still there. I am trying to understand the changes and why there isnt any event/update to the accessory using this code update.

The addition to Characteristic.prototype.updateValue set status = newValue https://github.com/KhaosT/HAP-NodeJS/blob/1862f73d495c7f25d3ed812abac4be4c1d2dee34/lib/Characteristic.js#L359-L363 but later on the newValue = new Error is overwritten in validateValue(newValue) which returns 0.

If I follow correctly, there is nothing that is emitted, or sent to the accessory. I followed the example, added 'debug' to the 'characteristic.js' file but no change on console or the accessory itself on iOS. There is no change when using an instance of Error("..") in updateValue.

Any help would be greatly appreciated. Using HAP-Node master & iOS12.2. The only confusing part is the usage of "status" which is not clear how it causes a change to the accessory side.

@NorthernMan54
Copy link
Contributor Author

I can confirm that this feature is still working with iOS 12.2 and the latest version of homebridge/Hap-nodejs.

Also, please keep in mind that the ‘not responding’ status is only sent to HomeKit as a response to the characteristic status request. And is not sent as an event. The HomeKit API for events does not support the setting of a not responding status.

To sum it up, the response to a characteristic status pull request from the home app can include an error response that triggers ‘not responding’. But characteristic status push events from hap-nodejs can not, and this is a HomeKit API limitation.

When your testing the feature, are you triggering a characteristic status request from the home app? Ie restart the home app or change rooms

@aboulfad
Copy link

aboulfad commented Apr 24, 2019

Thank you for the reply. Ok gotcha on the characteristic status request and I was changing rooms or restarting the Home App but no change. I wonder if the MQTT server retained values for the characteristics parameters are affecting it. I will remove "retain" flag from the MQTT client and try.

if (message == 'exit') {
      debug("Received message %s", message);
      sensor
      .getService(Service.TemperatureSensor)
      .getCharacteristic(Characteristic.CurrentTemperature)
      .updateValue(new Error("No Response"));
      
      hsensor
      .setCharacteristic(Characteristic.CurrentRelativeHumidity, new Error("Offline"));
    }

@aboulfad
Copy link

aboulfad commented Apr 24, 2019

The MQTT retain flag has nothing to do with it, as HAP-Node caches or uses the previous values. Here is a log that shows that a characteristic status request was triggered but I can't tell from the debug logs if indeed something was sent or not to Homekit (home app does NOT show offline, not responding, ...)

For some reason, this code section is never reached which I think is relevant. https://github.com/KhaosT/HAP-NodeJS/blob/1862f73d495c7f25d3ed812abac4be4c1d2dee34/lib/Characteristic.js#L166-L168

Hap-Node JS Log
 -------------------- Received LWT "exit" msg -------------------------------
 _DHTTiny received topic home/dht11tiny/status message exit +5s
  _DHTTiny Received message exit +2ms

  EventedHTTPServer [::ffff:10.10.1.109] HTTP request: /characteristics +55s
  HAPServer [C1:5D:3A:AE:5E:FB] HAP Request: PUT /characteristics +2ms
  Accessory [Tiny DHT11 Sensor] Processing characteristic set: [{"aid":1,"iid":9,"ev":true},{"aid":1,"iid":12,"ev":true}] +2ms
  Accessory [Tiny DHT11 Sensor] Registering Characteristic "Current Temperature" for events +1ms
  Accessory [Tiny DHT11 Sensor] Registering Characteristic "Current Relative Humidity" for events +0ms
  EventedHTTPServer [::ffff:10.10.1.109] HTTP Response is finished +2ms
  EventedHTTPServer [::ffff:10.10.1.109] HTTP request: /characteristics?id=1.9,1.12 +17ms
  HAPServer [C1:5D:3A:AE:5E:FB] HAP Request: GET /characteristics?id=1.9,1.12 +1ms
  Accessory [Tiny DHT11 Sensor] Getting value for Characteristic "Current Temperature" +2ms
  Accessory [Tiny DHT11 Sensor] Got Characteristic "Current Temperature" value: 22.4 +2ms
  Accessory [Tiny DHT11 Sensor] Getting value for Characteristic "Current Relative Humidity" +2ms
  Accessory [Tiny DHT11 Sensor] Got Characteristic "Current Relative Humidity" value: 70 +1ms
  EventedHTTPServer [::ffff:10.10.1.109] HTTP Response is finished +3ms
  EventedHTTPServer [::ffff:10.10.1.101] HTTP request: /characteristics +11s
  HAPServer [C1:5D:3A:AE:5E:FB] HAP Request: PUT /characteristics +2ms
  Accessory [Tiny DHT11 Sensor] Processing characteristic set: [{"aid":1,"iid":12,"ev":true},{"aid":1,"iid":9,"ev":true}] +2ms
  Accessory [Tiny DHT11 Sensor] Registering Characteristic "Current Relative Humidity" for events +1ms
  Accessory [Tiny DHT11 Sensor] Registering Characteristic "Current Temperature" for events +1ms
  EventedHTTPServer [::ffff:10.10.1.101] HTTP Response is finished +2ms

-------------------- Changed rooms back and forth, HAP-Node uses previous cached values -------------------------
  EventedHTTPServer [::ffff:10.10.1.109] HTTP request: /characteristics?id=1.9,1.12 +12s
  HAPServer [C1:5D:3A:AE:5E:FB] HAP Request: GET /characteristics?id=1.9,1.12 +1ms
  Accessory [Tiny DHT11 Sensor] Getting value for Characteristic "Current Temperature" +2ms
  Accessory [Tiny DHT11 Sensor] Got Characteristic "Current Temperature" value: 22.4 +1ms
  Accessory [Tiny DHT11 Sensor] Getting value for Characteristic "Current Relative Humidity" +1ms
  Accessory [Tiny DHT11 Sensor] Got Characteristic "Current Relative Humidity" value: 70 +1ms
  EventedHTTPServer [::ffff:10.10.1.109] HTTP Response is finished +2ms

@NorthernMan54
Copy link
Contributor Author

Looking at your log, are you actually setting the "Error" status?

Here is a log from my environment, please note the line "Error getting value", this is the error being returned.

Thu, 25 Apr 2019 01:39:02 GMT EcoPlug Plug not responding ECO-7801DEF1 Floor Fan
Thu, 25 Apr 2019 01:39:12 GMT EcoPlug Plug not responding ECO-7801DEF1 Floor Fan
Thu, 25 Apr 2019 01:39:22 GMT EcoPlug Plug not responding ECO-7801DEF1 Floor Fan
Thu, 25 Apr 2019 01:39:26 GMT EventedHTTPServer [::ffff:192.168.1.194] HTTP request: /characteristics?id=20.10,17.10,23.10
Thu, 25 Apr 2019 01:39:26 GMT HAPServer [CC:22:3D:E3:CE:35] HAP Request: GET /characteristics?id=20.10,17.10,23.10
Thu, 25 Apr 2019 01:39:26 GMT Accessory [Howard] Getting value for Characteristic "On"
Thu, 25 Apr 2019 01:39:26 GMT Accessory [Howard] Got Characteristic "On" value: false
Thu, 25 Apr 2019 01:39:26 GMT Accessory [Howard] Error getting value for Characteristic "On": No Response
Thu, 25 Apr 2019 01:39:26 GMT Accessory [Howard] Getting value for Characteristic "On"
Thu, 25 Apr 2019 01:39:26 GMT Accessory [Howard] Got Characteristic "On" value: false
Thu, 25 Apr 2019 01:39:26 GMT Accessory [Howard] Getting value for Characteristic "On"
Thu, 25 Apr 2019 01:39:26 GMT Accessory [Howard] Got Characteristic "On" value: false
Thu, 25 Apr 2019 01:39:26 GMT EventedHTTPServer [::ffff:192.168.1.194] HTTP Response is finished

This request was from a page reload with three devices on the page, and one of them was 'not responding'

The plugin code behind this is here

https://github.com/NorthernMan54/homebridge-ecoplug/blob/e353de921ae4bc4bd3e2f2884783c2ddcf7869e9/index.js#L188

And the actual message is returned from here in Accessory.js

https://github.com/KhaosT/HAP-NodeJS/blob/1862f73d495c7f25d3ed812abac4be4c1d2dee34/lib/Accessory.js#L776

@aboulfad
Copy link

Thanks again, “error status”? I thought the only thing required was to use updateValue as per the code snippet I included in post above. Is there another step?

I’ve came across the code you linked but can’t yet deduce what is missing in my hap-node code. I may think it has to do with this snippet but unsure... https://github.com/KhaosT/HAP-NodeJS/blob/1862f73d495c7f25d3ed812abac4be4c1d2dee34/accessories/TemperatureSensor_accessory.js#L40

@NorthernMan54
Copy link
Contributor Author

In your logging are you seeing this being executed?

if (message == 'exit') {
      debug("Received message %s", message);

In that example your shared, the callback needs to be an error object and not 'null', the callback lands here

https://github.com/KhaosT/HAP-NodeJS/blob/1862f73d495c7f25d3ed812abac4be4c1d2dee34/lib/Characteristic.js#L164

And sets 'status' to be the first parameter of the callback.

@aboulfad
Copy link

aboulfad commented Apr 25, 2019

Yes, execution reaches that line, and you just confirmed my suspicion, the callback needs to be an error object. I just literally read your first post in the PR and thought the callback(null,value) is fine... I also saw that .emit code but couldn’t piece all together. Not obvious for noobs. Although this line says it ... Creates a characteristic level status 'this.status' - Value is null or the Error returned by the callback lol

I now have to understand how to do this !

@aboulfad
Copy link

ok that was easy ... All I did was initialize a var myerr to null, and set that error object accordingly based on the acc presence/reachability.

But one confusing find, the .updateValue(myerr) is not needed as you explained that the error is only returned in response to a charac status request. So then what's the purpose of that .updateValue(myerr) ?

Just setting the error in the callback is sufficient to trigger this code section https://github.com/KhaosT/HAP-NodeJS/blob/1862f73d495c7f25d3ed812abac4be4c1d2dee34/lib/Characteristic.js#L164

 _H2OS currentime 07:28 received topic home/basement/h2os1/status message exit +43s
  Accessory [Water Sensor] Getting value for Characteristic "Leak Detected" +6s
  Accessory [Water Sensor] Got Characteristic "Leak Detected" value: undefined +1ms
  Accessory [Water Sensor] Error getting value for Characteristic "Leak Detected": Bye +1ms
var myerr = null; // init the error object

// Add the actual Sensor Service.
sensor
  .addService(lsensor)
  .getCharacteristic(Characteristic.LeakDetected)
  .on('get', function(callback) {
    callback(myerr, ACC.getLeak());
   });

isAccReachable ? myerr = null : myerr = new Error("Bye");

@NorthernMan54
Copy link
Contributor Author

NorthernMan54 commented Apr 25, 2019 via email

@aboulfad
Copy link

Thank you for that additional insight, that is very interesting. I always thought the .get event is required but I will experiment. And thanks again for all your replies and this PR !

@NorthernMan54
Copy link
Contributor Author

Good luck, and if you have more questions, I’m around

@aboulfad
Copy link

aboulfad commented Apr 26, 2019

So I removed all get event handlers, and used updateValue for all updates incl errors, and indeed it works :-) Even when no cached values exist (start from scratch, clear mosquitto db) and device offline, HAP-Node will PUT charac defaults of 0 to Homekit (a safeguard).

I take your word about this increasing Homekit responsiveness, I have no way of testing it as I only have around 10 IoT devices running on HAP-Node. I did notice few times that Home app takes a while to update the HAP-Node devices but can't correlate this to the get event handlers.

The reason for the get handler is explained by @KhaosT in the example comments: https://github.com/KhaosT/HAP-NodeJS/blob/1862f73d495c7f25d3ed812abac4be4c1d2dee34/accessories/Light_accessory.js#L106-L109

But if the cached Characteristic.value(s) are the result of querying the devices through say MQTT and updateValue, then implementing that get handler is kinda redundant or not needed.

@NorthernMan54
Copy link
Contributor Author

NorthernMan54 commented Apr 26, 2019 via email

@aboulfad
Copy link

aboulfad commented Apr 26, 2019

Indeed, coupling devices with MQTT (or other means) and the usage of updateValue is the most ideal. That is how all my devices behave, I just had that not-needed get handler lying there for no good reason :-)

It's too bad that Homekit doesn't support not responding status in events, a bit puzzling...
Other homekit enabled apps (Eve,...) do seem to respond and display the active, tampered, fault status, but cant recall if it was via events or a response to a query. I just tested Characteristic.StatusActive with the Eve App, and the device icon updates to show it is inactive based on a push event !

EventedHTTPServer [::ffff:10.10.1.109] Sending HTTP event '1.14' with data: {"characteristics":[{"aid":1,"iid":14,"value":false}]} +1ms

This could have been a nice alternative to using the error status had Home app display those events on the device icon instead of embedding them in device settings ... (Apple being lazy)

@lboue
Copy link

lboue commented Oct 28, 2019

I managed to report accessory "not responding" with all the comments. Thanks !

IMG_3121

You can try with my test file here:
https://github.com/lboue/HAP-NodeJS/blob/no_response/accessories/Light_accessory.js

Regards

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

Successfully merging this pull request may close these issues.

4 participants