Running LUA from a PLEG Condition - Slowly Dimming a light

Hello All -

I have a situation where I need to slowly dim a light over a 30 minute period.

  1. Turn light on 100%
  2. Slowly dim in given intervals (e.g. 1 minute)
  3. Down to a configurable value 0%, 20%, etc

I found and cobbled together some LUA code to do this because I couldn’t figure out how to do it in PLEG. However, I still wanted to use PLEG conditions as scenes don’t give me enough flexibility (IMO).

Question: When PLEG runs LUA instead of a direct action on a device, does all other condition/action assessments hold until that LUA is complete?

I’m guessing that’s the case. Unfortunately, the code I’m using loops for 30 minutes and I believe that’s holding up PLEG from doing my normal stuff.

Any suggestions?

Have you looked at the Ramping example?

[url=http://forum.micasaverde.com/index.php/topic,51953.0.html][size=2]http://forum.micasaverde.com/index.php/topic,51953.0.html[/size][/url]

tbully,

Here is some Luup code I use to slow dim the lights in our parrot room. (it helps simulate natural sunset for them and uses a variable step value based on the actual sunset time and 9:00pm - their bedtime). Its a 3% drop over 20 loop cycles with each loop cycle 1/20th of the total minutes between sunset (+/- an offset) and 9pm. Theres a lot of extra stuff going on here with pushing variables out to V-Container and bypasses if the lights fall below a certain level that you could trim out, but the core routine works flawlessly. I have it running on Alt-UI on a Raspberry Pi3 but you could insert the code into a scene or PLEG at your discretion. Feel free to ask about variable namers if you can’t figure out what they do. I’d be glad to help.

var_txt = "Bird Room Slow Dim Lights"
var_txt = "ALTUI: " .. var_txt
var_url = require "socket.url"
var_txt = var_url.escape(var_txt)
luup.inet.wget ("http://192.168.0.11/port_3480/data_request?id=lr_EventWatcher&event=" .. var_txt)

varMin = 5
varMax = 65
varEWDev = 6
varLoopCnt = 0
varDimStep = (varMax-varMin)/20
varDevice1 = 10052
varDevice2 = 10053
varDimLevel1 = varMax
varDimLevel2 = luup.variable_get("urn:upnp-org:serviceId:Dimming1","LoadLevelStatus",varDevice2)

varLupSS = luup.sunset()
varLuaSST = os.date("*t", varLupSS)
varSunsetTime = varLuaSST.hour * 60 + varLuaSST.min
varSSTHr = math.floor(varSunsetTime/60)
varSSTMin = varSunsetTime-(varSSTHr*60)
varSSTMin = string.format("%02d",varSSTMin)
varSST = varSSTHr .. ":" .. varSSTMin
varSSoffset = 30

varStartTime = varSunsetTime - varSSoffset
varSTHr = math.floor(varStartTime/60)
varSTMin = varStartTime-(varSTHr*60)
varSTMin = string.format("%02d",varSTMin)
varST = varSTHr .. ":" .. varSTMin

varEndTime = "21:00"
varETHr = tonumber( varEndTime:sub( varEndTime:find("%d+") ) )
varETMin = tonumber(varEndTime:sub(-2))
varEndTime = varETHr * 60 + varETMin

varDelayPeriod = ((varEndTime - varStartTime)*3)
varCurDate = os.date("%m/%d/%Y")
varHumanTime = os.date("%m/%d/%Y %H:%M:%S")
varCurTime = os.date("*t")
varCurrentTime = varCurTime.hour * 60 + varCurTime.min

function DimLights()
	varLoopCnt = varLoopCnt + 1
	varCurTime = os.date("*t")
	varCurTm = os.time()
	varCurrentTime = varCurTime.hour * 60 + varCurTime.min
	varNextAction = (os.date("%m/%d/%Y %H:%M:%S",varCurTm + varDelayPeriod))
	varHumanTime = os.date("%m/%d/%Y %H:%M:%S")
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName3","Next Action",varEWDev)
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName4","Delay:Step:Loop",varEWDev)
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName5","Max:Min:Sec",varEWDev)
	if varStartTime <= varCurrentTime and varCurrentTime <= varEndTime then
		varDimLevel2 = luup.variable_get("urn:upnp-org:serviceId:Dimming1","LoadLevelStatus",varDevice2)
		varDimLevel2 = varDimLevel2 - varDimStep
		if varDimLevel2 < 0 then varDimLevel2 = 0 end
		if (varDimLevel2 == 0 and varLoopCnt >= 16) then 
			var_txt = "Bird Room Slow Dim Aborted"
			var_txt = "ALTUI: " .. var_txt
			var_txt = var_url.escape(var_txt)
			luup.inet.wget ("http://192.168.0.11/port_3480/data_request?id=lr_EventWatcher&event=" .. var_txt)
			luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName2","Aborted at ",varEWDev)
			luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable2", varHumanTime,varEWDev)
			luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable3","",varEWDev)
			return false
		end
		if varDimLevel2 > varMin then
			luup.call_action("urn:upnp-org:serviceId:Dimming1","SetLoadLevelTarget",{ newLoadlevelTarget=varDimLevel2 },varDevice2)
			luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName2","This Action",varEWDev)
			var_txt = "Bird Room Lights to " .. varDimLevel2 .. "%" .. ", #" .. varLoopCnt .. " @ " .. varDelayPeriod .." sec."
			var_txt = "ALTUI: " .. var_txt
			var_txt = var_url.escape(var_txt)
			luup.inet.wget ("http://192.168.0.11/port_3480/data_request?id=lr_EventWatcher&event=" .. var_txt)
		else
		    if varDimLevel2 < varMin then varDimLevel2 = varMin end
		    luup.call_action("urn:upnp-org:serviceId:Dimming1","SetLoadLevelTarget",{ newLoadlevelTarget=varMin },varDevice2)
			luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName2","This Bypass",varEWDev)
			var_txt = "Bird Room Lights bypassed at " .. varDimLevel2 .. "%" .. " : " .. varDelayPeriod.." sec."
			var_txt = "ALTUI: " .. var_txt
			var_txt = var_url.escape(var_txt)
			luup.inet.wget ("http://192.168.0.11/port_3480/data_request?id=lr_EventWatcher&event=" .. var_txt)
		end
		luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable2", varHumanTime,varEWDev)
		luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable3",varNextAction,varEWDev)
		luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable4",varDelayPeriod/60 .. " min : " .. varDimStep .. "% : " .. varLoopCnt,varEWDev)
		luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable5",varMax .. " : " .. varMin .. " : " .. varDelayPeriod,varEWDev)
		luup.sleep (2000)
		luup.call_timer("DimLights",1,varDelayPeriod, "", "")
	else
		luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName2","Final Action",varEWDev)
		luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName3","End Dim Loop",varEWDev)
		luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable3",varHumanTime,varEWDev)
		var_txt = "End Bird Room Lights Dim"
		var_txt = "ALTUI: " .. var_txt
		var_txt = var_url.escape(var_txt)
		luup.inet.wget ("http://192.168.0.11/port_3480/data_request?id=lr_EventWatcher&event=" .. var_txt)
		luup.sleep (2000)
		return false
	end
	return false
end

StartDelaySecs = 5
if varStartTime <= varCurrentTime and varCurrentTime <= varEndTime then
	if varDimLevel2 == 0 then
		varDimLevel2 = varMax
	end
	varCurTm = os.time()
	varCurTime = os.date("*t")
	varCurrentTime = varCurTime.hour * 60 + varCurTime.min
	varNextAction = (os.date("%m/%d/%Y %H:%M:%S",varCurTm + varDelayPeriod))
	varHumanTime = os.date("%m/%d/%Y %H:%M:%S")
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName2","Started at ",varEWDev)
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable2",varHumanTime,varEWDev)
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName3","Next Action ",varEWDev)
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable3",varNextAction,varEWDev)
	luup.call_timer("DimLights",1,StartDelaySecs, "", "")
else
	luup.sleep (2000)
        luup.variable_set("urn:upnp-org:serviceId:VContainer1","VariableName3","Bypassed at ",varEWDev)
	luup.variable_set("urn:upnp-org:serviceId:VContainer1","Variable3",varHumanTime,varEWDev)
end

Thanks for the PLEG example! I’ll have to read that carefully and circle-back.

The LUA also makes sense to me. The LUA I have works fine (although yours is more eloquent). I’m more concerned with how LUA is executed by PLEG as it appears it holds up all condition analysis (and logic actions) until the routine is finished. Since my routine runs for 30 minutes, I believe it essentially holds up PLEG.

So reading over this, it’s not clear to me how they dim the light using the “LightLevel-1” logic. I assume it has something to do with using Logic Expressions in the action but I’ve never done that. Any pointers? This may be a better route than LUA for me…

Input
LightLevel Current Light Level

Schedule
NextStepTimer On - Self Trigger, Off After 30 sec interval
OffTimer On - Self Trigger, Off after 30 minutes

Condition
Start What every you use to start this (i.e. some Multi-Switch turns on
KeepGoing (Start; !NextStepTimer) and !NextStepTimer and (LightLevel > 5) and (LightLevel <= 25)
AllOff (Start;OffTimer) and (LightLevel == 5)

Actions:
Start - Set light to 25 % and trigger NextStepTimer with an interval of 30 and trigger OffTimer with an interval of 30:00
KeepGoing Set Light to {(LightLevel - 1}} and trigger NextStepTimer with an interval of 30
AllOff Turn Off Light

See the PLEG Basics document, where it indicates how “{” are used to pass properties into action logic. Discussed on page 14, but also later in the document…
http://forum.micasaverde.com/index.php/topic,21603.0.html

I’ve referenced that doc countless times over the years and never picked up on that one!

Thanks for the reminder, wilme.