arachnetech / homebridge-mqttthing

A plugin for Homebridge allowing the integration of many different accessory types using MQTT.
Apache License 2.0
469 stars 103 forks source link

Identify device errors #10

Closed MoeweX closed 5 years ago

MoeweX commented 6 years ago

Hi,

is there the possibility to add a last will functionality? I.e., if a device disconnects from an MQTT broker, the broker can publish a last will message for that device. This can be used to permanently indicate a device error, until the device gets back online. In such a case, the get methods of an accessory (such as the outlet) would not return anything anymore in order to indicate, that the device is offline.

Or how does homebridge currently identify a device error?

Best, Jonathan.

arachnetech commented 6 years ago

I believe I could add support for last will functionality from the MQTT side, but I'm not sure what I could usefully tell Homebridge. Which device types are you wanting to use this with?

hejsiri commented 6 years ago

Detecting the condition of the device is very important. This situation: I physically switch on the light switch on the wall, but the iOS home app does not update the state. For comparison, another "mqtt-switch-tasmota" plugin updates the device state correctly. Unfortunately, its disadvantage is the lack of support for the type of "lightbulb" device. Your plugin is great, you only need to add support for device status.

For example, look at the configuration:

{ "accessory": "mqtt-switch-tasmota", "switchtype": "lightbulb", "url": "mqtt://192.168.99.100", "username": "", "password": "", "topics": { "statusGet": "stat/salon_lampa/POWER", "statusSet": "cmnd/salon_lampa/power", "stateGet": "tele/salon_lampa/STATE" }, "onValue": "ON", "offValue": "OFF", "activityTopic": "tele/salon_lampa/LWT", "activityParameter": "Online", "startCmd": "cmnd/salon_lampa/TelePeriod", "startParameter": "120", "manufacturer": "Itead", "model": "Sonoff Basic", "serialNumberMAC": "5C:CF:7F:7A:6C:4D", "name": "Salon lampa" },

{ "accessory": "mqttthing", "type": "lightbulb", "name": "Salon lampa X", "url": "mqtt://192.168.99.100", "username": "", "password": "", "caption": "", "topics": { "getOn": "stat/salon_lampa/Power", "setOn": "cmnd/salon_lampa/Power" }, "integerValue": "false", "onValue": "ON", "offValue": "OFF" }

...and this movie: https://youtu.be/3xSeWYWbF2k

arachnetech commented 6 years ago

Thanks for the detail - I think I understand now.

homebridge-mqttthing already supports get topics in addition to set topics. So, for example with this configuration for a light:

        {
            "accessory": "mqttthing",
            "type": "lightbulb",
            "name": "Office Lamp",
            "topics": {
                "getOn": "rf1/get/9",
                "setOn": "rf1/set/9"
            },
            "integerValue": true
        }

... the topic rf1/set/9 is published when Homekit turns a light on or off, e.g. (using mosquitto_sub -v -t "#"):

rf1/set/9 0
rf1/set/9 1

... and the topic rf1/get/9 may be published by the light switch to notify Homekit (through homebridge-mqttthing) of its state. Testing this with mosquitto_pub (as my light is an RF receiver only):

pi@homebridge:~ $ mosquitto_pub -t rf1/get/9 -m "1"
pi@homebridge:~ $ mosquitto_pub -t rf1/get/9 -m "0"

... the light's state updates as expected in the Home App.

MoeweX commented 6 years ago

Hi,

so what would the home app show, when you publish rf1/get/9 -m "1", and afterwards the device crashes (so it is neither on or off, it is "not reachable")? It would still show 1, right?

arachnetech commented 6 years ago

It would, yes. With a last will message you could tell set it reliably to on or off on device crash, I believe - but I’m not aware of a way to give homebridge a separate ‘device not responding’ state.

MoeweX commented 6 years ago

I think the easiest solution is to simply not use the callback, e.g., when your plugin receives a last will message indicating that a device is now offline, it does not use this callback for a boolean value anymore: https://github.com/arachnetech/homebridge-mqttthing/blob/b041271d733cbeaed5c9d8b1b054d428ee687091/index.js#L104

I am not to sure about another solution that crossed my mind: can't you use the "Active" Characteristic or, as a work around, put the battery level to 0%?

By the way: thank you for responding to all my messages here!

arachnetech commented 6 years ago

Unfortunately Characteristic.StatusActive and Characteristic.StatusFault appear only to be supported by sensor types. I already support them for motionSensor, occupancySensor, lightSensor, temperatureSensor, humiditySensor, contactSensor, smokeSensor and doorBell. I just tried adding Characteristic.StatusFault to a light bulb and it did nothing.

Also, not calling the callback in charac.on('get') doesn't seem to do much. From the tests I've just done, I'm not even sure that code's required. (I based mqttthing on the logic used by another plugin, but I may have made a mistake or there may even have been an error in the original.)

If you have any other ideas do let me know. I'll leave this 'open' in case I find anything that might help too.

Delighted to respond when I get time - it's great to know that people are using this. I created it for my own convenience but hoped it might be useful to other homebridge users too.

MoeweX commented 6 years ago

Ok, thanks for testing this! I thought not using the callback would work, as I once forgot to use the callback in one of my plugins which rendered the accessory unusable, but I could be mistaken. I will look into it :).

However, I use your plugin already in great success together with https://github.com/MoeweX/RemoteSwitchBricklet_MQTT, so thanks!

arachnetech commented 6 years ago

Thanks. Do let me know the results of your tests (I may well have missed something) or if you have any other ideas. It would be handy to add this functionality.

MoeweX commented 6 years ago

Hi, this morning I ran some experiments and came up with the following, sorry that I took so long :):

What does this mean: It is possible to set an accessory to "offline" via mqtt. For that, an is_connected boolean has to be added to an accessories state field in your plugin. This boolean is controlled via a last will mqtt topic, upon a received last will message, the boolean is set to false. When the boolean is false, both callbacks are not used anymore.

The boolean is set to true again, when any mqtt message on another topic is received for the respective accessory. Therefore, a device also has to publish it's current state on startup to set is_connected to true, e.g., an outlet device publishes off, when it is ready to receive comments.

I think this would be a cool feature, however, it would increase the complexity of your plugin from the user perspective as devices that use this functionality need to publish an initial state upon startup and configure a last will message. What do you think?

arachnetech commented 6 years ago

Thanks for testing this, and explaining the necessary changes. I could certainly do what you've described - but presumably an accessory would only show as 'Not responding' in the Home app when something triggered a get or set call - i.e. (from your tests) only when the Home app refreshed the state of an accessory or tried to change the state of an accessory. Effectively the 'not responding' state has to be pulled, rather than being pushed as soon as the last will message is received. Would this really be sufficiently useful to be worth implementing?

MoeweX commented 6 years ago

I actually do think so, as with this feature one can at least be sure that the physical device, e.g., a light bulb, received the command, i.e., was active. Otherwise, it is possible that the device's mqqt client has not been connected for a very long time... . I think this is not a top priority, but useful nevertheless. Or what do you think?

Kepete commented 6 years ago

@arachnetech @MoeweX I do also think that this would be a needed feature. It is actually the only feature I'm missing from this plugin, so I think it is worth implementing :) And thanks for the awesome plugin!

tobekas commented 6 years ago

You can set the reachability of an accessory by writing an error status code in the callback argument. HomeKit then renders this as "not reachable". This is the recommended way in Hobebridge / HAP-NodeJS. See also https://github.com/KhaosT/HAP-NodeJS/issues/499

Unfortunately, as it was already noted correctly, this status is not immediately pushed, but accepted at the next HomeKit-get (polling). That would be okay for most of the use cases. Nobody is waiting with an open Home-app for a device going offline. However, if the set-call fails, then the status is updated immediately.

Instead of not calling callback(null,state[property]); you can call callback(1) within the HomeKit get and set event.

It wound be great, if you can implement this feature to be used with an optional isConnected or isOnline topic (for all types of accessories) Would also be useful for sensors, that no longer sent values (timeout).

Thanks so far, for your great work and the very simple, versatile plugin

Kepete commented 6 years ago

Are there any updates for this? Really waiting for the LWT to be added :)

arachnetech commented 6 years ago

Thanks for the nudge!

Thinking about this again from Jonathan's description of LWT: "if a device disconnects from an MQTT broker, the broker can publish a last will message for that device" at the top of this thread...

If mqttthing sets an LWT then this will be published by the broker if mqttthing disconnects from the broker. So, we could use this to (for example) turn off a light if Homebridge was stopped - but if we want a disabled device to 'tell' mqttthing that it's not responding then the device will need to set an LWT message when it connects to the broker.

So the functionality that I'd add would be a new subject like getOnline, to which the device would publish 1 (or whatever represented true) on start-up, and for which the device would configure an LWT message to publish 0 (or whatever represented false) to when it disconnected. Mqttthing would respond to an indication of the device not being online by becoming 'not reachable' by one of the mechanisms discussed above.

Am I understanding this correctly, and if so is this the functionality that you'd like me to add?

tobekas commented 6 years ago

Yes, exactly! This functionality would be great. AnisOnline topic is required from the device, which must be set to 1 after startup (with retained flag) and to 0 via LWT if the device is going offline. Mqttthing could store this info in the state array, such as the characteristic values. Only that it is not a “real” HomeKit characteristic.

arachnetech commented 6 years ago

Thanks for confirming - very helpful. Looking at it now.

arachnetech commented 6 years ago

I have (hopefully!) implemented a getOnline topic for all accessories which after receiving a false value (0 if integerValue: true is configured) causes homebridget-mqttthing to response to Homekit get requests with an error. This seems to work as expected in my testing, but let me know how you get on. It's in version 1.0.18.

Homekit only notices that a device has stopped responding when switching to or opening the Home App.

deon-wentzel commented 6 years ago

Hi, I have tried the getOnline option with a Sonoff Basic with Tasmota software, with no success, if I add the following lines in topics , "getOnline": "tele/basiclight/LWT". It takes the device offline straight away with a "No Response" on the Home APP, BTW I have tried on type = lightbulb and switch and fan. Am I missing something or is my syntax incorrect?

tobekas commented 6 years ago

@deon-wentzel: If the payload in "tele/basiclight/LWT" is "online"/"offline" (default in Tasmota sowtware), you have to specify this in the onValue and offValue configuration. Otherwise, Mqttthing might interpret this string as "false", which leads to "not responding".

By the way... @arachnetech: Is it possible to specify a different "Boolean Value Settings" (onValue/offValue) for several boolean topics?

arachnetech commented 6 years ago

It’s not currently possible to use different values for different Boolean topics of the same accessory.

tobekas commented 6 years ago

It would be helpful to make onlineValue and offlineValue configurable since the LWT payload can be different from other boolean characteristics. Tasmota (one of the most popular mqtt software) use „Online“ / „Offline“ as payload. I did not found a way to chance this.

MoeweX commented 6 years ago

Hey @arachnetech , I think the original issue is now resolved thanks to your commit 7f863e32b90dcc33dc9b60ce132f90f7a99b8fee, thank you a lot! From my perspective, the request from @tobekas is more related to another question/issue: should it be possible to use different "boolean" values other than true/false and 1/0. Thus, I think a new issue should be opened for that so that this one can be closed.

arachnetech commented 5 years ago

Closing this thread as getOnline implemented.

nihebe commented 2 years ago

Sorry to resuscitate this old issue, but I think my problem fits here very well:

I'm using mqttthing to receive messages from an ESP8266 with a temp sensor, sent by ESPeasy. I configured ESPeasy to send an LWT to a topic, it is configured like so: ESP comes online: /esp/status/lwt = true ESP disappears (LWT triggered by mosquitto): /esp/status/lwt = false I observed this behavior with MQTTexplorer and verified it's working correctly.

In homebridge I configured the mqttthing field "Get online" to "/esp/status/lwt". However, no matter if the topic is true or false, it never says "unavailable", even though I killed Home.app and opened it to force the GET-Request from HomeKit.

I am quite unsure, if this is a bug in homebridge-mqttthing v1.1.41 or a wrong interpretation from my side... the documentation at the respective section is a bit vague to me.

Any hint is appreciated! :)