Lightning in corridor using motion detection and other dimming rules

Hi,

Just installed my first batch of Z-Wave components & Vera3.
So far I’m quite happy with my choice! installation is going smoothly.
UI5 is not what we can call “user friendly”… however, I really appreciate the fact that you can develop/script + root access + that it can run without depending on central servers (these were the selling points).

I have just completed my first LUUP scene to control lightning in my corridor. As I’m really new to this stuff, I would really appreciate a quick review/comments/suggestions! :wink:

Goal:

  • corridor lights can be controlled with two mono-stable switches (one at each end of the corridor) and can be dimmed (wiring done using a Fibaro FGD221 module)
  • a motion sensor (Aeotech 4-in-1) will turn the lights on + adjust dimming intensity according to outside luminosity (currently based on luup.is_night(), may change this later for an outside sensor) and intensity of the dimmer in my living room (in order to balance relative luminosity)
    . when living room lights are OFF during night, set corridor lights to 15% (night time case)
    . when living room lights are OFF during daytime, don’t turn corridor lights ON (day time case)
    . when living room lights are ON during night, set corridor lights to 2/3 of the living room dimming intensity & no less than 15% (evening case)
    . when living room lights are ON during day, set corridor lights to the same intensity as the living room (end of day case)
    . lights will stay ON for at least 30 seconds and as long as motion is detected (Aeotech sensor timeout is also set to 30 seconds)
    . when someone manually changes the dimming intensity in the corridor, don’t turn lights ON/OFF automatically (manual override case)

Those rules are just a starting point and will be probably adjusted.

Here goes the corresponding working LUUP code for the single scene that manages all of this:

[tt]
local dimmer_device = 18 – corridor dimmer
local sensor_device = 19 – corridor motion sensor
local reference_dimmer_device = 11 – living room dimmer

local target_dimming = 20 – dimming %
local min_timeout = 30 – seconds
local retry_timeout = 3 – seconds

function calc_dynamic_dimming()
local reference_dimmer_state = luup.variable_get(“urn:upnp-org:serviceId:SwitchPower1”, “Status”, reference_dimmer_device)
if (reference_dimmer_state == “0”) then
if (luup.is_night()) then
target_dimming = 15 – 15% during night
else
target_dimming = 0 – stay off during daytime when reference dimmer is off
end
else
local reference_dimmer_load = luup.variable_get(“urn:upnp-org:serviceId:Dimming1”, “LoadLevelStatus”, reference_dimmer_device)
reference_dimmer_load = tonumber(reference_dimmer_load)
if (luup.is_night()) then
target_dimming = math.floor(reference_dimmer_load * 2 / 3) – 2/3rd of reference dimmer during night
if (target_dimming < 15) then
target_dimming = 15 – but no less than 15%
end
else
target_dimming = reference_dimmer_load – copy reference dimmer value during day
end
end
end

function switch_on()
luup.log("Switching dimmer ON to " … target_dimming)
luup.call_action(“urn:upnp-org:serviceId:Dimming1”, “SetLoadLevelTarget”, { newLoadlevelTarget = “” … target_dimming }, dimmer_device)
luup.call_delay(‘switch_off’, min_timeout)
end

function switch_off()
local current_dimmer_load = luup.variable_get(“urn:upnp-org:serviceId:Dimming1”, “LoadLevelStatus”, dimmer_device)
if (current_dimmer_load == (“” … target_dimming)) then
if (luup.variable_get(“urn:micasaverde-com:serviceId:SecuritySensor1”, “Tripped”, sensor_device) == “1”) then
luup.log(“Not switching dimmer off yet, sensor is still tripped. Retrying in " … retry_timeout … " seconds”)
luup.call_delay(‘switch_off’, retry_timeout)
else
luup.log(“Switching dimmer OFF”)
luup.call_action(“urn:upnp-org:serviceId:SwitchPower1”, “SetTarget”, { newTargetValue = “0” }, dimmer_device)
end
else
luup.log("Not switching dimmer off, load level has changed from " … target_dimming … " to " … current_dimmer_load)
end
end

if (reference_dimmer_device) then
calc_dynamic_dimming()
end

if (target_dimming > 0) then
switch_on()
return true
else
return false
end
[/tt]

Welcome!

How do you trigger the scene, based on a shedule like “every minute”?

For me the vera UI5 is only a configuration UI, for all controls I use Apps on Smartphones or remotes (Aeon Labs MiniMote).

Do you have considered using the plugin PLEG? I just moved over from generating very complex scenes with a lot of code to doing all my logics in PLEG. The conclusion so far is that I wish I would have done this step earlier and that I am now able to create very complex logics within minutes.

Hi!

Thanks :slight_smile:
I also control everything using my android phone/tablet (and I also have a couple of minimotes, but I guess they will find most of their use with the children).

The scene is triggered directly by the motion sensor (when tripped).
It would have been better to have the motion sensor directly command the dimmer without going through the Vera, but I don’t see how to update the target dimming value without actually turning lights ON (ie, ideally I would have a Vera scene updating the dimming value regularly only, and leave the ON/OFF command directly to the motion sensor & wall switches).

I didn’t investigate PLEG yet. Working with software during my day job, I know that software dependencies can hurt, esp. when you don’t understand how they work :smiley: So for now I prefer dirtying my hands to get familiar with LUUP :wink: But I will definitely check this too!

Wow! First post and it’s a complex logic LUUP script that works perfectly.

Good job. Thank you for sharing.

That is what I was thinking too! Already guessed that you must be working with software ;D

Thanks guys :wink:

I was wondering: is there any best practice for maintaining the list of devices IDs? (instead of hard coding them in each LUUP scene)
Maybe a list of constants in the startup file?

Followup: just succeeded in having the Aeotec 4-in-1 motion sensor directly command the Fibaro FGD 221 dimmer power state to the right dimming level without having to ask the Vera in real time

Indeed, my goal was to reduce latency & increase reliability after a motion has been detected (i.e., by removing the Vera from the real time process).

How it works:

  1. The sensor directly tells the dimmer to go ON when motion is detected (easy: parameter 5 = 1, and add the dimmer to it’s Association Group 1)
  2. The Vera regularly updates the wanted dimming level (without turning the dimmer ON, obviously): dimming level calculation and update is performed in a scene which is run at startup + right after sunrise/sunset + immediately when the living room dimming level changes

This is possible thanks to parameter 40 of the Fibaro FGD 221: this sets the “memorized” dimming level. That’s great: one just need to change this parameter when needed… except that there’s no LUUP call that I know of that can change the parameter value and push it to the device.
Some Googling & Z-Wave debugging later, problem solved with a low level Z-Wave call:

[tt] luup.call_action(“urn:micasaverde-com:serviceId:ZWaveNetwork1”,“SendData”,{Node=“” … luup.devices[dimmer_device].id, Data="112 4 40 1 " … target_dimming}, 1 ) – set variable 40 with 1 byte value = target_dimming[/tt]

So, the LUUP scene becomes:

[tt]
local dimmer_device = 18 – corridor dimmer
local reference_dimmer_device = 11 – living room dimmer

function updateCorridorTargetDimming()
local target_dimming = 0
local reference_dimmer_state = luup.variable_get(“urn:upnp-org:serviceId:SwitchPower1”, “Status”, reference_dimmer_device)
if (reference_dimmer_state == “0”) then
if (luup.is_night()) then
target_dimming = 15 – 15% during night
else
target_dimming = 50 – 50% during daytime
end
else
local reference_dimmer_load = luup.variable_get(“urn:upnp-org:serviceId:Dimming1”, “LoadLevelStatus”, reference_dimmer_device)
reference_dimmer_load = tonumber(reference_dimmer_load)
if (luup.is_night()) then
target_dimming = math.floor(reference_dimmer_load * 2 / 3) – 2/3rd of reference dimmer during night
if (target_dimming < 15) then
target_dimming = 15 – but no less than 15%
end
else
target_dimming = reference_dimmer_load – copy reference dimmer value during day
end
end

luup.log("Changing corridor target dimming to " .. target_dimming)

luup.call_action("urn:micasaverde-com:serviceId:ZWaveNetwork1","SendData",{Node="" .. luup.devices[dimmer_device].id, Data="112 4 40 1 " .. target_dimming}, 1 ) -- set variable 40 with 1 byte value = target_dimming

end

if not watching_corridor_reference_dimmer then
watching_corridor_reference_dimmer = true
luup.log(“Watching living room dimmer load”)
luup.variable_watch(‘updateCorridorTargetDimming’, ‘urn:upnp-org:serviceId:Dimming1’, ‘LoadLevelStatus’, reference_dimmer_device)
end

updateCorridorTargetDimming()
return true[/tt]

Works great.
Except that I forgot one rule: I don’t want the motion sensor to trigger the corridor lights at day time (except if the living room is lit). And the only way I can think of to deal with this rule would be to reconfigure the sensor (set parameter 4 to 0 to disable motion detection, 1 to reenable), using the same low level Z-Wave command trick. However, this is a battery powered sensor that doesn’t wake up very often to catch its configuration update… not very convenient.

So, I’m back to the first solution for now, leaving that one for reference!