Wildcard in devicechanged

Moderator: leecollings

Post Reply
barbaar
Posts: 56
Joined: Wednesday 24 December 2014 16:01
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Wildcard in devicechanged

Post 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
simonrg
Posts: 329
Joined: Tuesday 16 July 2013 22:54
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.8807
Location: North East England
Contact:

Re: Wildcard in devicechanged

Post 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.
Raspberry Pi 2 B - 2A@5V PSU - Raspbian + Domoticz + RFXtrx(89), LightwaveRF House(dimmers, sockets, wireless/mood switches), Owl CM113, 4 LaCross Temp / Humidity Sensors, 4 Siemens PIR, Smappee, Solaredge, ESP8266
barbaar
Posts: 56
Joined: Wednesday 24 December 2014 16:01
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Wildcard in devicechanged

Post 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..
User avatar
jvdz
Posts: 2334
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Wildcard in devicechanged

Post 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
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
barbaar
Posts: 56
Joined: Wednesday 24 December 2014 16:01
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Wildcard in devicechanged

Post 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'?
User avatar
jvdz
Posts: 2334
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Wildcard in devicechanged

Post 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
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
mischa
Posts: 74
Joined: Tuesday 07 April 2015 20:32
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.8872
Location: Heerhugowaard, The Netherlands
Contact:

Re: Wildcard in devicechanged

Post 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%
Pi 2 - Pi 1 - Razzbery 2.0 - Fibaro FGD-211 - Fibaro FGD-212 - Fibaro FGRGBWM-441 (RGBW Module) - Fibaro FGBS321 (Universal Switch) - FGWPF-102 - TBK Home TZ67-G - Synology DS1515+ - Esp Easy (with wemos D1 mini)
User avatar
jvdz
Posts: 2334
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Wildcard in devicechanged

Post 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
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
mischa
Posts: 74
Joined: Tuesday 07 April 2015 20:32
Target OS: Raspberry Pi / ODroid
Domoticz version: 3.8872
Location: Heerhugowaard, The Netherlands
Contact:

Re: Wildcard in devicechanged

Post by mischa »

Good tip, Going to try that.

Mischa
Pi 2 - Pi 1 - Razzbery 2.0 - Fibaro FGD-211 - Fibaro FGD-212 - Fibaro FGRGBWM-441 (RGBW Module) - Fibaro FGBS321 (Universal Switch) - FGWPF-102 - TBK Home TZ67-G - Synology DS1515+ - Esp Easy (with wemos D1 mini)
barbaar
Posts: 56
Joined: Wednesday 24 December 2014 16:01
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Wildcard in devicechanged

Post 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?
User avatar
jvdz
Posts: 2334
Joined: Tuesday 30 December 2014 19:25
Target OS: Raspberry Pi / ODroid
Domoticz version: 4.107
Location: Netherlands
Contact:

Re: Wildcard in devicechanged

Post 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
New Garbage collection scripts: https://github.com/jvanderzande/GarbageCalendar
barbaar
Posts: 56
Joined: Wednesday 24 December 2014 16:01
Target OS: Raspberry Pi / ODroid
Domoticz version:
Contact:

Re: Wildcard in devicechanged

Post 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
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest