I've written a driver that successfully gets values from my MQTT server (Mosquitto), but after a day or two loses connection. I know the server is still running because another device is publishing messages that NodeRED is subscribed to, and it is processing the data and publishing messages correctly. I foolishly log the mqqtClientStatus conditionally to debug, so I haven't actually seen the disconnect reason yet. Next on the list...
My question is, is the MQTT client supposed to be handling reconnects? Or am I supposed to write code in mqttClientStatus(String message) that watches for disconnects and attempts to reconnect?
I used to have issues with mqtt, not had a problem for some time now though.
My main issue was with the version of moquitto I had .. it used to leak memory and freeze for several seconds while writing its DB, but a version upgrade got rid of that ..
The version Ive been running for a few months now is 1.6.4
It is most easily apparent if you have log messages in the code and they appear multiple times or interleaved. My main issue was in my app but I saw it in the driver too. Initially I created the problem by calling initialize in the app again after a reconnect in the driver that still had some runin methods scheduled. I needed to run initialize again to recreate the MQTT subscriptions.
OK, probably very stupid question, but I've wasted too much time on something probably very, very simple.
I've read that I should save state in the state map. However when the MQTT library calls back in def mqttClientStatus(String message), there is no state or atomicState variable, and as expected if I set any values on those variables, they do not make it out of that function. I added logging to def refresh(), so I can see if the value made it out, and they do not. They are still the values I had set in configure().
If I am going to manage reconnections, I need to keep state like connected and retryCount, am I trying to access the state variable incorrectly? Should I be doing this another way?
Assuming the state variable is defined somewhere earlier within the same driver (or app) and assigned a value before it is again referenced, and not reinitialized again for example in configure() .
def state.myVar = "fred"
later in code
state.myVar="john"
log.info "State myVar is $state.myVar"
log.info "State myVar is " + state.myVar
outputs to the log
State myVar is john
State myVar is john
Do check configure() is not running more often than you expect... maybe in initialize() is a better place.
state variables and their current values show in the device's Hubitat webpage too. You will have to refresh [F5] on that page to see changes
You can see that the state logs as expected at the end of configure, but at the start of mqttClientStatus(String)retryCount is missing. The values I add do log at the end of mqqtClientStatus(String), but when I click refresh to trigger logging of state, connected is back to false, retryCount reappears, and the added lastMQTTStatus is gone.
Edit: I changed the MQTT server IP address, not really using localhost
The method already has a log of state at the end, and the output has what I would expect. It is after the method completes and I trigger refresh that the values no longer print. If there was an exception inside mqttClientStatus(String), I would not expect the logging at the start and end of that function to be in the log.
I was previously logging the individual values, but found that logging the entire state map was easier. Same result though. That mqttClientStatus(String) starts out missing the retryCount value makes me think this is a different context of state.
With the timestamps removed, might be easier to see what comes and goes from the state map:
[debug] refresh: state is [connected:false, retryCount:0]
[debug] Configured
[debug] mqttClientStatus: finish state: [connected:true, lastMQTTStatus:Status: Connection succeeded]
[debug] mqttClientStatus: start state: [connected:false]
[debug] Connecting...
[debug] configure: state is [connected:false, retryCount:0]
Does the finish state have state.connected within .. and is it correct ?
I wonder from the dev page ... "Just remember that all modifications done to state within a SmartApp or Device Handler are only written to external storage after the execution completes".
I use state.connected outside of that method and it is correct.. It updates correctly on the device page too. I assume you set state.connected = false prior to that method ?