What triggered the event my app just received?

Is there any way I can tell which app (or a click on the devices page) triggered an event received by my app from a device ? Or even just determine if the event is in response to a command my app originated to the device ?

I'm running into a difficulty with loops in MQTT for external devices where rapid updates on there can cause me to send commands back to the device creating such a loop. As I consider multiple MQTT broker support through multiple child drivers this becomes even more critical.

This is only an issue for me with virtual devices

I had the same problem with in-bound received messages. I ended up flagging the msg in the driver to distinguish between the inbound vs outbound so that when the targeted device raised a new event triggered by the incoming message, the resulting outbound message didn't get sent out.

I think I understand what you're saying but the device drivers are not mine they are the HE provided (closed source) ones... or am i missing the point ?

You aren't communicating directly from MQTT to those build-in devices are you? I imagine that you have a custom MQTT driver that translates to an HE subscribe event or similar.

Your custom code should be in full control of any inbound and outbound MQTT message processing AND how those msgs get translated to a native HE events. If this is the case then you can determine whether an outbound event was raised as a result of an inbound and shut it down to prevent the loop.

I take an incoming MQTT message in my child MQTT device driver and into the parent app and decide if I have to update the state of an inbuilt (already subscribed to everything) virtual device because it's changed. If needed I do and from that I get an event back from that device driver. But I'm not absolutely certain I (my app) caused that event it could have been something else. Now I obviously expect that event back but it could be one of several events I expect back across devices and attributes. I'm trying to avoid building a lookup of all of these and checking them off. I have tried using atomicState but it is not fast (dependable) enough to keep up with multiple simultaneous updates from MQTT - say a json payload... of course I can add delays but I really don't like that at all.

That is only partially true - my app is in full control of the inbound and outbound messages and can drop/block outgoing messages if required but I'm not absolutely in control of HE events - state changes can originate from anywhere and be very fast e.g. if a RM rule turns something off as soon as it turns on. This timing interspersed with the remote devices update turnaround for a cmd on MQTT can cause sequencing of state to get very interleaved and effectively be out of step creating a loop.

Your original post suggested that you were concerned with identifying device events triggered by an inbound message from your app. If that's the case, why are you referring to HE triggered state or RM change events?

If the atomicState isn't fast enough to track then I'm not sure what else to suggest.

So, for example, a motion sensor detects movement. A RM rule is triggered and sends a command to a switch to turn on. That creates an on event from that switch. You want to know that it was the RM motion rule that caused that switch to turn on? Am I understanding you correctly?

Exactly ..

... but I think my issue is created more by timing when the MQTT updates are being reported more slowly than state updates are being made on MQTT . Or vica versa..

HE posting successive 'cmd's to the device before a previous status is confirmed back and updated in HE. Perhaps an RM rule that turns a device off and back on again in say 500ms when the device hasn't even reported 'off' back so when it later (belatedly) reports 'on' it loops.

Maybe the RM rule creator just has to be wary of the response times of the device...

I am not sure that my original source identification for the event will assist me with this. (although it would be very useful to know it's an event in response to a command originated from my app rather than me having some stored data knowing what I'm expecting back )

For example I receive one status update from MQTT that is json encoded telling me the onoff, level and color current values so I have to know that I expect three events back - actually probably four as the device might return switch and switchedDim. But maybe color didnt change so no event. But RM updates the color at roughly the same time... Just awkward.

1 Like

It sounds more like a driver problem. And you can run into the exact same problem if you issue commands too quickly to slow devices from any app in Hubitat.

Let's say you have two toggle commands that are 500ms apart but you have a default fade time of 2 seconds built into the bulb. The bulb is off when you issue the first toggle command so the light is turned on but the second toggle command will be issued to the device before the state of the device is changed to ON because it takes 2 seconds for the light to reach it's final state of on. So, starting with the light off, two toggle commands 500ms apart would most likely end up with the light being in the on state, not off like you intended.

What you are describing isn't something I would expect your MQTT app to be able to solve. The problem is in the architecture of whatever is issuing the commands being incompatible with the setup of the device. MQTT is just the messenger...if the message is bad/wrong, it isn't it's job to sort it out.

But MQTT is just issuing the events to "whoever" has subscribed to those messages. I wouldn't think it would need to sort out why the event was created. It happened, so whoever subscribes to those device updates would need to know about the change, regardless of where they came from. Or am I still not understanding you?

(And yes, I am anthropomorphizing apps because it's easier to talk about as people. No, i don't think apps are people. :stuck_out_tongue: )

Yes - I mostly agree - and toggle is always problematic with timings.

The issue it can cause is a loop on MQTT and that kills performance. Maybe I'm better advised to try and detect and then block such loops that happen more than xx times..

I'm not seeing where a loop would occur. If there's a device event, there would have to be an MQTT message for said event, right?

The only way I could see a loop happening is if the driver is forcing a new event even when there isn't a state change by using "isStateChange: true". But that would be the fault of the driver.

My MQTT driver doesn't (now) issue events - it calls the parent methods. The parent then issues the appropriate commands to the device. This was done to cut down on the copious number of events the previous MQTT driver made that clogged the logging and caused backup issues and delays during the overnight maintenance.

Okay, maybe I'm not following. I thought your app subscribes to devices and when a device creates an event, an MQTT message is generated. Is that not how it works?

Yes the MQTT event happens because Rule Machine changes the state of the 'virtual' device and so I have then to send a cmd to the device over MQTT.

You're sending a command to a Hubitat device over MQTT because a RM rule fired and changed the state of that device? Now you've really lost me.

This is to import a 'remote device' from MQTT into HE - so in HE it's a virtual device. I subscribe to it's state change topic and update the HE virtual device accordingly. I only send a 'cmd' back to MQTT to control the device if something (not my app) updates the virtual device.

The actual physical device is external to HE - only connected and controllable via MQTT

It's not a real device on HE - it's simply a virtual device representing a remote MQTT connected device. So I have to send the cmd to MQTT to control it

Oh...so, how is whatever issued the command to Hubitat (through MQTT) confirming that the state changed if a corresponding MQTT message is not received confirming that the device did, indeed, chagne state?

See, I would have expected that your APP would issue an MQTT message whenever the state changed, regardless of where it originated. But I can see why you would want to avoid that if your could to cut down on the number of messages.

But it seems more logical to me that whatever is subscribing to the device updates through MQTT should sort out whether it needs to do anything with the messages it is receiving.

This is the same logic that goes into the command/event system. An app issues a command and then knows that it was executed because the event is issued. It's up to the app to figure out if it needs to do anything with the event. I would think the same would hold true with MQTT. Your app is just issuing messages when an event occurs, it's up to whoever is subscribing to those messages to sort it out.

But with devices external to Hubitat so, whereever the actual "event" started, triggering the update to the virtual, device created by your app, is probably not subscribed to MQTT messages from Hubitat, so, there is no cross-checking. So, the outbound message is useless. It still doesn't mean I wouldn't expect it to happen.

Maybe make the distinction that "blatant". Never send MQTT messages for virtual devices created by the MQTT app unless the user specifically enables it.
(It took me a minute for my train to pull into your station....but it got there eventually, isn't that what's important? :wink: )

Nothing issues a command via MQTT to Hubitat for this device - instead a command is issued to the remote device directly which is monitoring a designated cmd' device topic. This device is essentially independent of HE. It then reports a state update on its status topic (which I use to update the virtual devices status in HE)

It's a fundamental feature of my MQTT app that you can import such 'ad hoc' MQTT devices and get status updates and control them from HE.

That's not the objective . what I have to avoid is when the device reports 'off' in its status topic I mustn't send an 'off' command or it will send an 'off' status again and it will loop. This could be stopped at either end (me not sending an off command if its already off) or it not sending an off status if it has already reported it is off. I think the onous is one my end though.