Extract temperature/humidity via Tasmota flashed Sonoff zigbee bridge

Discussion in 'C-Bus Automation Controllers' started by philthedill, Mar 16, 2021.

  1. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    Hi there, I've bought a number of Sonoff (eWeLink) temperature/humidity sensors and have them connected to my SHAC via a Tasmota flashed zigbee bridge and MQTT broker running on Pi3. Everything looks fine but I cannot bridge the last piece and get the temperature/humidity reading together with sensor ID across to a user variable.
    I have this working so far....

    mqtt = require("mosquitto")
    client = mqtt.new()

    client.ON_CONNECT = function()
    client:subscribe("tele/Tasmota_ZBB-1/SENSOR")
    local mid = client:subscribe("tele/Tasmota_ZBB-1/SENSOR", 2)
    end

    client.ON_MESSAGE = function(mid, topic, payload)

    Sensor_message = "return "..payload:gsub('("[^"]-"):','[%1]=')
    output=loadstring(Sensor_message)()
    log(output) --- see below

    end

    broker = "192.168.86.31" -- MQTT broker address - Raspberry Pi
    client:connect(broker)
    client:loop_forever()
    "
    this is what the log is giving me
    Tasmota ZB bridge from MQTT 16.03.2021 13:53:39
    * table:
    [ZbReceived]
    * table:
    [0xF53A]
    * table:
    [LinkQuality]
    * number: 84
    [Device]
    * string: 0xF53A
    [Humidity]
    * number: 61.04
    [Name]
    * string: temp_sensor_1
    [Endpoint]
    * number: 1"
    any clues appreciated..... with thanks
     
    Last edited: Mar 16, 2021
    philthedill, Mar 16, 2021
    #1
  2. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    What’s the raw message from payload var?
    As above location of humidity value would be
    humidity = output.Humidity
    I can’t see the temp value in the above output
     
    Pie Boy, Mar 16, 2021
    #2
  3. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    this is what I can see in the Tasmota console view... will this help

    temperature example:
    16:43:44.184 MQT: tele/Tasmota_ZBB-1/SENSOR = {"ZbReceived":{"0xCB69":{"Device":"0xCB69","Temperature":25.46,"Endpoint":1,"LinkQuality":0}}}

    humidity example:
    16:40:22.355 MQT: tele/Tasmota_ZBB-1/SENSOR = {"ZbReceived":{"0xCB69":{"Device":"0xCB69","Humidity":53.93,"Endpoint":1,"LinkQuality":0}}}


    the devices send either temperature or humidity depending when the variables change by a certain amount - eg 0.1 deg C. I'd like to be able to capture both temp and humidity and update CBus user variables accordingly....
     
    philthedill, Mar 16, 2021
    #3
  4. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    That is possible, are you receiving the MQTT messages on the shac side?

    If you change this bit,
    client.ON_MESSAGE = function(mid, topic, payload)
    log(payload)
    end

    what dose the shac log show?
     
    Pie Boy, Mar 16, 2021
    #4
  5. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    Tasmota ZB bridge from MQTT 16.03.2021 18:15:24
    * string: {"ZbReceived":{"0x9021":{"Device":"0x9021","Humidity":55.21,"Endpoint":1,"LinkQuality":55}}}
     
    philthedill, Mar 16, 2021
    #5
  6. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    Ok, cool try the below

    client.ON_MESSAGE = function(mid, topic, payload)
    require(’json’)

    payload = json.pdecode(payload)
    log(payload)

    if topic = ‘tele/Tasmota_ZBB-1/SENSOR’ then

    if payload[1].Humidity then
    log(payload[1].Humidity)
    —SetUserParam(1,payload[1].Humidity)
    end

    if payload[1].Temperature then
    log(payload[1].Temperature)
    —SetUserParam(2, payload[1].Temperature)
    end

    end

    end
     
    Pie Boy, Mar 16, 2021
    #6
  7. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    that's looking good thank you but I also need to differentiate the sensor name (I have 8 of them). any ideas?
     
    philthedill, Mar 16, 2021
    #7
  8. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    You could differentiate by MQTT topic or by the value Device in the payload I expect that value would be individual to each sensor.

    if payload[1].Device == “0x9021” then

    if payload[1].Humidity then
    log(payload[1].Humidity)
    —SetUserParam(1,payload[1].Humidity)
    end

    if payload[1].Temperature then
    log(payload[1].Temperature)
    —SetUserParam(2, payload[1].Temperature)
    end


    end
     
    Pie Boy, Mar 16, 2021
    #8
  9. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    correct "Device" is unique by sensor
    However, I am having trouble getting it to work....
    what is the "1" referring to in the line <if payload[1].Device == “0x9021” then>?
     
    philthedill, Mar 17, 2021
    #9
  10. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    looks like the index [1] is not working in the lua table because table is indexed by key, try like this, where device value goes as string inside the square brackets

    if payload.ZbReceived['0x9021'] then

    if payload.ZbReceived['0x9021'].Humidity then
    log(payload.ZbReceived['0x9021'].Humidity)
    --SetUserParam(1,payload.ZbReceived['0x9021'].Humidity)
    end

    if payload.ZbReceived['0x9021'].Temperature then
    log(payload.ZbReceived['0x9021'].Temperature)
    --SetUserParam(2, payload.ZbReceived['0x9021'].Temperature)
    end


    end
     
    Pie Boy, Mar 17, 2021
    #10
  11. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    good progress here - thank you. I have the relevant device being recognised but am unable to write it to user parameter. i think I have copied your framework correct but here is a sample and the resultant error message

    elseif
    payload.ZbReceived["0xA315"] then
    log("Device = 0xA315")
    if payload.ZbReceived["0xA315"].Temperature then
    SetUserParam(32, payload.ZbReceived["0xA315"].Temperature)
    elseif payload.ZbReceived["0xA315"].Humidity then
    SetUserParam(42, payload.ZbReceived["0xA315"].Humidity)
    end

    Tasmota ZB bridge from MQTT 18.03.2021 10:54:18
    Library cbuslogic:0: Group number must be integral
    stack traceback:
    [C]: in function 'error'
    Library cbuslogic: in function 'CBusLookupTags'
    Library cbuslogic: in function 'SetUserParam'
    Resident script:47: in function <Resident script:16>
    [C]: in function 'loop_forever'

    ... nearly there!
     
    philthedill, Mar 18, 2021
    #11
  12. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    It appears I had the network number missing from the "SetUserParam" instruction. Appears to be working fine and thanks again to Pie Boy....
     
    philthedill, Mar 18, 2021
    #12
  13. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    this has been working fine since March but recently I had to re-discover my Sonoff/zigbee TH sender devices. The problem being that the ZB hub then allocated new "short addresses" to the senders and I had to do a lot of editing to get things working again. I have discovered that you can allocate a "friendly name" in Tasmota that is non-volatile. My challenge now is to extract the temperature/humidity data from the new format. Hence this posting...

    This is an example of what is being sent via my MQTT broker.....

    < 17:06:06.088 MQT: tele/Tasmota_ZBB-1/SENSOR = {"ZbReceived":{"0xFAD4":{"Device":"0xFAD4","Name":" TH_sensor_7","Temperature":22.55,"Endpoint":1,"LinkQuality":16}}} > My "old" script made use of the blue section to identify the sending device.. but I now want to use the "non-volatile" red coloured section. I think I need to bypass the blue section somehow using something like a wildcard but am struggling.

    Any help is appreciated.... with thanks
     
    philthedill, Aug 22, 2021
    #13
  14. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    This code syntax not complete but the bit you are looking for is

    if payload[1].Name == “TH_sensor_7” then ….. etc

    client.ON_MESSAGE = function(mid, topic, payload)
    require(’json’)

    payload = json.pdecode(payload)
    log(payload)

    if topic = ‘tele/Tasmota_ZBB-1/SENSOR’ then

    if payload[1].Name == “TH_sensor_7” then

    if payload[1].Humidity then
    log(payload[1].Humidity)
    —SetUserParam(1,payload[1].Humidity)
    end

    if payload[1].Temperature then
    log(payload[1].Temperature)
    —SetUserParam(2, payload[1].Temperature)
    end

    end
    end
    end
     
    Pie Boy, Aug 22, 2021
    #14
  15. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    thanks for the suggestion but I am getting this error
    <
    Tasmota ZB bridge from MQTT new 23.08.2021 11:27:33
    Resident script:33: attempt to index a nil value
    stack traceback:
    Resident script:33: in function <Resident script:15>
    [C]: in function 'loop_forever' >

    this is the code that is causing the error message
    <
    if
    payload[1].Name == "TH_sensor_0" then
    log("device = TH_sensor_0")
    >
    any ideas? I note we are no longer referencing <ZBReceived> in the code

     
    philthedill, Aug 23, 2021
    #15
  16. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    Ahh i see the problem now, it is because the data "Name" sits inside the table which is indexed by "0xFAD4", which cant be indexed by payload.ZbReceived[1] as it is indexed by string "0xFAD4" so table key is string.

    so if you don't want to use the device id and only name, you could try converting the data to string then extract the nit you need like the below, its not as elegant as using the decoded json

    test the following

    payload = [[{"ZbReceived":{"0xFAD4":{"Device":"0xFAD4","Name":" TH_sensor_7","Temperature":22.55,"Endpoint":1,"LinkQuality":16}}}]]

    str = string.format(payload)

    local name = string.match(dat, '"Name":" (.*)","' )
    local temp = string.match(str, '"Temperature":(.*),"E' )

    log(name, temp)

    this should end up with the variable name containing the data, problem with this way is if the data changes in the table it could fail/ read a nill value

    the json way would be better, is there any way on the tasmota side to make the message sent from the tasmota start with the friendly name as opposed to the "0xFAD4" Id.
    then you could use the key payload.ZbReceived.Name to find all the data
     
    Pie Boy, Aug 23, 2021
    #16
  17. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    you are a genius .... the option exists in Tasmota to use the friendly name at the start of the message - here is an example
    <
    14:13:11.287 MQT: tele/Tasmota_ZBB-1/SENSOR = {"ZbReceived":{" TH_sensor_0":{"Device":"0xE365","Name":" TH_sensor_0","Temperature":22.13,"Endpoint":1,"LinkQuality":16}}} >
     
    philthedill, Aug 23, 2021
    #17
  18. philthedill

    Pie Boy

    Joined:
    Nov 21, 2012
    Messages:
    248
    Likes Received:
    31
    Location:
    New Zealand
    Ok, nice one, try the below

    if payload.ZbReceived[" TH_sensor_0"] then -- checking we are reading the correct sensor

    log(payload.ZbReceived[" TH_sensor_0"].Temperature)
    -- setuserparam here etc eg
    SetUserParam('Local', 'temp', payload.ZbReceived[" TH_sensor_0"].Temperature)

    end

    if payload.ZbReceived[" TH_sensor_1"] then -- checking we are reading the correct sensor

    log(payload.ZbReceived[" TH_sensor_1"].Temperature)
    -- setuserparam here etc eg
    SetUserParam('Local', 'temp', payload.ZbReceived[" TH_sensor_0"].Temperature)
    end

    etc etc
     
    Pie Boy, Aug 24, 2021
    #18
  19. philthedill

    philthedill

    Joined:
    Mar 21, 2010
    Messages:
    140
    Likes Received:
    3
    Location:
    Melbourne
    spot on - that's what its doing and working well ---- thank you
     
    philthedill, Aug 24, 2021
    #19
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.