openLuup: Tasmota MQTT Bridge
-
@therealdb you are of course correct, I tested and it works both with and without the mqtt:// prefix for the incoming messages.
I changed the "CurrentTemperature" to a value that always will be lower than the setpoints ( in my case 10 degrees), by doing this the "ModeState" stays at "Heating" which means that the changing the temperature from the OpenLuup device works. Quite obvious of course when you think of it.
All in all it works as it should, thanks for the hard work!
@archers great!
I’m thinking of creating a cooler device, because I need it myself. It’s really stupid imho that they created heaters, complex thermostats, but no humidifier, dehumidifier or cooler device. But since we’re not tied to Vera anymore, I guess it’s time to add them, as I did with my own virtual alarm/alarm partition.
-
@akbooer I did some debug on the error messages above and came up with the following. I placed some debug entries in the "L_TasmotaBridge.lua" to try to see what was causing the errors. First the code: under function _G.Tasmota_MQTT_Handler (topic, message)
local myMessage = "" if message == nil then myMessage = "Message is null" else if message == "" then myMessage = "Message is empty" else myMessage = message end end _log ("JSON error info " .. myMessage)
Which produced the following log errors and their context:
2021-04-16 20:48:01.335 openLuup.io.server:: MQTT:1882 connection from 10.17.2.28 tcp{client}: 0x55fac42317b8 2021-04-16 20:48:01.355 luup.tasmota:262: JSON error info Online 2021-04-16 20:48:01.356 luup.tasmota:262: JSON error: ? 2021-04-16 20:48:01.366 luup.tasmota:262: JSON error info Message is empty 2021-04-16 20:48:01.367 luup.tasmota:262: JSON error: ? 2021-04-16 20:48:01.423 openLuup.mqtt:: BedroomTV SUBSCRIBE to cmnd/power_BedroomTV/# tcp{client}: 0x55fac42317b8 2021-04-16 20:48:01.432 openLuup.mqtt:: BedroomTV SUBSCRIBE to cmnd/tasmotas/# tcp{client}: 0x55fac42317b8 2021-04-16 20:48:01.433 openLuup.mqtt:: BedroomTV SUBSCRIBE to cmnd/BedroomTV_fb/# tcp{client}: 0x55fac42317b8
@akbooer I think I found the culprit causing the random connection disconnects to Mosquitto. The LWT payload for a given device is a simple string, which doesn't seem to decode in the json decode call. So I added the below code to send a json string to the decoder. The errors have disappeared and I now see the LWT variable in the service variables. The variable reads "LWT : Online"
--line 165 local valid = {SENSOR = true, STATE = true, RESULT = true, LWT = true}
--line 172 -- begin code local info, err = json.decode (message) if message then if not info then -- json did not decode because of single string parameter message = '{' .. '"' .. mtype .. '"' .. ':' .. '"' .. message .. '"' .. '}' end end -- end code local info, err = json.decode (message)
This is probably not the way you would handle the error, but it does work.
-
@akbooer I think I found the culprit causing the random connection disconnects to Mosquitto. The LWT payload for a given device is a simple string, which doesn't seem to decode in the json decode call. So I added the below code to send a json string to the decoder. The errors have disappeared and I now see the LWT variable in the service variables. The variable reads "LWT : Online"
--line 165 local valid = {SENSOR = true, STATE = true, RESULT = true, LWT = true}
--line 172 -- begin code local info, err = json.decode (message) if message then if not info then -- json did not decode because of single string parameter message = '{' .. '"' .. mtype .. '"' .. ':' .. '"' .. message .. '"' .. '}' end end -- end code local info, err = json.decode (message)
This is probably not the way you would handle the error, but it does work.
Great work!
There may be some compatibility problem betwen JSON decoders – which one are you using (openLuup / Cjson / RapidJson) ? The beginning of the Startup Log should tell you...
2021-06-06 20:08:48.470 openLuup.json:: version RapidJSON (0.6.1) + openLuup (2021.05.01) @akbooer
-
@akbooer I think I found the culprit causing the random connection disconnects to Mosquitto. The LWT payload for a given device is a simple string, which doesn't seem to decode in the json decode call. So I added the below code to send a json string to the decoder. The errors have disappeared and I now see the LWT variable in the service variables. The variable reads "LWT : Online"
--line 165 local valid = {SENSOR = true, STATE = true, RESULT = true, LWT = true}
--line 172 -- begin code local info, err = json.decode (message) if message then if not info then -- json did not decode because of single string parameter message = '{' .. '"' .. mtype .. '"' .. ':' .. '"' .. message .. '"' .. '}' end end -- end code local info, err = json.decode (message)
This is probably not the way you would handle the error, but it does work.
Should now be fixed in development v21.6.8.
My implementation, FYI:
local tasmota, mtype = tasmotas: match "^(.-)/(%u+)" local valid do -- thanks @Buxton for LWT as text message local j, t = "json", "text" valid = {SENSOR = j, STATE = j, RESULT = j, LWT = t} end local decoder = valid[mtype] if not (tasmota and decoder) then _log (table.concat ({"Topic ignored", topic, message}, " : ")) return end local info, err if decoder == "text" then info = {[mtype] = message} else info, err = json.decode (message) if not info then _log ("JSON error: " .. (err or '?')) _log ("Received message ignored: " .. message) return end end
-
Great work!
There may be some compatibility problem betwen JSON decoders – which one are you using (openLuup / Cjson / RapidJson) ? The beginning of the Startup Log should tell you...
2021-06-06 20:08:48.470 openLuup.json:: version RapidJSON (0.6.1) + openLuup (2021.05.01) @akbooer
-
Should now be fixed in development v21.6.8.
My implementation, FYI:
local tasmota, mtype = tasmotas: match "^(.-)/(%u+)" local valid do -- thanks @Buxton for LWT as text message local j, t = "json", "text" valid = {SENSOR = j, STATE = j, RESULT = j, LWT = t} end local decoder = valid[mtype] if not (tasmota and decoder) then _log (table.concat ({"Topic ignored", topic, message}, " : ")) return end local info, err if decoder == "text" then info = {[mtype] = message} else info, err = json.decode (message) if not info then _log ("JSON error: " .. (err or '?')) _log ("Received message ignored: " .. message) return end end
@akbooer Yes, that should work. However, the LWT MQTT specification calls for a standard message, so a tasmota upgrade could change the text message to a json message. Is there a way to test the message for a non-json string, and then filter accordingly. I fear the hardcoded flags will inevitably break....
-
OK, so here's what it will be now, a hybrid of our approaches...
local valid = {SENSOR = 1, STATE = 1, RESULT = 1, LWT = 1} -- thanks @Buxton for LWT as text message if not (tasmota and valid[mtype]) then _log (table.concat ({"Topic ignored", topic, message}, " : ")) return end local info = json.decode (message) or {[mtype] = message} -- treat invalid JSON as plain text
-
OK, so here's what it will be now, a hybrid of our approaches...
local valid = {SENSOR = 1, STATE = 1, RESULT = 1, LWT = 1} -- thanks @Buxton for LWT as text message if not (tasmota and valid[mtype]) then _log (table.concat ({"Topic ignored", topic, message}, " : ")) return end local info = json.decode (message) or {[mtype] = message} -- treat invalid JSON as plain text
-
OK, so here's what it will be now, a hybrid of our approaches...
local valid = {SENSOR = 1, STATE = 1, RESULT = 1, LWT = 1} -- thanks @Buxton for LWT as text message if not (tasmota and valid[mtype]) then _log (table.concat ({"Topic ignored", topic, message}, " : ")) return end local info = json.decode (message) or {[mtype] = message} -- treat invalid JSON as plain text
@akbooer Can I ask you for one more addition. I'd like to be able to set tasmota prefixes and suffixes via lua startup. Something like:
attr ("openLuup.Tasmota.Prefix", "tele", "tasmota/tele","stat") attr ("openLuup.Tasmota.Topic", "SENSOR", "STATE","RESULT", "LWT")
You'd also need to change the upper case error check on the topic as some of the full topic suffixes are not all in upper case:
local tasmota, mtype = tasmotas: match "^(.-)/(.+)"
-
@akbooer Can I ask you for one more addition. I'd like to be able to set tasmota prefixes and suffixes via lua startup. Something like:
attr ("openLuup.Tasmota.Prefix", "tele", "tasmota/tele","stat") attr ("openLuup.Tasmota.Topic", "SENSOR", "STATE","RESULT", "LWT")
You'd also need to change the upper case error check on the topic as some of the full topic suffixes are not all in upper case:
local tasmota, mtype = tasmotas: match "^(.-)/(.+)"
@buxton said in openLuup: Tasmota MQTT Bridge:
I'd like to be able to set tasmota prefixes and suffixes via lua startup.
Try the latest development version (21.6.12b)
A tiny syntax difference from your suggestion, you need to write...
attr ("openLuup.Tasmota.Prefix", {"tele", "tasmota/tele", "stat"}) attr ("openLuup.Tasmota.Topic", {"SENSOR", "STATE", "RESULT", "LWT"})
-
@buxton said in openLuup: Tasmota MQTT Bridge:
I'd like to be able to set tasmota prefixes and suffixes via lua startup.
Try the latest development version (21.6.12b)
A tiny syntax difference from your suggestion, you need to write...
attr ("openLuup.Tasmota.Prefix", {"tele", "tasmota/tele", "stat"}) attr ("openLuup.Tasmota.Topic", {"SENSOR", "STATE", "RESULT", "LWT"})
@akbooer After updating to the lastest development version (21.6.12b), I did a direct copy and paste of the above attr code into startup lua, and it appears that openLuup hangs on the ipairs iteration, because the ipairs statement is seeing a string instead of a table. I was then able to boot openLuup by removing the "or" clause :
--local prefixes = config.Prefix or {"tele", "tasmota/tele"} -- subscribed Tasmota prefixes local prefixes = {"tele", "tasmota/tele"} -- subscribed Tasmota prefixes for _, prefix in ipairs (prefixes) do luup.register_handler ("Tasmota_MQTT_Handler", "mqtt:" .. prefix .. "/#", prefix) -- * * * MQTT wildcard subscription * * * end
The topic table has the same problem.
I was able to see the error message when using "./openLuup_reload" at the linux command prompt.
-
Oh yes, that's the traditional Vera-compliant Luup API for you, which only allows string attributes.
TBH, I don't use that much these days. Sorry about that.Two ways forward:
- This will work right now:
local oL = luup.attr_get "openLuup" oL.Tasmota = { Prefix = {"tele", "tasmota/tele", "stat"}, Topic = {"SENSOR", "STATE", "RESULT", "LWT"}}
- I could change the Tasmota code to accept:
attr ("openLuup.Tasmota.Prefix", "tele, tasmota/tele, stat") attr ("openLuup.Tasmota.Topic", "SENSOR, STATE, RESULT, LWT")
which might be better in the long run.
-
Oh yes, that's the traditional Vera-compliant Luup API for you, which only allows string attributes.
TBH, I don't use that much these days. Sorry about that.Two ways forward:
- This will work right now:
local oL = luup.attr_get "openLuup" oL.Tasmota = { Prefix = {"tele", "tasmota/tele", "stat"}, Topic = {"SENSOR", "STATE", "RESULT", "LWT"}}
- I could change the Tasmota code to accept:
attr ("openLuup.Tasmota.Prefix", "tele, tasmota/tele, stat") attr ("openLuup.Tasmota.Topic", "SENSOR, STATE, RESULT, LWT")
which might be better in the long run.