Script examples (Lua)

Moderator: leecollings

Vopis
Posts: 9
Joined: Sunday 03 May 2020 17:12
Target OS: Linux
Domoticz version:
Contact:

Re: Check last seen?

Post by Vopis »

Hi all,
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
Script 2: Script that sends notification if the timeout timer expired:

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
Creating variables: You need to create a variable for every sensor you want to monitor. This variable will be updated by Script 1 with the "Last Seen" date and time (when the sensor was reaching Zigbee2MQTT last time, not when the sensor status changed).
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

Image
Krenstik
Posts: 45
Joined: Saturday 13 June 2020 12:51
Target OS: NAS (Synology & others)
Domoticz version:
Contact:

Counter data

Post by Krenstik »

HI,

I reading data usage from Synology router via SNMP and I get text or value, but I wish to have it counter, but to be honest I spend a week to understand a Lua script without result.

SO can any one of you please make for me a stupid simple script that takes a value from virtual / or text (I have both) and put it in the counter?

Device id is 682 - Data: "5398910887", (HardwareName: "SNMP Router upx",)
or
device is 688- Data: "5.3991e+09 ",

and virtual counter is a 689

Thank you........
timmpo
Posts: 14
Joined: Sunday 24 February 2019 10:26
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Script examples (Lua)

Post by timmpo »

Domoticz input device!
I needed a device to store settings and other information.
The device creates a uservariable and saves input information witch you can use in other scripts outside and inside domoticz.
The text box is set to only accept numbers if strings neded you have to change "number" to "text" --> html_3 = "</label><br> <input type=\"number\"


Code: Select all


commandArray = {}

    --Create a text device and enable this script

    --Settings
    domoticsURL         = "192.168.1.2:8080"    --Domoticz ip address
    domoticsUser        = "gDgDgDgD"            --Username in base64! https://www.base64encode.org/
    domoticsPass        = "LsLsLsLSL"   	--Password in base64! https://www.base64encode.org/
    userVariableName    = "pris"                --Variable name (its automatly created)
    label               = " Öre"                --Your label
    textDeviceName      = "Avblockeringspris"   --Name on your text device


    html_1 = "<iframe name=\"dummyframe\" id=\"dummyframe\" style=\"display: none\"></iframe> <form method=\"POST\" action=\"/json.htm\" target=\"dummyframe\"> <input type=\"hidden\" id=\"\" name=\"type\" value=\"command\"> <input type=\"hidden\" id=\"\" name=\"param\" value=\"udevice\"> <input type=\"hidden\" id=\"\" name=\"idx\" value=\""
    html_2 = "\"> <input type=\"hidden\" id=\"\" name=\"nvalue\" value=\"0\"> <label for=\"fname\">"
    html_3 = "</label><br> <input type=\"number\" id=\"fname\" name=\"svalue\" value=\"\"> <input type=\"image\" class=\"btnsmall\" alt=\"Save\"></form>"

function url_encode(str)
  if (str) then
    str = string.gsub (str, "\n", "\r\n")
    str = string.gsub (str, "([^%w %-%_%.%~])",
        function (c) return string.format ("%%%02X", string.byte(c)) end)
    str = string.gsub (str, " ", "+")
  end
  return str   
end 

if(uservariables[userVariableName] == nil) then
    print("Variable dont exist")
    commandArray['OpenURL']=domoticsURL..'/json.htm?username='..domoticsUser..'&password='..domoticsPass..'&type=command&param=adduservariable&vname='..url_encode(userVariableName)..'&vtype=0&vvalue=0'
end

if (otherdevices[textDeviceName] == 'Hello World') then
    ttext = "0"
    commandArray['Variable:'..userVariableName] = ttext
    ttidx = otherdevices_idx[textDeviceName]
    html = html_1..ttidx..html_2..ttext..label..html_3
    commandArray['UpdateDevice'] = ttidx..'|0|'..html
end

if (devicechanged[textDeviceName]) then
    ttext = otherdevices[textDeviceName]
    commandArray['Variable:'..userVariableName] = ttext
    ttidx = otherdevices_idx[textDeviceName]
    html = html_1..ttidx..html_2..ttext..label..html_3
    commandArray['UpdateDevice'] = ttidx..'|0|'..html
end

return commandArray

Attachments
input.png
input.png (7.46 KiB) Viewed 2927 times
Thorgal789
Posts: 815
Joined: Wednesday 15 August 2018 14:38
Target OS: -
Domoticz version:
Contact:

Re: Script examples (Lua)

Post by Thorgal789 »

Nice, so usefull.
Good idea too, using html code in text, I think I will do same for other stuff.

Thx a lot.
Neutrino
Posts: 21
Joined: Sunday 08 May 2016 19:00
Target OS: Raspberry Pi / ODroid
Domoticz version: 2021.1
Location: France
Contact:

Re: Script examples (Lua)

Post by Neutrino »

Very good !
Looks like a hack, but very useful.
Thanks 🍺
Nautilus
Posts: 722
Joined: Friday 02 October 2015 12:12
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Finland
Contact:

Re: Script examples (Lua)

Post by Nautilus »

Has there been some sort of quite fundamental change in Lua recently? These used to work fine but now I've noticed in two places that changing On/Off with commandArray in Lua, the changed device does not trigger the associated automation (from "devicechanged").

E.g.

Code: Select all

...
elseif otherdevices['Kotona'] == 'Off' and otherdevices['Nukkumassa'] == 'On' then
    commandArray[#commandArray+1]={['Nukkumassa'] = 'Off'}
    commandArray[#commandArray+1]={['Variable:AwakeCounter'] = '0'}
...

does not trigger the automation associated to device "Nukkumassa".
But this works:

Code: Select all

...
elseif otherdevices['Kotona'] == 'Off' and otherdevices['Nukkumassa'] == 'On' then
    os.execute('curl -s -m 10 --connect-timeout 10 "http://127.0.0.1:30/json.htm?type=command&param=switchlight&idx='..otherdevices_idx['Nukkumassa']..'&switchcmd=Off" &')
    commandArray[#commandArray+1]={['Variable:AwakeCounter'] = '0'}
...
zicht
Posts: 251
Joined: Sunday 11 May 2014 11:09
Target OS: Windows
Domoticz version: 2023.1+
Location: NL
Contact:

Re: Script examples (Lua)

Post by zicht »

Check on daylight saving or not (also timezone offset)

Code: Select all

local timezone = os.date('%z') 
local signum, hours, minutes = timezone:match '([+-])(%d%d)(%d%d)'
signum : returns + or -
hours : the amount of hours for timezone offset
minutes : the amount of minutes for timezone offset, (i don't see a usercase for this)

In summer hours returns for amsterdam +2
During daylight saving it returns for amsterdam +1

This can be handy to adjust timing in script based on time of year and taking into acount daylight saving time.
Rpi & Win x64. Using : cam's,RFXCom, LaCrosse, RFY, HuE, google, standard Lua, Tasker, Waze traveltime, NLAlert&grip2+,curtains, vacuum, audioreceiver, smart-heating&cooling + many more (= automate all repetitive simple tasks)
zicht
Posts: 251
Joined: Sunday 11 May 2014 11:09
Target OS: Windows
Domoticz version: 2023.1+
Location: NL
Contact:

Re: Script examples (Lua)

Post by zicht »

Previous duration

I think we all know that its usefull to know sometimes how long a "switch" is on. Thats pretty much explained and in use.
But some times its not about the current state duration but the previous state duration....
Lets say you want to send a message on a current "On" state change but only if the "Off" state has been longer than x seconds ? (Like: display a welcome greeting only if longer detected away then 30 minutes, as soon as you arrive)

Thats where the below script can help you ;

Code: Select all

function get_previous_state_duration(idx)
 		cmd='C:/progra~2/Domoticz/curl.exe -4 -s "http://192.168.xxx.xxx:xxxx/json.htm?type=command&param=getlightlog&idx='..idx..'"'
	        local f,err=assert(io.popen(cmd, 'r')) if f~=nil then content=assert(f:read('*a')) f:close() end
	        if content~=nil and string.find(content,'"Data"',0)~=nil then
		a=string.find(content,'"Data"',0) b=string.find(content,'"User"',a) eerste=string.sub(content,a,b) a1=string.find(eerste,'Date') b1=string.find(eerste,'Level',a1) eerste=string.sub(eerste,a1+9,b1-8) 
		c=string.find(content,'"Data"',b) d=string.find(content,'"User"',c) tweede=string.sub(content,c,d) a1=string.find(tweede,'Date') b1=string.find(tweede,'Level',a1) tweede=string.sub(tweede,a1+9,b1-8)
		yearx=string.sub(eerste, 1, 4) monthx=string.sub(eerste, 6, 7) dayx=string.sub(eerste, 9, 10) hourx=string.sub(eerste, 12, 13) minutesx=string.sub(eerste, 15, 16) secondsx=string.sub(eerste, 18, 19) 
		t1=os.time{year=tonumber(yearx), month=tonumber(monthx), day=tonumber(dayx), hour=tonumber(hourx), min=tonumber(minutesx), sec=tonumber(secondsx)} 
		yeary=string.sub(tweede, 1, 4) monthy=string.sub(tweede, 6, 7) dayy=string.sub(tweede, 9, 10) houry=string.sub(tweede, 12, 13) minutesy=string.sub(tweede, 15, 16) secondsy=string.sub(tweede, 18, 19) 
		t2=os.time{year=tonumber(yeary), month=tonumber(monthy), day=tonumber(dayy), hour=tonumber(houry), min=tonumber(minutesy), sec=tonumber(secondsy)}
		difference=os.difftime (t1, t2) print(difference)
		return difference
	else
		return err
	end
end	
I use it on a windows machine so you need to alter the curl command to your sys. Dont forget to alter the domoticz IP and PORT
In setting i have disabled the username passw verification for the local host and for api call. (i sadly was never able to get the new api call security to work with curl on windows, it just does not work at all )
Rpi & Win x64. Using : cam's,RFXCom, LaCrosse, RFY, HuE, google, standard Lua, Tasker, Waze traveltime, NLAlert&grip2+,curtains, vacuum, audioreceiver, smart-heating&cooling + many more (= automate all repetitive simple tasks)
User avatar
habahabahaba
Posts: 192
Joined: Saturday 18 March 2023 14:44
Target OS: Windows
Domoticz version: 2024.4
Contact:

Re: Script examples (Lua)

Post by habahabahaba »

zicht wrote: Tuesday 29 October 2024 12:45 I think we all know that its usefull to know sometimes how long a "switch" is on.
Yes, thats right. Thats my solution:

Code: Select all

return {
	on = {
        timer = {'Every 20 minutes'},
    },

	logging = {
		level = domoticz.LOG_INFO,
		marker = 'Check backdoor lights',
	},
	
	
    execute = function(domoticz, item)
        
        local switch = domoticz.devices(1)  -- idx of the switches to check
        
	function disp_time(total_seconds)
          local days = math.floor(total_seconds/86400)
          local remaining = total_seconds % 86400
          local hours = math.floor(remaining/3600)
          remaining = remaining % 3600
          local minutes = math.floor(remaining/60)
          remaining = remaining % 60
          local seconds = remaining
          local hoursstr = "hours"
          local daysStr = ""
          
          if days > 0 then
              
              daysStr = days .. ' days'
              
            end

          if (minutes < 10) then
            minutes = "0" .. tostring(minutes)
          end
          if (seconds < 10) then
            seconds = "0" .. tostring(seconds)
          end
          
          answer =daysStr..' '.. tostring(hours)..' '..hoursstr..' '..minutes..' minutes'
          return answer
    end
        
           
            if (switch.state == 'On' and switch.lastUpdate.secondsAgo > 7000 and item.isTimer ) then  -- if switch is on > 7000 seconds
                
                
                local total_seconds = switch.lastUpdate.secondsAgo
                
                -- sending notify to Telegram^
                
                domoticz.executeShellCommand('curl -v -X POST --silent --output /dev/null https://api.telegram.org/bot'.. domoticz.variables('TbotNumber').value ..'/sendMessage -d chat_id='.. domoticz.variables('MyChatId').value ..' -d text="Backdor light is ON for more then '..disp_time(total_seconds)..'!!! Do you forgot about it??"')
                
            end
    end
    }
P.S. I'm on windows too.
Why dont you use 'domoticz.openURL' method for example ?
zicht
Posts: 251
Joined: Sunday 11 May 2014 11:09
Target OS: Windows
Domoticz version: 2023.1+
Location: NL
Contact:

Re: Script examples (Lua)

Post by zicht »

P.S. I'm on windows too.
Why dont you use 'domoticz.openURL' method for example ?
I am still on plain lua, dzevents is really nice and i should switch... just to lazy to transform all my scripts.
openurl on lua is working great as output, but i also need sometimes a return value.

As for offloading domoticz, i put recurrent url or curl callings on windows taskschedular (writing to a txt file.)"
This way domoticz only does a discoperation and thats lightning fast = without any delay (<1 ms on my machine)
With all automations timing in the end becomes a problem if not managed well.
Rpi & Win x64. Using : cam's,RFXCom, LaCrosse, RFY, HuE, google, standard Lua, Tasker, Waze traveltime, NLAlert&grip2+,curtains, vacuum, audioreceiver, smart-heating&cooling + many more (= automate all repetitive simple tasks)
HvdW
Posts: 504
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: Script examples (Lua)

Post by HvdW »

You don't have to switch to dzVents for every lua script.
I suggest to do it one by one, try, learn, enjoy.
Bugs bug me.
User avatar
KoffieNu
Posts: 3
Joined: Tuesday 20 September 2022 17:37
Target OS: Linux
Domoticz version: 2024.7
Location: Earth, EU, NL, Flevoland
Contact:

Re: Script examples (Lua)

Post by KoffieNu »

I'm using 2024.7 and I'm trying to use a motionsensor to switch on and off a light in the hallway (socket switch, as I'm still messing about, so main light needs to be manual) and limit it's workings to moments when it's dark enough to need it.

However, I get the error "attempt to index a nil value (global 'devicechanged')" the 1st time I try to use devicechanged. The device names I use are copy'n'pasted from the devices list, as to prevent typos (I'm good at them).

Exact error:

Code: Select all

Error: EventSystem: in Licht gang: [string "-- ..."]:26: attempt to index a nil value (global 'devicechanged')
Script (without the 24 line header of the template, so line 26 is the 2nd line of real code.

Code: Select all

commandArray = {}
if (devicechanged['BewegingsensorGang']) then
   luxLevel=tonumber(otherdevices['LichtsensorGang'])
   
   if (devicechanged['BewegingsensorGang'] == 'On' and otherdevices['StopcontactGang'] == 'Off' and luxLevel < 2300 ) then
       commandArray['StopcontactGang']='On'
            print('StopcontactGang was switched ON')
   end

   if (devicechanged['BewegingsensorGang'] == 'Off') then
      commandArray['StopcontactGang']='Off'
      print('StopcontactGang was switched OFF')
   end

   if (devicechanged['BewegingsensorGang'] == 'On' and luxLevel >= 2300 ) then
      commandArray['StopcontactGang']='Off'
      print('StopcontactGang was switched ON but it\'s daytime!')
   end
end

return commandArray
And the devices I use according to the 'Devices current state' tab while editing the script via the web interface:
Image

I have the motion sensor as switch for the socket, that works, but I want to prevent the light being turned on when it's already light enough in the hallway. When I turn on the main light, the value of the lux meter is 2359, so 2300 is a test value that should be usable, but I can't get past the 1st line, or is the error on line 26 indicating I have an error in that if statement, somewhere?

Edit: PEBKAC... (user error) I got the error as I had all as trigger. With device as trigger the script gives errors I can fix. I'm working on it now and will post the end result. I still have the issue that the switch isn't triggered from time to time, leaving either the light on when it should be off or not turning on. I see loads of resets from the dongle though, could be a power issue.

Edit 2: Got the code below running and it runs pretty well.

Code: Select all

hallLightLux = 2300
switchedLightLux = 1150
dayLightLux = 650
commandArray = {}

-- Enable for debugging
-- print("Light : "..otherdevices['LichtsensorGang'])
-- print("Plug  : "..otherdevices['StopcontactGang'])

-- State change BewegingsensorGang
if (devicechanged['BewegingsensorGang'])
then
   -- make a number from lux level in hallway
   luxLevel=tonumber(otherdevices['LichtsensorGang'])
   
   -- When motion sensor detects motion
   if (devicechanged['BewegingsensorGang'] == 'On')
   then
      -- Plug hallway is off
      if (otherdevices['StopcontactGang'] == 'Off')
      then
         -- When to dark, turn on
         if ( luxLevel < dayLightLux )
         then
            commandArray['StopcontactGang']='On'
            print('Motion was detected, StopcontactGang was switched ON')
         end
      -- Plug hallway is on and enough light (more then the switched light)
      elseif (luxLevel >= switchedLightLux )
      then
         --- turn light off as it's not needed  
         commandArray['StopcontactGang']='Off'
         -- check level for log message
         if (luxLevel >= hallLightLux )
         then
            print('Motion was detected, but the main light is on, StopcontactGang switched OFF!')
         else
            print('Motion was detected, but there is enough light ('..luxLevel..'), StopcontactGang switched OFF!')
         end
      else
         print('Motion was detected, but there is enough light ('..luxLevel..'), nothing switched.')
      end   
   end

   if (devicechanged['BewegingsensorGang'] == 'Off' and otherdevices['StopcontactGang'] == 'On')
   then
      commandArray['StopcontactGang']='Off'
      print('No more motion detected, StopcontactGang was switched OFF')
   end
end

-- State change LichtsensorGang
if (devicechanged['LichtsensorGang'])
then
   -- check is motion sensor is off and light is on.
   -- delayed off when found on. (dirty hack on random disconnects)
   if (otherdevices['BewegingsensorGang'] == 'Off' and otherdevices['StopcontactGang'] == 'On')
   then
      commandArray['StopcontactGang']='Off'
      print('No more motion detected, StopcontactGang was switched OFF')
   end
end    

return commandArray
The extra section for LichtsensorGang is to use the more often changing lux sensor to trigger an off event when it's still on. Stability of the stick isn't to great.

What I haven't figured out yet is how to delay a power-off. I tried to use the scene I have for the light with a delayed power-off, but that doesn't seem to work to well. I don't want to put the delay on the device StopcontactGang, as that needs to be switched off without delay when the light level is high enough. Something to think about.

Edit 3: Found how to switch a scene thanks to this question about checking the state of a scene. Added it to my script and it seems to work. (alas, not working, reverting to device, so I'm still looking for a timer option)
FlyingDomotic
Posts: 303
Joined: Saturday 27 February 2016 0:30
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Contact:

Re: Script examples (Lua)

Post by FlyingDomotic »

devicechanged is not a variable but a table, that may contain more than one value.

The right way to extract name and value of changing devices is :
[code
for deviceName,deviceValue in pairs(devicechanged) do
<<Use here deviceName and deviceValue>>
end
[/code]
lost
Posts: 616
Joined: Thursday 10 November 2016 9:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Script examples (Lua)

Post by lost »

FlyingDomotic wrote: Sunday 15 December 2024 21:01 devicechanged is not a variable but a table, that may contain more than one value.
Hello,

Are you really sure of this statement? This contradict what's written in script_device_demo.lua that states:
-- device changed contains state and svalues for the device that changed.
(...)
otherdevices and otherdevices_svalues are arrays for all devices
Hence the singular for this name/state table (not the case for otherdeviceS)... but that's in my understanding for a single device.
Never parsed the full table in my device scripts & did not observed missed actions based on devicechanged filtering as well!
User avatar
jvdz
Posts: 2189
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Script examples (Lua)

Post by jvdz »

devicechanged is a table/array containing the devices changed for this event.
Try to put this code in a device event script and you will see:

Code: Select all

for i, v in pairs(devicechanged) do
   print("! Device =>"..i.." new   status:"..v)
end
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
lost
Posts: 616
Joined: Thursday 10 November 2016 9:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Script examples (Lua)

Post by lost »

As device/time... type scripts are all triggered when an event occurs, not sure parsing the devicechanged table would make a difference anyway (the device parse loop in a single script would be somehow transferred to the event system script calling loop).

But I always observe a few ms between prints, not a single one in the exact same time range. IMO, even on a PI3, the parse+print itself is far from needing a single ms to be processed... and there is always at least 1ms (the log time resolution) difference, mostly several, even for a device like my smartmeter that always send all measurements (I/V/P/CosPhy) if a single value change exceed 2% vs last reported.
FlyingDomotic
Posts: 303
Joined: Saturday 27 February 2016 0:30
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Contact:

Re: Script examples (Lua)

Post by FlyingDomotic »

Here's the default script for LUA/Device (click on "+", right most on scripts tab):

Code: Select all

--
-- Domoticz passes information to scripts through a number of global tables
--
-- device changed contains state and svalues for the device that changed.
--   devicechanged['yourdevicename'] = state 
--   devicechanged['svalues'] = svalues string 
--
-- otherdevices, otherdevices_lastupdate and otherdevices_svalues are arrays for all devices: 
--   otherdevices['yourotherdevicename'] = "On"
--   otherdevices_lastupdate['yourotherdevicename'] = "2015-12-27 14:26:40"
--   otherdevices_svalues['yourotherthermometer'] = string of svalues
--
-- uservariables and uservariables_lastupdate are arrays for all user variables: 
--   uservariables['yourvariablename'] = 'Test Value'
--   uservariables_lastupdate['yourvariablename'] = '2015-12-27 11:19:22'
--
-- other useful details are contained in the timeofday table
--   timeofday['Nighttime'] = true or false
--   timeofday['SunriseInMinutes'] = number
--   timeofday['Daytime'] = true or false
--   timeofday['SunsetInMinutes'] = number
--   globalvariables['Security'] = 'Disarmed', 'Armed Home' or 'Armed Away'
--
-- To see examples of commands see: http://www.domoticz.com/wiki/LUA_commands#General
-- To get a list of available values see: http://www.domoticz.com/wiki/LUA_commands#Function_to_dump_all_variables_supplied_to_the_script
--
-- Based on your logic, fill the commandArray with device commands. Device name is case sensitive. 
--
commandArray = {}

-- loop through all the changed devices
for deviceName,deviceValue in pairs(devicechanged) do
    print ("Device based event fired on '"..deviceName.."', value '"..tostring(deviceValue).."'");
--    if (deviceName=='myDevice') then
--        if deviceValue == "On" then
--            print("Device is On")
--        elseif deviceValue == "Off" then
--            commandArray['a device name'] = "On"
--            commandArray['another device name'] = "Off AFTER 10"
--            commandArray['Scene:MyScene'] = "Off"
--            commandArray['Group:My Group'] = "Off AFTER 30"
--        end
--    end
end

return commandArray
Concerning timing, don't forget that there's only one script active at a time. Guess what will happen if you spend too much time in a script, while few events will be delivered (but nor executed, as waiting for current script to end).
lost
Posts: 616
Joined: Thursday 10 November 2016 9:30
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Script examples (Lua)

Post by lost »

The time difference observation I made was with jvzd test script. So I presumed prints always resulted from successive calls but... Looks this was not the case, if I add a counter to the loop (+ here I have some logs with exact same timing up to 1ms resolution) that counts devices that trig'ed in a single call:

2024-12-17 08:09:30.992 Status: LUA: ! Device1 =>Prise Seche Linge W_Utility new status:685.0
2024-12-17 08:09:30.994 Status: LUA: ! Device2 =>Prise Seche Linge W new status:685.0
2024-12-17 08:09:35.986 Status: LUA: ! Device1 =>Prise Seche Linge W new status:678.0
2024-12-17 08:09:35.986 Status: LUA: ! Device2 =>Prise Seche Linge W_Utility new status:678.0
2024-12-17 08:09:36.987 Status: LUA: ! Device1 =>Prise Seche Linge W_Utility new status:684.0
2024-12-17 08:09:36.987 Status: LUA: ! Device2 =>Prise Seche Linge W new status:684.0
2024-12-17 08:09:39.991 Status: LUA: ! Device1 =>Prise Seche Linge W new status:677.0
2024-12-17 08:09:39.991 Status: LUA: ! Device2 =>Prise Seche Linge W_Utility new status:677.0
2024-12-17 08:09:41.449 Status: LUA: ! Device1 =>SmartMeterW CTR new status:975.300;22682400.000
2024-12-17 08:09:41.449 Status: LUA: ! Device2 =>SmartMeterW CTR_Utility new status:975.29998779297
2024-12-17 08:09:41.851 Status: LUA: ! Device1 =>SmartMeter W new status:983.2
2024-12-17 08:09:41.851 Status: LUA: ! Device2 =>SmartMeter W_Utility new status:983.20001220703
2024-12-17 08:09:41.905 Status: LUA: ! Device1 =>SmartMeterW CTR new status:983.200;22682400.000
2024-12-17 08:09:41.905 Status: LUA: ! Device2 =>SmartMeterW CTR_Utility new status:983.20001220703
2024-12-17 08:09:42.050 Status: LUA: ! Device1 =>SmartMeter V new status:233.500
2024-12-17 08:09:42.050 Status: LUA: ! Device2 =>SmartMeter V_Utility new status:233.5
2024-12-17 08:09:42.263 Status: LUA: ! Device1 =>SmartMeter I new status:4.4;0.0;0.0
2024-12-17 08:09:42.466 Status: LUA: ! Device1 =>SmartMeter PF_Utility new status:1.0
2024-12-17 08:09:42.467 Status: LUA: ! Device2 =>SmartMeter PF new status:1.00
2024-12-17 08:09:45.033 Status: LUA: ! Device1 =>Prise Seche Linge W new status:684.0
2024-12-17 08:09:45.033 Status: LUA: ! Device2 =>Prise Seche Linge W_Utility new status:684.0
2024-12-17 08:09:49.762 Status: LUA: ! Device1 =>PI CPU Usage_Utility new status:4.8899998664856
2024-12-17 08:09:49.762 Status: LUA: ! Device2 =>PI CPU Usage new status:4.89
=> There can be a few ms gap between 2 prints for the same call, as the very 1st in this log extract so my assumption was wrong.

But also note (sub-)devices that change always are part of the same hardware, for now I did not saw exceptions to this + that's mostly 1 or 2, rarely up to 4 (only for weather virtual devices on which I do not have any script handling, not real hardware)... See for instance my Smart-Meter that sends many measurements in bursts: They are in fact always split in Lua handling.

So agree this may optimize Lua scripts handling a bit, but as sub-devices that belongs to the same hardware will most probably be handled in a single script not sure this makes so big difference.

Here is the modified script to make it clear (script_device_test.lua):

Code: Select all

local devicesTriggeredNb = 0

for i, v in pairs(devicechanged) do
   devicesTriggeredNb = devicesTriggeredNb + 1
   print("! Device"..devicesTriggeredNb.." =>"..i.." new   status:"..v)
end
On my side (2024.7), the demo device script have your lines commented and also have these lines as supposed real case examples at the end (that's the one in domoticz/scripts/lua, I don't use event editor as having a messy script stored in DB can turn to headache if this cause domoticz runtine issues, with no easy way to remove it!):

Code: Select all

-- TBD: nice time example, for instance get temp from svalue string, if time is past 22.00 and before 00:00 and temp is bloody hot turn on fan. 

print('this will end up in the domoticz log')

commandArray = {}
if (devicechanged['MyDeviceName'] == 'On' and otherdevices['MyOtherDeviceName'] == 'Off') then
	commandArray['MyOtherDeviceName']='On'
end
return commandArray
And no loop based handling there, the commented one looked to target debugging IMO & induced my understanding.

Anyway, I keep in mind that (sub-)devices handling may be optimized using a loop... or even prefilter early in scripts using name prefix as I always use a real hardware name prefix for their included devices before the targeted handling that'll follow.
HvdW
Posts: 504
Joined: Sunday 01 November 2015 22:45
Target OS: Raspberry Pi / ODroid
Domoticz version: 2023.2
Location: Twente
Contact:

Re: Script examples (Lua)

Post by HvdW »

FlyingDomotic wrote: Monday 16 December 2024 18:43 Here's the default script for LUA/Device (click on "+", right most on scripts tab):
So great a script!
It's a realy simple way to be able to watch what's happening behind the scenes PLUS the data being displayed.
I have put in the list of scripts and named it All data display

Activate it, wait a little while, deactivate it and read the log to get all information you're searching for.
Bugs bug me.
Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests