Add GUI support to LoRaWan decoders

This commit is contained in:
Theo Arends 2025-05-22 17:32:16 +02:00
parent 92f14dd0c0
commit 4f4bf7c61b
6 changed files with 410 additions and 200 deletions

View File

@ -2,41 +2,77 @@
# https://github.com/TheThingsNetwork/lorawan-devices/tree/master/vendor # https://github.com/TheThingsNetwork/lorawan-devices/tree/master/vendor
var LwRegions = ["EU868", "US915", "IN865","AU915","KZ865","RU864","AS923", "AS923-1","AS923-2","AS923-3"] var LwRegions = ["EU868", "US915", "IN865","AU915","KZ865","RU864","AS923", "AS923-1","AS923-2","AS923-3"]
var LwDeco
import mqtt import mqtt
class lwdecode_cls
var thisDevice
var LwDecoders
def init()
self.thisDevice = tasmota.cmd('Status',true)['Status']['Topic']
self.LwDecoders = {}
if global.lwdecode_driver
global.lwdecode_driver.stop() # Let previous instance bail out cleanly
end
tasmota.add_driver(global.lwdecode_driver := self)
tasmota.add_rule("LwReceived", /value, trigger, payload -> self.LwDecode(payload))
end
def LwDecode(data)
import json
var deviceData = data['LwReceived']
var deviceName = deviceData.keys()()
var Node = deviceData[deviceName]['Node']
var Payload = deviceData[deviceName]['Payload']
var FPort = deviceData[deviceName]['FPort']
var decoder = deviceData[deviceName].find('Decoder')
if !decoder
return true
end
if !self.LwDecoders.find(decoder)
LwDeco = nil
load(decoder) #sets LwDeco if found
if LwDeco
self.LwDecoders.insert(decoder, LwDeco)
end
end
if Payload.size() && self.LwDecoders.find(decoder)
var topic = "tele/" + self.thisDevice + "/SENSOR"
var decoded = self.LwDecoders[decoder].decodeUplink(Node, FPort, Payload)
var mqttData = {"LwDecoded":{deviceName:decoded}}
mqtt.publish(topic, json.dump(mqttData))
end
return true #processed
end
#------------------------------------------------------------
Display sensor value in the web UI and react to button
Called every WebRefresh time
------------------------------------------------------------#
def web_sensor()
import string
var msg = ""
for decoder: self.LwDecoders
msg = msg + decoder.add_web_sensor()
end
if msg
tasmota.web_send_decimal(msg)
end
end
end
lwdecode = lwdecode_cls()
tasmota.cmd('SetOption100 off') # Keep LwReceived in JSON message tasmota.cmd('SetOption100 off') # Keep LwReceived in JSON message
tasmota.cmd('SetOption118 off') # Keep SENSOR as subtopic name tasmota.cmd('SetOption118 off') # Keep SENSOR as subtopic name
tasmota.cmd('SetOption119 off') # Keep device address in JSON message tasmota.cmd('SetOption119 off') # Keep device address in JSON message
tasmota.cmd('SetOption147 on') # Hide LwReceived MQTT message but keep rule processing tasmota.cmd('SetOption147 on') # Hide LwReceived MQTT message but keep rule processing
tasmota.cmd('LoRaWanBridge on') tasmota.cmd('LoRaWanBridge on')
var thisDevice = tasmota.cmd('Status',true)['Status']['Topic']
var LwDecoders = {}
var LwDeco
def LwDecode(data)
import json
var deviceData = data['LwReceived']
var deviceName = deviceData.keys()()
var Payload = deviceData[deviceName]['Payload']
var FPort = deviceData[deviceName]['FPort']
var decoder = deviceData[deviceName].find('Decoder')
if !decoder return true end
if !LwDecoders.find(decoder)
LwDeco = nil
load(decoder) #sets LwDeco if found
if LwDeco LwDecoders.insert(decoder, LwDeco) end
end
if Payload.size() && LwDecoders.find(decoder)
var topic = "tele/" + thisDevice + "/SENSOR"
var decoded = LwDecoders[decoder].decodeUplink(FPort, Payload)
var mqttData = {"LwDecoded":{deviceName:decoded}}
mqtt.publish (topic, json.dump(mqttData))
end
return true #processed
end
tasmota.add_rule("LwReceived", /value, trigger, payload -> LwDecode(payload))

View File

@ -8,6 +8,9 @@
# the string module is not needed in this decoder; shown as an example. # the string module is not needed in this decoder; shown as an example.
import string import string
# define a global map for storage of GUI parameters
global.DEVICENodes = {}
# Declare a new Class # Declare a new Class
# The Class name should follow this format: LwDecoXXXX where XXXX is the DEVICE # The Class name should follow this format: LwDecoXXXX where XXXX is the DEVICE
class LwDecoDEVICE class LwDecoDEVICE
@ -16,24 +19,49 @@ class LwDecoDEVICE
# Name: decodeUplink Must use this name, and arguments # Name: decodeUplink Must use this name, and arguments
# Arguments: FPort The Fport number used by the End Device for this packet of data # Arguments: FPort The Fport number used by the End Device for this packet of data
# Bytes The Raw Data Payload # Bytes The Raw Data Payload
static def decodeUplink(FPort, Bytes) static def decodeUplink(Node, FPort, Bytes)
# Create the data structure (a Berry 'map'), and populate with the VENDOR & DEVICE names # Create the data structure (a Berry 'map'), and populate with the VENDOR & DEVICE names
var data = {"Device":"VENDOR DEVICE"} var data = {"Device":"VENDOR DEVICE"}
data.insert("Node", Node)
var valid_values = false
var gui_value
# For each Fport used by the DEVICE: # For each Fport used by the DEVICE:
# write a decoder that continues to populate the data structure by parsing the Raw Data Payload # write a decoder that continues to populate the data structure by parsing the Raw Data Payload
if 2 == FPort && 11 == Bytes.size() #Example: For this device, Data from Fport 2 should have 11 bytes if 2 == FPort && 11 == Bytes.size() #Example: For this device, Data from Fport 2 should have 11 bytes
data.insert("LABEL1", Bytes[0] | Bytes[1] <<8 ) #Example Numerical value = Bytes[1]*256 + Bytes[0] data.insert("LABEL1", Bytes[0] | Bytes[1] <<8 ) #Example Numerical value = Bytes[1]*256 + Bytes[0]
gui_value = Bytes[0] | Bytes[1] <<8
data.insert("LABEL2", "TEXT VALUE") #Example Text value data.insert("LABEL2", "TEXT VALUE") #Example Text value
var valid_values = true
else else
# Ignore other Fports # Ignore other Fports
end #Fport end #Fport
if valid_values
if global.DEVICENodes.find(Node)
global.DEVICENodes.remove(Node)
end
global.DEVICENodes.insert(Node, [Node, gui_value])
end
return data return data
end #decodeUplink() end #decodeUplink()
static def add_web_sensor()
var msg = ""
for sensor: global.DEVICENodes
msg += string.format("{s}DEVICE_%i Gui value{m}%i{e}",
sensor[0], sensor[1])
end
return msg
end #add_web_sensor()
end #class end #class
# Set LwDeco variable to the new Class # Set LwDeco variable to the new Class

View File

@ -4,26 +4,50 @@
# LHT52 User Manual: https://wiki.dragino.com/xwiki/bin/view/Main/User%20Manual%20for%20LoRaWAN%20End%20Nodes/LDS02%20-%20LoRaWAN%20Door%20Sensor%20User%20Manual/ # LHT52 User Manual: https://wiki.dragino.com/xwiki/bin/view/Main/User%20Manual%20for%20LoRaWAN%20End%20Nodes/LDS02%20-%20LoRaWAN%20Door%20Sensor%20User%20Manual/
# TTN Device Repository: https://github.com/TheThingsNetwork/lorawan-devices/blob/master/vendor/dragino/lds02.js # TTN Device Repository: https://github.com/TheThingsNetwork/lorawan-devices/blob/master/vendor/dragino/lds02.js
import string
global.lds02Nodes = {}
class LwDecoLDS02 class LwDecoLDS02
static def decodeUplink(Node, FPort, Bytes)
static def decodeUplink(FPort, Bytes)
var data = {"Device":"Dragino LDS02"} var data = {"Device":"Dragino LDS02"}
data.insert("Node", Node)
var valid_values = false
var door_open
## SENSOR DATA ## ## SENSOR DATA ##
if 10 == FPort && Bytes.size() == 10 if 10 == FPort && Bytes.size() == 10
data.insert("DoorOpen", ( Bytes[0] & 0x80 ) ? true : false ) door_open = ( Bytes[0] & 0x80 ) ? 1 : 0
data.insert("DoorOpen", ( door_open ) ? true : false)
data.insert("Battery_mV", ( Bytes[1] | (Bytes[0] << 8) & 0x3FFF )) data.insert("Battery_mV", ( Bytes[1] | (Bytes[0] << 8) & 0x3FFF ))
data.insert("DoorOpenEvents", Bytes[5] | (Bytes[4] << 8) | (Bytes[3] << 16 )) data.insert("DoorOpenEvents", Bytes[5] | (Bytes[4] << 8) | (Bytes[3] << 16 ))
data.insert("DoorOpenLastDuration_mins", Bytes[8] | (Bytes[7] << 8) | (Bytes[6] << 16)) data.insert("DoorOpenLastDuration_mins", Bytes[8] | (Bytes[7] << 8) | (Bytes[6] << 16))
data.insert("Alarm", (Bytes[9] & 0x01 ) ? true : false) data.insert("Alarm", (Bytes[9] & 0x01 ) ? true : false)
valid_values = true
else else
# Ignore other Fports # Ignore other Fports
end #Fport end #Fport
if valid_values
if global.lds02Nodes.find(Node)
global.lds02Nodes.remove(Node)
end
global.lds02Nodes.insert(Node, [Node, door_open])
end
return data return data
end #decodeUplink() end #decodeUplink()
static def add_web_sensor()
var msg = ""
for sensor: global.lds02Nodes
msg += string.format("{s}LDS02_%i Door{m}%s{e}",
sensor[0], (sensor[1]) ? "Open" : "Closed")
end
return msg
end
end #class end #class
LwDeco = LwDecoLDS02 LwDeco = LwDecoLDS02

View File

@ -6,35 +6,48 @@
import string import string
global.lht52Nodes = {}
class LwDecoLHT52 class LwDecoLHT52
static def decodeUplink(Node, FPort, Bytes)
static def decodeUplink(FPort, Bytes)
var data = {"Device":"Dragino LHT52"} var data = {"Device":"Dragino LHT52"}
data.insert("Node", Node)
var valid_values = false
var temp_int
var humidity
var temp_ext = 1000
## SENSOR DATA ## ## SENSOR DATA ##
if 2 == FPort && Bytes.size() == 11 if 2 == FPort && Bytes.size() == 11
var TempC var TempC
TempC = Bytes[0]<<8 | Bytes[1] TempC = Bytes[0] << 8 | Bytes[1]
if Bytes[0]>0x7F TempC -= 0x10000 end if Bytes[0] > 0x7F
TempC -= 0x10000
end
TempC /= 100.0 TempC /= 100.0
data.insert("TempC_Internal",TempC) data.insert("TempC_Internal", TempC)
temp_int = TempC
TempC = Bytes[4]<<8 | Bytes[5] TempC = Bytes[4] << 8 | Bytes[5]
if 0x7FFF == TempC if 0x7FFF == TempC
data.insert("Ext_SensorConnected", false) data.insert("Ext_SensorConnected", false)
else else
data.insert("Ext_SensorConnected", true) data.insert("Ext_SensorConnected", true)
if Bytes[4]>0x7F TempC -= 0x10000 end if Bytes[4] > 0x7F
TempC -= 0x10000
end
TempC /= 100.0 TempC /= 100.0
data.insert("TempC_External",TempC) data.insert("TempC_External", TempC)
temp_ext = TempC
end end
data.insert("Hum_Internal", ((Bytes[2]<<8 ) | Bytes[3])/10.0) data.insert("Hum_Internal", ((Bytes[2] << 8) | Bytes[3]) / 10.0)
humidity = ((Bytes[2] << 8) | Bytes[3]) / 10.0
data.insert("Ext_SensorType", Bytes[6]) data.insert("Ext_SensorType", Bytes[6])
# data.insert("Systimestamp",(Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10])
var epoch = (Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10] var epoch = (Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10]
data.insert("Systimestamp",tasmota.time_str(epoch)) data.insert("Systimestamp",tasmota.time_str(epoch))
valid_values = true
## STATUS DATA ## ## STATUS DATA ##
elif 5 == FPort && Bytes.size() == 7 elif 5 == FPort && Bytes.size() == 7
@ -48,8 +61,31 @@ class LwDecoLHT52
# Ignore other Fports # Ignore other Fports
end #Fport end #Fport
if valid_values
if global.lht52Nodes.find(Node)
global.lht52Nodes.remove(Node)
end
global.lht52Nodes.insert(Node, [Node, temp_int, humidity, temp_ext])
end
return data return data
end #decodeUplink() end #decodeUplink()
static def add_web_sensor()
var msg = ""
for sensor: global.lht52Nodes
msg += string.format("{s}LHT52_%i Temperature{m}%.1f °C{e}"..
"{s}LHT52_%i Humidity{m}%.1f %%{e}",
sensor[0], sensor[1],
sensor[0], sensor[2])
if sensor[3] < 1000
msg += string.format("{s}LHT52_%i Temperature ext.{m}%.1f °C{e}",
sensor[0], sensor[3])
end
end
return msg
end
end #class end #class
LwDeco = LwDecoLHT52 LwDeco = LwDecoLHT52

View File

@ -6,25 +6,42 @@
import string import string
var LHT65_BatteryStatus = ["Very low <= 2.5V","Low <=2.55V","OK","Good >= 2.65V"] var LHT65_BatteryStatus = ["Very low <= 2.5V","Low <=2.55V","OK","Good >= 2.65V"]
global.lht65Nodes = {}
class LwDecoLHT65 class LwDecoLHT65
static def decodeUplink(FPort, Bytes) static def decodeUplink(FPort, Bytes)
var data = {"Device":"Dragino LHT65"} var data = {"Device":"Dragino LHT65"}
data.insert("Node", Node)
data.insert("poll_message_status",(Bytes[6] & 0x40) >> 6) data.insert("poll_message_status",(Bytes[6] & 0x40) >> 6)
var Ext = Bytes[6] & 0x0F #External sensor type var Ext = Bytes[6] & 0x0F #External sensor type
var NoConnect = (Bytes[6] & 0x80) >> 7 var NoConnect = (Bytes[6] & 0x80) >> 7
var valid_values = false
var temp_int = 1000
var humidity
var temp_ext = 1000
if global.lht65Nodes.find(Node)
temp_int = global.lht65Nodes.item(Node)[1]
humidity = global.lht65Nodes.item(Node)[2]
temp_ext = global.lht65Nodes.item(Node)[3]
end
## SENSOR DATA ## ## SENSOR DATA ##
if 2 == FPort && Bytes.size() == 11 if 2 == FPort && Bytes.size() == 11
var TempC var TempC
if Ext == 9 #Sensor E3, Temperature Sensor, Datalog Mod if Ext == 9 #Sensor E3, Temperature Sensor, Datalog Mod
TempC = ((Bytes[0] << 8) | Bytes[1]) TempC = ((Bytes[0] << 8) | Bytes[1])
if 0x7FFF == TempC if 0x7FFF == TempC
data.insert("Ext_SensorConnected", false) data.insert("Ext_SensorConnected", false)
else else
data.insert("Ext_SensorConnected", true) data.insert("Ext_SensorConnected", true)
if Bytes[0]>0x7F TempC -= 0x10000 end if Bytes[0]>0x7F
data.insert("TempC_External", TempC / 100.0) TempC -= 0x10000
end
temp_ext = TempC / 100.0
data.insert("TempC_External", temp_ext)
valid_values = true
end end
data.insert("Bat_status", LHT65_BatteryStatus[Bytes[4] >> 6]) data.insert("Bat_status", LHT65_BatteryStatus[Bytes[4] >> 6])
else else
@ -34,16 +51,21 @@ class LwDecoLHT65
if Ext != 0x0F if Ext != 0x0F
TempC = ((Bytes[2] << 8) | Bytes[3]) TempC = ((Bytes[2] << 8) | Bytes[3])
if Bytes[2]>0x7F TempC -= 0x10000 end if Bytes[2]>0x7F
data.insert("TempC_Internal", ( TempC / 100.0)) TempC -= 0x10000
data.insert("Hum_Internal" , (((Bytes[4] << 8) | Bytes[5]) / 10.0)) end
temp_int = TempC / 100.0
data.insert("TempC_Internal", temp_int)
humidity = (((Bytes[4] << 8) | Bytes[5]) / 10.0)
data.insert("Hum_Internal" , humidity)
valid_values = true
end end
if NoConnect if NoConnect
data.insert('No_connect','No connection to external sensor') data.insert('No_connect','No connection to external sensor')
end end
if 0==Ext if 0 == Ext
data.insert("Ext_sensor", 'No external sensor') data.insert("Ext_sensor", 'No external sensor')
elif 1==Ext elif 1==Ext
data.insert("Ext_sensor",'Temperature Sensor') data.insert("Ext_sensor",'Temperature Sensor')
@ -52,31 +74,34 @@ class LwDecoLHT65
data.insert("Ext_SensorConnected", false) data.insert("Ext_SensorConnected", false)
else else
data.insert("Ext_SensorConnected", true) data.insert("Ext_SensorConnected", true)
if Bytes[7]>0x7F TempC -= 0x10000 end if Bytes[7]>0x7F
data.insert("TempC_External", TempC / 100.0) TempC -= 0x10000
end end
elif 4==Ext temp_ext = TempC / 100.0
data.insert("TempC_External", temp_ext)
valid_values = true
end
elif 4 == Ext
data.insert("Work_mode", 'Interrupt Sensor send') data.insert("Work_mode", 'Interrupt Sensor send')
data.insert("Exti_pin_level", Bytes[7] ? 'High' : 'Low') data.insert("Exti_pin_level", Bytes[7] ? 'High' : 'Low')
data.insert("Exti_status", Bytes[8] ? 'True' : 'False') data.insert("Exti_status", Bytes[8] ? 'True' : 'False')
elif 5==Ext elif 5 == Ext
data.insert("Work_mode", 'Illumination Sensor') data.insert("Work_mode", 'Illumination Sensor')
data.insert("ILL_lx", (Bytes[7] << 8) | Bytes[8]) data.insert("ILL_lx", (Bytes[7] << 8) | Bytes[8])
elif 6==Ext elif 6 == Ext
data.insert("Work_mode", 'ADC Sensor') data.insert("Work_mode", 'ADC Sensor')
data.insert("ADC_V", ((Bytes[7] << 8) | Bytes[8]) / 1000.0) data.insert("ADC_V", ((Bytes[7] << 8) | Bytes[8]) / 1000.0)
elif 7==Ext elif 7 == Ext
data.insert("Work_mode ", 'Interrupt Sensor count') data.insert("Work_mode ", 'Interrupt Sensor count')
data.insert("Exit_count", (Bytes[7] << 8) | Bytes[8]) data.insert("Exit_count", (Bytes[7] << 8) | Bytes[8])
elif 8==Ext elif 8 == Ext
data.insert("Work_mode", 'Interrupt Sensor count') data.insert("Work_mode", 'Interrupt Sensor count')
data.insert("Exit_count", (Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10]) data.insert("Exit_count", (Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10])
elif 9==Ext elif 9 == Ext
data.insert("Work_mode", 'DS18B20 & timestamp') data.insert("Work_mode", 'DS18B20 & timestamp')
# data.insert("Systimestamp", (Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10])
var epoch = (Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10] var epoch = (Bytes[7] << 24) | (Bytes[8] << 16) | (Bytes[9] << 8) | Bytes[10]
data.insert("Systimestamp",tasmota.time_str(epoch)) data.insert("Systimestamp",tasmota.time_str(epoch))
elif 15==Ext elif 15 == Ext
data.insert("Work_mode",'DS18B20ID') data.insert("Work_mode",'DS18B20ID')
data.insert("ID",f"{Bytes[2]:%02X}" + f"{Bytes[3]:%02X}" + f"{Bytes[4]:%02X}" + f"{Bytes[5]:%02X}" + f"{Bytes[6]:%02X}" + f"{Bytes[8]:%02X}" + f"{Bytes[9]:%02X}" + f"{Bytes[10]:%02X}" ) data.insert("ID",f"{Bytes[2]:%02X}" + f"{Bytes[3]:%02X}" + f"{Bytes[4]:%02X}" + f"{Bytes[5]:%02X}" + f"{Bytes[6]:%02X}" + f"{Bytes[8]:%02X}" + f"{Bytes[9]:%02X}" + f"{Bytes[10]:%02X}" )
else else
@ -94,8 +119,34 @@ class LwDecoLHT65
# Ignore other Fports # Ignore other Fports
end #Fport end #Fport
if valid_values
if global.lht65Nodes.find(Node)
global.lht65Nodes.remove(Node)
end
global.lht65Nodes.insert(Node, [Node, temp_int, humidity, temp_ext])
end
return data return data
end # decodeUplink() end # decodeUplink()
static def add_web_sensor()
var msg = ""
for sensor: global.lht65Nodes
if sensor[1] < 1000
msg += string.format("{s}LHT65_%i Temperature{m}%.1f °C{e}"..
"{s}LHT65_%i Humidity{m}%.1f %%{e}",
sensor[0], sensor[1],
sensor[0], sensor[2])
end
if sensor[3] < 1000
msg += string.format("{s}LHT65_%i Temperature ext.{m}%.1f °C{e}",
sensor[0], sensor[3])
end
end
return msg
end
end # class end # class
LwDeco = LwDecoLHT65 LwDeco = LwDecoLHT65

View File

@ -4,30 +4,65 @@
# DW10 Product information: https://www.browan.com/products-detail/OpenClose-Sensor-EBL-LoRaWAN/ # DW10 Product information: https://www.browan.com/products-detail/OpenClose-Sensor-EBL-LoRaWAN/
# Browan JS Decoder (TTN): https://www.browan.com/member/login/?refererUrl=https%3A%2F%2Fwww.browan.com%2Fproducts-detail%2FOpenClose-Sensor-EBL-LoRaWAN%2F # Browan JS Decoder (TTN): https://www.browan.com/member/login/?refererUrl=https%3A%2F%2Fwww.browan.com%2Fproducts-detail%2FOpenClose-Sensor-EBL-LoRaWAN%2F
import string
global.dw10Nodes = {}
class LwDecoDW10 class LwDecoDW10
static def decodeUplink(Node, FPort, Bytes)
static def decodeUplink(FPort, Bytes)
var data = {"Device":"MerryIoT DW10"} var data = {"Device":"MerryIoT DW10"}
data.insert("Node", Node)
var valid_values = false
var door_open
var button_pressed
var temperature
var humidity
## SENSOR DATA ## ## SENSOR DATA ##
if 120 == FPort && Bytes.size() == 9 if 120 == FPort && Bytes.size() == 9
data.insert("DoorOpen", ( Bytes[0] & 0x01 ) ? true : false ) door_open = ( Bytes[0] & 0x01 ) ? 1 : 0
data.insert("ButtonPress", ( Bytes[0] & 0x02 ) ? true : false ) data.insert("DoorOpen", ( door_open ) ? true : false )
button_pressed = ( Bytes[0] & 0x02 ) ? 1 : 0
data.insert("ButtonPress", ( button_pressed ) ? true : false )
data.insert("TamperDetect", ( Bytes[0] & 0x04 ) ? true : false ) data.insert("TamperDetect", ( Bytes[0] & 0x04 ) ? true : false )
data.insert("TiltDetect", ( Bytes[0] & 0x08 ) ? true : false ) data.insert("TiltDetect", ( Bytes[0] & 0x08 ) ? true : false )
data.insert("Battery_mV", ( 21 + Bytes[1] ) * 100 ) data.insert("Battery_mV", ( 21 + Bytes[1] ) * 100 )
data.insert("Temperature_C", Bytes[2]) data.insert("Temperature_C", Bytes[2])
temperature = Bytes[2]
data.insert("Humidity", Bytes[3]) data.insert("Humidity", Bytes[3])
humidity = Bytes[3]
data.insert("DoorOpenLastDuration_mins", Bytes[4] | (Bytes[5] << 8)) data.insert("DoorOpenLastDuration_mins", Bytes[4] | (Bytes[5] << 8))
data.insert("DoorOpenEvents", Bytes[6] | (Bytes[7] << 8) | (Bytes[8] << 16 )) data.insert("DoorOpenEvents", Bytes[6] | (Bytes[7] << 8) | (Bytes[8] << 16 ))
valid_values = true
else else
# Ignore other Fports # Ignore other Fports
end #Fport end #Fport
if valid_values
if global.dw10Nodes.find(Node)
global.dw10Nodes.remove(Node)
end
global.dw10Nodes.insert(Node, [Node, door_open, button_pressed, temperature, humidity])
end
return data return data
end #decodeUplink() end #decodeUplink()
static def add_web_sensor()
var msg = ""
for sensor: global.dw10Nodes
msg += string.format("{s}DW10_%i Door{m}%s{e}"..
"{s}DW10_%i Button{m}%s{e}"..
"{s}DW10_%i Temperature{m}%.1f °C{e}"..
"{s}DW10_%i Humidity{m}%.1f %%{e}",
sensor[0], (sensor[1]) ? "Open" : "Closed",
sensor[0], (sensor[2]) ? "Pressed" : "Released",
sensor[0], sensor[3],
sensor[0], sensor[4])
end
return msg
end
end #class end #class
LwDeco = LwDecoDW10 LwDeco = LwDecoDW10