From 4b74c71f19d7bb9209cd7aeebff7ef253d3f9000 Mon Sep 17 00:00:00 2001 From: UBWH <72185209+UBWH@users.noreply.github.com> Date: Tue, 22 Jul 2025 15:20:02 +0800 Subject: [PATCH] Create D20.be (#23709) --- .../lorawan/decoders/vendors/dragino/D20.be | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 tasmota/berry/lorawan/decoders/vendors/dragino/D20.be diff --git a/tasmota/berry/lorawan/decoders/vendors/dragino/D20.be b/tasmota/berry/lorawan/decoders/vendors/dragino/D20.be new file mode 100644 index 000000000..13de30686 --- /dev/null +++ b/tasmota/berry/lorawan/decoders/vendors/dragino/D20.be @@ -0,0 +1,122 @@ +# LoRaWAN Decoder file for Dragino D20/D22/D23 (1,2,3 temp sensor models) +# +# References +# User Manual: https://wiki.dragino.com/xwiki/bin/view/Main/User%20Manual%20for%20LoRaWAN%20End%20Nodes/D20-LBD22-LBD23-LB_LoRaWAN_Temperature_Sensor_User_Manual/ +# TTN Device Repository: https://github.com/TheThingsNetwork/lorawan-devices/blob/master/vendor/dragino/d2x-lb.js + +import string + +global.DrgD20Nodes = {} + +class LwDecoDrgD20 + static def decodeUplink(Node, RSSI, FPort, Bytes) + var data = {"Device":"Dragino D20"} + data.insert("Node", Node) + + var valid_values = false + var last_seen = 1451602800 + var battery_last_seen = 1451602800 + var battery = 1000 + var rssi = RSSI + var tempC1 = 1000 + var tempC2 = 1000 + var tempC3 = 1000 + + if global.DrgD20Nodes.find(Node) + last_seen = global.DrgD20Nodes.item(Node)[1] + battery_last_seen = global.DrgD20Nodes.item(Node)[2] + battery = global.DrgD20Nodes.item(Node)[3] + rssi = global.DrgD20Nodes.item(Node)[4] + tempC1 = global.DrgD20Nodes.item(Node)[5] + tempC2 = global.DrgD20Nodes.item(Node)[6] + tempC3 = global.DrgD20Nodes.item(Node)[7] + end + + ## SENSOR DATA ## + if 2 == FPort && Bytes.size() == 11 + last_seen = tasmota.rtc('local') + + var mode=(Bytes[6] & 0x7C)>>2 + if 3==mode + battery = (Bytes[0]<<8 | Bytes[1])/1000 + + # 0x07FF = 2047 = no temp sensor + + tempC1 = Bytes[2] << 8 | Bytes[3] + if Bytes[2]>0x7F tempC1-=0x10000 end + tempC1 /= 10.0 + data.insert("TempC1", tempC1) + + tempC2 = Bytes[7] << 8 | Bytes[8] + if Bytes[7]>0x7F tempC2-=0x10000 end + tempC2 /= 10.0 + data.insert("TempC2", tempC2) + + tempC3 = Bytes[9] << 8 | Bytes[10] + if Bytes[9]>0x7F tempC3-=0x10000 end + tempC3 /= 10.0 + data.insert("TempC3", tempC3) + + end + + valid_values = true + + ## STATUS DATA ## + elif 5 == FPort && Bytes.size() == 7 + data.insert("Sensor_Model",Bytes[0]) + data.insert("Firmware_Version", f'v{Bytes[1]:%u}.{Bytes[2]>>4:%u}.{Bytes[2]&0xF:%u}') + data.insert("Freq_Band",LwRegions[Bytes[3]-1]) + data.insert("Sub_Band",Bytes[4]) + data.insert("BattV",((Bytes[5] << 8) | Bytes[6]) / 1000.0) + battery_last_seen = tasmota.rtc('local') + battery = ((Bytes[5] << 8) | Bytes[6]) / 1000.0 + valid_values = true + else + # Ignore other Fports + end #Fport + + if valid_values + if global.DrgD20Nodes.find(Node) + global.DrgD20Nodes.remove(Node) + end + # sensor[0] [1] [2] [3] [4] [5] [6] [7] + global.DrgD20Nodes.insert(Node, [Node, last_seen, battery_last_seen, battery, RSSI, tempC1, tempC2, tempC3]) + end + + return data + end #decodeUplink() + + static def add_web_sensor() + var msg = "" + for sensor: global.DrgD20Nodes + var name = string.format("D20-%i", sensor[0]) + var name_tooltip = "Dragino D20" + var battery = sensor[3] + var battery_last_seen = sensor[2] + var rssi = sensor[4] + var last_seen = sensor[1] + msg += lwdecode.header(name, name_tooltip, battery, battery_last_seen, rssi, last_seen) + + # Sensors + var tempC1 = sensor[5] + msg += "┆" # | + if tempC1 < 1000 + msg += string.format(" ☀️ %.1f°C", tempC1) # Sunshine - Temperature + end + + var tempC2 = sensor[6] + if tempC2 < 1000 + msg += string.format(" ☀️ %.1f°C", tempC2) + end + + var tempC3 = sensor[7] + if tempC3 < 1000 + msg += string.format(" ☀️ %.1f°C", tempC3) + end + msg += "{e}" # = + end + return msg + end #add_web_sensor() +end #class + +LwDeco = LwDecoDrgD20