homebridge-mqttthing icon indicating copy to clipboard operation
homebridge-mqttthing copied to clipboard

Mqttthing garageDoorOpener trying to get working with one reed switch

Open hemant5400z opened this issue 5 years ago • 21 comments

Hi All,

I have a ESP8266 hooked to a relay with a reed switch. I have seen examples with 2 reed switches but they don't work for me while it should be simple for what i'm trying to achieve.

I now have 1 rules with OPENED and Closed topic in TASMOTA. The relay itself is a TOGGLE.

What I want to achieve get the status based on the reed and the OPEN/Close based on the toggle. With a remark that i want to be able to get the updates when controlling with the door push button or remotecontrol.

I have: setTargetDoorState": "cmnd/garage/POWER1", "getTargetDoorState": "stat/garage/door", "getCurrentDoorState": "stat/garage/door"

When I reboot I can see in the terminal log of homebridge doorstatus Cur =1, after reboot when the door is open however the homekit button keeps spinning forever.

Any ideas how to fix this?

For open/close I use TOGGLE which is working, seems i'm missing a piece not sure what. Because the door status gets updated when i use the door push button.

Cheers, Hemant

hemant5400z avatar Mar 28 '20 14:03 hemant5400z

Can you try enabling retain messages in your mqtt accessory? Normally after rebooting homebridge, this behavior is typical, because the accessory does not update its state again and the last states are not persisted. If the current state was sent with the retained flag, mqttthing gets the last states from the MQTT-Broker right after reconnection.

tobekas avatar Apr 05 '20 14:04 tobekas

I like that idea!

arachnetech avatar Apr 05 '20 15:04 arachnetech

Hi tobekas,

That wont work as the reed is used to determine the status of the door. The cmnd power1 is just a pulse command send to the relay so powerretain1 will not affect.

I do publish door status with backlog so reed switch shows correct status however door shows opening while it reads same publish as the reed switch not sure what it is expecting as currenstatus and get status are published as closed or opened as final stage. I can see that in HB log door status closed; but door controller opening

Cheers, Hemant

Verstuurd vanaf mijn iPhone

Op 5 apr. 2020 om 16:58 heeft tobekas [email protected] het volgende geschreven:



Can you try enabling retain messages in your mqtt accessory? Normally after rebooting homebridge, this behavior is typical, because the accessory does not update its state again and the last states are not persisted. If the current state was sent with the retained flag, mqttthing gets the last states from the MQTT-Broker right after reconnection.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHubhttps://github.com/arachnetech/homebridge-mqttthing/issues/225#issuecomment-609429673, or unsubscribehttps://github.com/notifications/unsubscribe-auth/AEA6CKW4KB5K7L4EC2GVVFTRLCMCJANCNFSM4LVTBNSA.

hemant5400z avatar Apr 06 '20 19:04 hemant5400z

I've just added an alternative way to expose garage door opening/closing state. Instead of publishing to the getCurrentDoorState topic, you can now publish to getDoorMoving - publishing true if the door is moving or false if it has reached its final state (with the usual options for Boolean values). Mqttthing will work out the corresponding opening/closing/open/closed state in relation to the target state. This might make what you're doing easier.

If you have a reed switch detecting when the door is fully-closed, and another detecting when the door is fully-opened, you could set them both to publish true to the getDoorMoving topic when the door starts to move away from them, and false when the door comes to rest at the other position.

As an even simpler option it's possible to configure a getDoorMoving topic but never publish it. Homekit will then just toggle the garage door between open and closed.

arachnetech avatar Apr 13 '20 23:04 arachnetech

Sounds promising. For those of us with one reed sensor only and no ability to alter the topics published (default device firmware), I wonder if a timer could be implemented, internally setting getDoorMoving to true after a HomeKit move command for some configurable door-move-time (12 seconds for me), after which time the sensor value would dictate the current state. This method of checking the sensor value is effective when an obstruction prevents or stops the movement.

Then, for any external control (like your physical button in the garage), the reed sensor could be used to directly update targetDoorState directly (no "door moving"), similar to your "configure but never publish" idea. Thanks for MQTTThing.

jdtsmith avatar Apr 16 '20 15:04 jdtsmith

OK, I played with it and I have a very workable solution for a single reed switch system, which is actuated and reported over MQTT in my case only at the fully closed position.

    {
      "accessory": "mqttthing",
      "type": "garageDoorOpener",
      "name": "ShellyGarage",
      "topics": {
	"setTargetDoorState": {
	  "topic": "shellies/shelly-garage/relay/0/command",
	  "apply": "this._isMoving=message; setTimeout(()=>{this._isMoving=false},10e3); return 'on';"
	},
	"getTargetDoorState": {
	  "topic": "shellies/shelly-garage/input/0",
	  "apply": "if (this._isMoving) {return this._isMoving} else {return message==1?'C':'O'}"
	},	  
	"getCurrentDoorState": {
	  "topic": "shellies/shelly-garage/input/0",
	  "apply": "closed=message==1; if(closed) return 'C'; if (this._isMoving) return this._isMoving.toLowerCase(); return closed?'C':'O';"
	}
      }
    }

I don't actually use the new getDoorMoving, since I want to treat sensor input changes closing and opening differently. Why? When the input switches to closed (==1 for my device's reporting), that is definitive: the move is over and the door is closed. When the sensor is found to be open, the door could be opening, closing, or stopped at any position besides fully closed. So far so good. Notice that I reuse the same topic for both target and current. Both run (target first).

Here's the wrinkle, my device (a Shelly 1) reports on the input sensor value every 30 seconds on the clock. That report could come at any time relative to the garage's motion, so I have to guard against reporting the door open in the middle of the move. That's why I use a saved "protection" variable this._isMoving, and a timeout to reset it after a safe move time.

If the garage door is controlled externally, there is no opening or closing; it just flips quickly from opened to closed and visa versa when it sees the sensor input change. When you command it from Homekit/Siri, close works well: it says "Closing..." in the Home app until such time as the sensor closes. For Homekit-initiated openings, or failed moves in either direction, you have to wait for the timeout (10s in this example) plus however much time until the next periodic device update to find out it opened (or failed).

It would be somewhat preferable if I could have arranged MQTTThing to cache and then report on any sensor value that came during the timeout delay after a specifiable delay, rather than waiting for a new update, but still it's pretty good.

If you have 2 sensors (top and bottom), it should be possible to do much better: just set a variable when one or the other opens and it's trivial to work out if you are opening/closing/opened/closed/stopped (after a delay) in between. Maybe some variable namespace guidance would be in order for people who want to use this technique.

jdtsmith avatar Apr 17 '20 21:04 jdtsmith

Wow, I can’t believe you’ve managed to customise the behaviour to that degree using apply functions! Most impressive!

I’ve been thinking for a while that apply functions, while adding a huge amount of flexibility, are actually pretty inconvenient to use beyond the simplest of manipulations. (They’re also incompatible with GUI-based configuration, which rules them out for some users.) One option that I’ve been considering for a while is an alternative ‘apply function’ mechanism where you can write the custom logic for encoding and decoding messages in a separate JavaScript source file in your configuration.

Is this a feature that you would have found useful in implementing this?

arachnetech avatar Apr 18 '20 08:04 arachnetech

One option that I’ve been considering for a while is an alternative ‘apply function’ mechanism where you can write the custom logic for encoding and decoding messages in a separate JavaScript source file in your configuration.

Is this a feature that you would have found useful in implementing this?

I did consider whether a more flexible "mini-plugin" JS interface to MQTTThing would have made this easier. One issue is that I needed some richer communication between the topic callbacks. For example, to make this more robust, you'd accept an update via the getCurrentDoorState topic, but hold off on applying it via Homebridge until a timeout elapses. I.e. after time out, apply whatever value you happened to have most recently received.

I didn't ponder it too long, but it wasn't immediately obvious that a simple approach could be found that would be generic enough for all potential such "elaborations" on the core MQTTThing logic, but light-weight enough to make it superior to just "write your own plugin". I considered that but find this plugin quite stable, and have been trying to simplify by moving more and more devices under it.

In terms of usability for non-experts, referencing and dropping a JS file or two in the right place vs. copy/pasting some arcane apply's seems about the same to me; maybe the latter is actually slightly easier. I suppose if your apply gets quite long and convoluted, it might be convenient to be able to refer to it as an external file implementing some simple API you set, but then you have to deal with tracking that file and making sure it's in the right place, and remembering that you did so. The advantages of a self-contained config file are pretty compelling.

One simple thing you could do right away is to pass another variable to your apply functions, an empty object state={}, one per accessory. The apply's could then communicate with each other, do timing based updates as I've done, etc., without polluting the main object's name-space. I suppose you could consider sharing a master state variable among all the accessories, which would allow for some very rich logic. But my instinct is this would be too much for a string-apply setup. And it competes with Homekit automations (limited as they are).

For me, this works about as well as the Raspberry PI GPIO-based plugin I had formerly used (and with hopefully much less maintenance/OS upgrades/separate Homebridge instance that goes down occasionally/etc.). For closes, it's actually better, since the closed sensor is definitive and state updates as soon as that hits. For opens, it's worse, since it will take up to timeout + 30seconds to report the garage door is open (as opposed to just timeout with the GPIO-based plugin). If I was writing my own device firmware or customizing Tasmota or some-such, I could mostly fix this just by increasing the reporting rate after the relay is operated.

Thanks for this great plugin.

jdtsmith avatar Apr 18 '20 16:04 jdtsmith

Thanks, @jdtsmith. I've been playing with this 'codec' idea this afternoon. (I certainly won't get rid of apply(), but personally I find it a pain to write anything but the simplest JavaScript in an 'apply' string.) If it works, I'll add it as another option.

I like the idea of your state object for apply functions too.

David

arachnetech avatar Apr 18 '20 17:04 arachnetech

Be happy to test a branch if you get to that point.

jdtsmith avatar Apr 19 '20 01:04 jdtsmith

Thanks, @jdtsmith - I'd be interested in your views on what I've done. I've not published a new release yet, but master now includes:

  • Added support for codecs
  • Added state to apply functions

I've not really documented codecs yet (see https://github.com/arachnetech/homebridge-mqttthing#codecs), but I think they're fairly self-explanatory if you look at the example (https://github.com/arachnetech/homebridge-mqttthing/blob/master/test/test-codec.js).

arachnetech avatar Apr 19 '20 13:04 arachnetech

  • Added support for codecs
  • Added state to apply functions

Looks interesting. Haven't yet played with it, but a couple thoughts occurred to me (sorry this got a bit long as ideas popped up while responding).

It would be convenient if you only needed to specify a "codec directory", and MQTTThing loads up all the right codecs for you. One way to do this is to make MQTTThing a platform, and specify that codec directory in platform config. A given accessory config can just specify the base name of the relevant codec (e.g. shelly1-garage), and codec_dir/shelly1.js gets loaded and used for translation. Or perhaps an even better approach: support loading any file on the JS load-path (perhaps with an mqttthing prefix). This would permit codec/plugin authors to deploy them via e.g npm and users don't have to bother with paths/etc. I.e. codec: "shelly1-garage" gets translated to a try/catch-wrapped require of mqttthing-shelly1-garage.

Since each codec gets the (full?) config passed in, they can separately specify their own custom config variables. Then people can easily make little codec projects that you can categorize on your main page.

Also, just as for apply, I think passing a shared state object to encode/decode among the various codecs will be useful. Whether that's a single state object for an entire Homebridge instance, or one per accessory is unclear. Given that you can squelch a given MQTT read/publish action by returning undefined from the codec, having all accessory state in one place would make it possible to have some very powerful automation capabilities (among your MQTT-enabled Homekit devices). (OK it starts to sound like HomeAssistant-light...).

Now that I'm envisioning it, I do wonder whether this is the right level of abstraction for a plugin-architecture. For my case above, I'd need 3 separate codec files, for [get/set][Target/Current]DoorState. In that case it would be conceptually cleaner for a "plugin" to configure its own type, the topics it wants to listen to (based on the default + its own custom config inputs, for example), and then implement encoders/decoders for all of them at once. I.e. my example would collapse to:

  {
      "accessory": "mqttthing",
      "name": "ShellyGarage",
      "codec": "shelly1-garage",
      "shelly-name": "shelly-garage",
      "garage-timeout": 10
    }

and MQTTThing would 1) find and load the codec plugin, 2) ask it what type it is, 3) ask the codec/plugin which topics it needs to handle, and their associated MQTT path, 4) subscribe to them, and 5) as they occur, hand the MQTT inputs/outputs over to the codec (along with the topic at hand) for translation, as needed. The codec author could even specify but skip topic handlers for "simple" cases (e.g. boolean, integer, etc.). To me this would be ideal: no need to fork or write a new plugin, let MQTTThing do what it knows best: implement a simple encoding which interfaces with ever-expanding Homekit topics, and do all the grunt work of shuttling MQTT messages around. Would also be a nice way for you to offload help requests too (take it to the plugin author!). Some of these plugins/codecs could be quite simple, and some more complex. But assuming it's an API that's well-documented, stable, and simple for authors to target, it takes you out of the "specific device" business.

jdtsmith avatar Apr 19 '20 16:04 jdtsmith

Thanks. One thing I may not have made clear is that the codec is for the whole accessory - so one codec can store state for the whole accessory as it requires (by creating it within its init() function) and handle any topics it wants to. (I'm going to add support for per-property encode and decode functions before I publish it.)

I'm also planning a different mechanism for configuration which allows the use of pre-created configuration profiles (potentially also using pre-created codecs). The idea is that complex apply function (or codec)-based configurations could be replaced with custom accessory types with simple configurations which get mapped to the real configuration through a configuration profile. These could potentially be built for the more popular configurations in https://github.com/arachnetech/homebridge-mqttthing/wiki/Tested-Configurations.

Switching to a platform-based set-up would probably be too big a change, as it would break existing configurations. Maybe this would work better as a separate add-in. It's certainly an interesting idea...

arachnetech avatar Apr 19 '20 21:04 arachnetech

Sounds cool. If custom/codec config can be generalized enough, they can pull in separate code pretty easily I'd guess, making a switch to platform unnecessary. I'd also consider just one encode/decode method, which is passed the topic it is being asked to work on. I'd bet a small crop of affiliated codec projects emerges once this settles.

jdtsmith avatar Apr 20 '20 01:04 jdtsmith

Hi,

Mine works with this plugin:

{ "accessory": "mqttgaragedoor", "name": "Garagedeur", "url": "mqtt://xxxx:1883", "caption": "Garagedeur", "lwt": "tele/lctech/LWT", "lwtpayload": "Offline", "topics": { "statusSet": "cmnd/lctech/POWER1", "openGet": "stat/lctech/open", "openValue": 1, "closedGet": "stat/lctech/closed", "closedValue": 0, "openStatusCmd": "TOGGLE", "closeStatusCmd": "TOGGLE" }, "doorRunInSeconds": "20" }

And added the rules in tasmota.

I will give yours a try when it gets published, but currently happy with my plugin and shows up correctly when controlled with remote or pushbutton outside Homekite/tasmota.

Cheers, Hemant

hemant5400z avatar Apr 20 '20 08:04 hemant5400z

Just an update: for toggle switches like Garage Doors, Siri/Homekit will sometimes attempt to "close" an already-closed door. Plugins have to explicitly trap and disable this behavior, which MQTTThing does not itself do. So my example above is a security risk. I've updated it to use the new state variable passed to apply functions, and also to trap and disable these. See #250.

jdtsmith avatar Apr 21 '20 17:04 jdtsmith

Hi,

Mine works with this plugin:

{ "accessory": "mqttgaragedoor", "name": "Garagedeur", "url": "mqtt://xxxx:1883", "caption": "Garagedeur", "lwt": "tele/lctech/LWT", "lwtpayload": "Offline", "topics": { "statusSet": "cmnd/lctech/POWER1", "openGet": "stat/lctech/open", "openValue": 1, "closedGet": "stat/lctech/closed", "closedValue": 0, "openStatusCmd": "TOGGLE", "closeStatusCmd": "TOGGLE" }, "doorRunInSeconds": "20" }

And added the rules in tasmota.

Do your tasmota rules include things like if sensor status is closed, don't try to close again? I was attempting to use the stock firmware of my Shelly 1 device, so no ability to put guards in like that.

jdtsmith avatar Apr 21 '20 21:04 jdtsmith

BTW, if you have a Shelly device doing your doors, you can shorten the reporting interval via HTTP: http://192.168.XX.XX/settings?mqtt_update_period=15.

jdtsmith avatar Apr 22 '20 21:04 jdtsmith

@jdtsmith I've been using Shelly 1 in HomeKit through Home Assistant and it's been pretty unreliable, probably because HA's cover component only passes open and close, but not opening and closing. I'm going to jump into your config through HomeBridge. I have 2 sensors at the gate with two Shelly 1's. Both have a magnetic reed at SW to detect fully closed and fully opened. Could you give me a hand on how to modify my config to make use of both sensors? I guess the rationale would be:

  • When sensor 1 is closed and sensor 2 is open, opening sensor 1 sends HomeKit opening until sensor 2 is closed.
  • When sensor 2 is closed and sensor 1 is open, opening sensor 2 sends HomeKit closing until sensor 1 is closed.

Thanks!

uspino2 avatar Apr 28 '20 10:04 uspino2

@jdtsmith I've been using Shelly 1 in HomeKit through Home Assistant and it's been pretty unreliable, probably because HA's cover component only passes open and close, but not opening and closing. I'm going to jump into your config through HomeBridge. I have 2 sensors at the gate with two Shelly 1's. Both have a magnetic reed at SW to detect fully closed and fully opened. Could you give me a hand on how to modify my config to make use of both sensors? I guess the rationale would be:

  • When sensor 1 is closed and sensor 2 is open, opening sensor 1 sends HomeKit opening until sensor 2 is closed.
  • When sensor 2 is closed and sensor 1 is open, opening sensor 2 sends HomeKit closing until wonder 1 is closed.

I'd suspect connectivity problems first, since Opening/Closing is really mostly an interface nicety. When it's not responsive for you, go to the Shelly's web page directly and see if the "tick mark" on the power circle is appropriate for the sensor state (in Detached Switch mode).

I think your logic is fine. You'll have to track the state of both sensors in the state.global that is passed into your apply's. I actually posted in another issue about the logic with this plugin using two sensors. See this post. The only slight tweak to your basic logic I'd suggest is you have to check for a sensor to re-report its state as no-contact, since the first such report initiates the "opening/closing" for external control (physical remote, etc.). When Homekit initiates a move itself, it's the easier case.

BTW, it wasn't clear if your two Shelley's control different operation contacts on the gate to open vs. close it, but if it's more like a garage door (one open/close toggle contact), you should add the logic to "trap and disable" close when already closed, and open when already open (see above).

You probably also want to shorten the mqtt_update_period a bit (see above). But with two sensors it should be pretty solid, as long as they both are reliable.

jdtsmith avatar Apr 28 '20 13:04 jdtsmith

I wanted to thank @arachnetech for your work implementing codecs. This made it a breeze to update my single-reed garage system with a new Gen2 Shelly1 Plus for both HK and button/car remote control. Really very straightforward!

jdtsmith avatar Jun 03 '24 23:06 jdtsmith