After many hours of research and tests, I found the solution!
I have some Xiaomi/Aqara sensors (Door sensors, Water Leak, Motion Sensor). The problem is that Domoticz is not saving "Last Seen" datetime from "Devices" and there are no ways to get this value into a script for determinating the sensor timeout.
I'm using a Raspberry Pi + Zigbee2MQTT (CC2531). From the logs I found that the sensors are connecting to the Zigbee2MQTT every 50 minutes. When this happens, the sensor changes the "Last Seen" but it doesn't change the "Last Update". If for example the sensor is in the same state, then this value doesn't change. I found how to make a kind of watchdog relaying on "Last Seen". I got this value using JSON API from domoticz, so when you send a GET request for the specific idx, you get the Last Seen value.
For this we need 2 LUA scripts and some variables.
Script 1: Checking Last Seen and updating variable with the actual Last Seen timer:
Code: Select all
commandArray = {}
json = (loadfile "/home/domoticz/scripts/lua/JSON.lua")() -- For Linux
local config=assert(io.popen('curl "http://127.0.0.1/json.htm?type=devices&rid=71"')) -- json data off all solar panels
local Stringjson = (config:read("*all"))
config:close()
local jsonData = json:decode(Stringjson)
commandArray['Variable:Entrance_Door_Sensor']=jsonData["result"][1]["LastUpdate"]
local config=assert(io.popen('curl "http://127.0.0.1/json.htm?type=devices&rid=84"')) -- json data off all solar panels
local Stringjson = (config:read("*all"))
config:close()
local jsonData = json:decode(Stringjson)
commandArray['Variable:Bedroom_Balcony_Door_Sensor']=jsonData["result"][1]["LastUpdate"]
local config=assert(io.popen('curl "http://127.0.0.1/json.htm?type=devices&rid=80"')) -- json data off all solar panels
local Stringjson = (config:read("*all"))
config:close()
local jsonData = json:decode(Stringjson)
commandArray['Variable:Living_Room_Balcony_Door_Sensor']=jsonData["result"][1]["LastUpdate"]
local config=assert(io.popen('curl "http://127.0.0.1/json.htm?type=devices&rid=53"')) -- json data off all solar panels
local Stringjson = (config:read("*all"))
config:close()
local jsonData = json:decode(Stringjson)
commandArray['Variable:Kitchen_Water_Leak_Sensor']=jsonData["result"][1]["LastUpdate"]
local config=assert(io.popen('curl "http://127.0.0.1/json.htm?type=devices&rid=67"')) -- json data off all solar panels
local Stringjson = (config:read("*all"))
config:close()
local jsonData = json:decode(Stringjson)
commandArray['Variable:Bathroom_Water_Leak_Sensor']=jsonData["result"][1]["LastUpdate"]
local config=assert(io.popen('curl "http://127.0.0.1/json.htm?type=devices&rid=75"')) -- json data off all solar panels
local Stringjson = (config:read("*all"))
config:close()
local jsonData = json:decode(Stringjson)
commandArray['Variable:Kitchen_Motion_Sensor']=jsonData["result"][1]["LastUpdate"]
return commandArray
Code: Select all
-- $Id: script_time_sensormonitor.lua,v 1.3 2016/03/13 12:13:03 pi Exp $
--
logging = false
debug = false
--
-- User variables from Domoticz setup
-- SensorTimeOut (integer) is useful to change for debugging, or undefined for defaults
-- SensorsAlerted (string) - blank / undefined for no alerts, set to "None" as initial value for alterts
-- SensorMonitorDevices (string) - comma separated list of substrings to match for device names
-- SensorMonitorExcluded (string) - comma separated list of substrings out of the matched devices to exclude
--
monitordevices=uservariables["Zigbee_SensorMonitorDevices"];
sensorsalerted=uservariables["Zigbee_SensorsAlerted"];
devicetimeout=uservariables["Zigbee_SensorTimeOut"];
--
-- Fallback values
--
--
-- No changes should be needed below here
--
function changedsince(device)
t1 = os.time()
ts = uservariables[device]
year = string.sub(ts, 1, 4)
month = string.sub(ts, 6, 7)
day = string.sub(ts, 9, 10)
hour = string.sub(ts, 12, 13)
minutes = string.sub(ts, 15, 16)
seconds = string.sub(ts, 18, 19)
t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difftime=(os.difftime(t1,t2))
-- if (debug) then print("Device " .. device .. " not changed in " .. difftime .. " seconds") end
return difftime
end
commandArray = {}
for device, value in pairs(uservariables)
do
pos = nil
exclpos = nil
for matchname in string.gmatch(monitordevices, "[^,]+")
do
pos = string.find(device,matchname,1,true)
if ( pos ) then
if ( exclpos ) then break end
if (debug) then print("Included device " .. device .. " matching " .. matchname .. " value=" .. value) end
deltatime = changedsince(device)
if ( deltatime > devicetimeout ) then
if (logging) then print("Timeout for " .. device .. ". Not seen for " .. deltatime .. " seconds" ) end
if ( sensorsalerted ) then
pos = string.find(sensorsalerted,"," .. device,1,true)
if not ( pos ) then
sensorsalerted = sensorsalerted .. "," .. device
if (logging) then print("sensorsalterted addition: " .. device .. " added to " .. sensorsalerted) end
commandArray['Variable:Zigbee_SensorsAlerted']=sensorsalerted
commandArray['SendNotification']="Sensor " .. device .. " inactive for " .. deltatime .." seconds"
end
end
else
if ( sensorsalerted ) then
pos = string.find(sensorsalerted,"," .. device,1,true)
if ( pos ) then
len = string.len(device) + 1
sensorsalerted = string.sub(sensorsalerted, 1, pos - 1) .. string.sub(sensorsalerted, pos + len)
if (logging) then print("sensorsalterted removal: " .. device .. " removed from " .. sensorsalerted) end
commandArray['Variable:Zigbee_SensorsAlerted']=sensorsalerted
commandArray['SendNotification']="Sensor " .. device .. " active again"
end
end
end
else
if (debug) then print("No match device " .. device .. " no match for " .. matchname) end
end
end
end
return commandArray
Also you need to create 3 variables for Script 2:
Zigbee_SensorTimeOut - time in seconds for sensors to send notification. (Sensors are connecting to Zigbee2MQTT every 50 minutes. I recommend to set: 3600 (60 minutes)
Zigbee_SensorMonitorDevices - variables for every sensor to monitor
Zigbee_SensorsAlerted - This variable will change once a notification was sent for a specific sensor. By default you must set it: None