Page 1 of 1
Wildcard in devicechanged
Posted: Thursday 31 December 2015 13:16
by barbaar
Right..
I want 3 lights on the ground floor to be turned on when one (of three) switches are turned. Two lights are attached to a Fibaro Dimmer. When the Fibaro dimmer is switched on, its status changes to 'Set Level 60', where 60 represents the dimlevel.
So I require the following (pseudo) LUA code:
Code: Select all
if (devicechanged['Licht Voorkamer'] == '[b]Set Level *[/b]' and otherdevices['Licht Achterkamer'] == 'Off' and otherdevices['Licht Keuken'] == 'Off') then
commandArray['Licht Achterkamer']='On'
commandArray['Licht Keuken']='On'
end
I tried changing the above code to
Code: Select all
if (devicechanged['Licht Voorkamer'] ~= nil ) then
if (devicechanged['Licht Voorkamer']:match("Set Level %a") and ...
However, there are two things I am unable to solve:
- Devicechanged needs to return a boolean, which it does not do in this code
- I don't understand how the stringmatching works in LUA
Any help is appreciated!
Ps:
Negatieve testing does not work
Code: Select all
if (devicechanged['Licht Voorkamer'] ~= 'Off"
will always switch on the light
Re: Wildcard in devicechanged
Posted: Thursday 31 December 2015 14:00
by simonrg
barbaar wrote:Negatieve testing does not work
Code: Select all
if (devicechanged['Licht Voorkamer'] ~= 'Off"
will always switch on the light
Negative testing could work, but in your example you seem to have mixed quotes which won't work but should show up as an error.
However, negative testing will only work if the off state of your dimmer is 'Off' if it is something else then it will appear to be always on.
Have a look at the Wiki -
http://www.domoticz.com/wiki/Scripts#Lua_Scripts - for examples of testing for multiple devices for example in the Smart PIR scripts -
http://www.domoticz.com/wiki/Smart_Lua_ ... _Smart_PIR.
Re: Wildcard in devicechanged
Posted: Friday 01 January 2016 16:13
by barbaar
Thanks,
Based on your reply, I changed my script to:
Code: Select all
tc=next(devicechanged)
v=tostring(tc)
if (v:sub(6,12) == 'Beneden') then
commandArray['LichtBenedenAchterkamer']='Set Level 60'
commandArray['LichtBenedenVoorkamer']='Set Level 40'
commandArray['LichtBenedenKeuken']='On'
end
return commandArray
Howver, I still have two issues

- The code above leads to a invinite loop: each device changes its state, and therefor activates the script
- The code above is also activated when a light is being turned off. This can be solved by determining the current state of the dimmer, but that leads to my initial question (can I use wildcards to test to 'Set Level *'?)
-- I can test the "keuken" light, which is a regulare Fibaro On/Off switch. But that would not be te most reliable option..
Re: Wildcard in devicechanged
Posted: Friday 01 January 2016 16:24
by jvdz
I am using the below function to switch switches/dimmers only when they are currently set to a different status.
This should avoid endless loops like you just described:
Code: Select all
function SwitchWhenDiff(DeviceName, iCommand)
local dstatus = otherdevices[DeviceName]
local dvalue = tonumber(otherdevices_svalues[DeviceName])
if dvalue == nil then
dvalue = 0
end
if dstatus == nil then
dstatus = "??"
end
--
local Command = ""
local Level = 0
local Suffix = ""
-- check for valid starting command to perform
if string.sub(iCommand,1,2) == "On" then
Command = "On"
Level = 255
Suffix = string.sub(iCommand,4)
elseif string.sub(iCommand,1,3) == "Off" then
Command = "Off"
Level = 0
Suffix = string.sub(iCommand,5)
elseif string.sub(iCommand,1,9) == "Set Level" then
Command = "Set Level"
Level = tonumber(string.sub(iCommand,11,13))
Suffix = string.sub(iCommand,11)
Suffix = string.sub(iCommand,5)
else
-- unknown command exiting
print ( "!### SwitchWhenDiff Unknown command for DeviceName:" ..DeviceName .."| iCommand:" .. iCommand .."|")
return
end
-- ensure we don't have any nil values to avoid errors
if Level == nil then
Level = 0
end
if Suffix == nil then
Suffix = ""
end
-- process information
print ( "!### SwitchWhenDiff DeviceName:" ..DeviceName .."| iCommand:" .. iCommand .."| Command:" .. Command .."| NewLevel:" ..tostring(Level) .. "| Currentstatus:" ..dstatus .."| value:" .. dvalue)
if dstatus == nil then
-- invalid switch found
print(" ==> Invalid switchname " .. DeviceName .. " (" .. ScriptName .. ")")
elseif (dstatus == Command and dstatus == "Set Level" and dvalue >= Level - 3 and dvalue <= Level + 3) then
-- no change so don't do anything
print(" ==> Nothing to change for Dimmer (within margins +/-3) " .. DeviceName .. " (" .. ScriptName .. ")")
elseif (dstatus == Command and dstatus ~= "Set Level") then
-- no change so don't do anything
print(" ==> Nothing to change for " .. DeviceName .. " (" .. ScriptName .. ")")
elseif (Command == "On" and dstatus == "Set Level" and dvalue >= 0 ) then
-- no change so don't do anything: request an On command for Dimmer and it is already have a status of "Set Level" and percentrage GT 0
print(" ==> Nothing to change for dimmer " .. DeviceName .. " (" .. ScriptName .. ")")
else
--
print(" ==> Set " .. DeviceName .. " to:" .. iCommand .. " inx=" .. #commandArray+1 .. " (" .. ScriptName .. ")")
commandArray[#commandArray+1]={[DeviceName] = iCommand}
end
return
end
commandArray = {}
tc=next(devicechanged)
v=tostring(tc)
if (v:sub(6,12) == 'Beneden') then
SwitchWhenDiff('LichtBenedenAchterkamer','Set Level 60')
SwitchWhenDiff('LichtBenedenVoorkamer','Set Level 40')
SwitchWhenDiff('LichtBenedenKeuken','On')
end
return commandArray
Jos
Re: Wildcard in devicechanged
Posted: Saturday 02 January 2016 15:13
by barbaar
Hi Jos, Thanks!
I'm still getting into an endless loop, but I'll have a look at that.
How do you use the global variable (??) 'ScriptName'?
Re: Wildcard in devicechanged
Posted: Saturday 02 January 2016 15:53
by jvdz
barbaar wrote:How do you use the global variable (??) 'ScriptName'?
My setup works as follows:
I have one "general_functions.lua" file containing a list of these type of general functions used in other LUA scripts.
At the top of each script I define ScriptName and set it to the scriptname running, then perform a dofile("/home/pi/domoticz/scripts/lua/general_functions.lua") which makes all standard functions available.
It then uses this variable in my print statements so I know from which base script the log entry is coming.
Any idea why it still keeps looping? The log entries in domoticz.log should help determining the reason and showing which device is changed/updated each time.
Jos
Re: Wildcard in devicechanged
Posted: Saturday 02 January 2016 20:35
by mischa
barbaar wrote:Right..
I want 3 lights on the ground floor to be turned on when one (of three) switches are turned. Two lights are attached to a Fibaro Dimmer. When the Fibaro dimmer is switched on, its status changes to 'Set Level 60', where 60 represents the dimlevel.
So I require the following (pseudo) LUA code:
Code: Select all
if (devicechanged['Licht Voorkamer'] == '[b]Set Level *[/b]' and otherdevices['Licht Achterkamer'] == 'Off' and otherdevices['Licht Keuken'] == 'Off') then
commandArray['Licht Achterkamer']='On'
commandArray['Licht Keuken']='On'
end
I tried changing the above code to
Code: Select all
if (devicechanged['Licht Voorkamer'] ~= nil ) then
if (devicechanged['Licht Voorkamer']:match("Set Level %a") and ...
However, there are two things I am unable to solve:
- Devicechanged needs to return a boolean, which it does not do in this code
- I don't understand how the stringmatching works in LUA
Any help is appreciated!
Ps:
Negatieve testing does not work
Code: Select all
if (devicechanged['Licht Voorkamer'] ~= 'Off"
will always switch on the light
The Devicechanged only returns a true boolean if the dimmer is at 100% or a false boolean when it is a 0%
I resolved this in the following way:
Code: Select all
commandArray = {}
if (otherdevices_svalues['Overloop 1e etage'] > '10 'and otherdevices['Trap'] == 'Off') then
commandArray['Trap']='Set Level 1'
elseif
(devicechanged['Overloop 1e etage'] == 'Off') then
commandArray['Trap']='Off'
end
return commandArray
So if my "Overloop 1e etage" light increases above the 10% dim level it set the level of my "Trap" lights to 1%
Re: Wildcard in devicechanged
Posted: Saturday 02 January 2016 21:44
by jvdz
mischa wrote:
The Devicechanged only returns a true boolean if the dimmer is at 100% or a false boolean when it is a 0%
You could also test whether a device changed by checking for nil to see whether it is present in the array or not:
Code: Select all
if devicechanged['Overloop 1e etage'] ~= nil then
...
end
Jos
Re: Wildcard in devicechanged
Posted: Saturday 02 January 2016 23:05
by mischa
Good tip, Going to try that.
Mischa
Re: Wildcard in devicechanged
Posted: Saturday 09 January 2016 17:43
by barbaar
jvdz wrote:
Any idea why it still keeps looping? The log entries in domoticz.log should help determining the reason and showing which device is changed/updated each time.
Jos
I'm sorry Jos, but I don't see why the script shouldn't loop..
The script will be triggered by a change in the devicetable. So turning on the LichtBenedenAchterkamer-switch will trigger the script and turn on the other two lightswitches..
But the other two lighswitches will also change the devicetable and thus trigger the script again. That's where the loop begins...
Or am I missing something?
Re: Wildcard in devicechanged
Posted: Saturday 09 January 2016 18:03
by jvdz
The script I provided should only update the devices in case they don't have that status yet, since it is using function SwitchWhenDiff().
So normally only the first time there is an action to change the device, unless the Set level 60 is setting a different level. The function check for a range from -3 to + 3, so in this case 57-63.
Jos
Re: Wildcard in devicechanged
Posted: Sunday 14 February 2016 11:29
by barbaar
I ended up with something different
I now monitor when the script was last executed, and prevent it from being executed multiple times within 5 seconds. Works and is simple!
Code: Select all
function timedifference(s)
print(s)
year = string.sub(s, 1, 4)
month = string.sub(s, 6, 7)
day = string.sub(s, 9, 10)
hour = string.sub(s, 12, 13)
minutes = string.sub(s, 15, 16)
seconds = string.sub(s, 18, 19)
t1 = os.time()
t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difference = os.difftime (t1, t2)
return difference
end
commandArray = {}
time = os.date("*t")
tc=next(devicechanged)
v=tostring(tc)
if (v:sub(6,12) == 'Beneden') then
PrevLightRun = uservariables['PrevLightRun']
i = otherdevices[v]
if ( i == 'On' or i == 'Set Level' or tonumber(otherdevices_svalues[v]) > 4 ) then
cmdVoorkamer = 'Set Level 40'
cmdAchterkamer = 'Set Level 60'
cmdKeuken = 'On'
elseif (i == 'Off' ) then
cmdVoorkamer = 'Off'
cmdAchterkamer = 'Off'
cmdKeuken = 'Off'
end
if (timedifference(PrevLightRun) > 5 ) then
commandArray['LichtBenedenVoorkamer'] = cmdVoorkamer
commandArray['LichtBenedenAchterkamer'] = cmdAchterkamer
commandArray['LichtBenedenKeuken'] = cmdKeuken
else
print("TOO SOON!!")
end
PrevLightRun = tostring(otherdevices_lastupdate[v])
commandArray['Variable:PrevLightRun'] = PrevLightRun
end
return commandArray