Presence simulation : pretty happy

Hello, got my Veralite one week ago, and I already got a pretty satisfying presence sim running, without too much hassle. I’m putting this here in case anyone is interested in this, and also, for anyone to review and tell me what I could have done better (especially in Lua, since I didn’t know this language 2 weeks ago) :wink:

For this, I use : 2 on/off modules, 1 light bulb socket module, a 4in1 sensor, and a 4keys mini remote, as well as a virtual switch plugin and a Chumby Radio.

The idea is the following :

  • The sim is running once every hour, all the time
  • When I leave the house, I use the 1st button of my remove to set the virtual switch to on (as well as giving me a feedback, by turning on then off one light).
  • When I come back, I use the second button of the remote to set the virtual switch off (and put the lights back on, so I can use them normally)
  • The sim checks this virtual switch and does nothing if it is not on
  • If it is on, it calculates a random uptime for the radio, and sends the corresponding requests (see below), but only on even hours
  • It also, depending on the luminosity, will calculate a random uptime for each light.
  • I log everything the sim is doing on the radio (again, see below).

Regarding the radio, the great thing about the Chumby is that it’s running on a mini-Unix, with a light http server. So, I developped some basic cgi scripts to accept http requests, and transform them into Chumby events. If anyone needs to know how to do that, let me know, I’d be glad to share.

The Veralite sim code :

local mRandom = math.random
local sFormat = string.format

-- Turn a light on or off
function TurnLight(ValueAndId)
  local value = string.sub(ValueAndId, 1, 1)
  local id = string.sub(ValueAndId, 3, string.len(ValueAndId))
  if (value == "0") then
    LogToRadio(sFormat("Sim:TurnLightOff:%s",id))
  else
    LogToRadio(sFormat("Sim:TurnLightOn:%s",id))
  end
  luup.call_action("urn:upnp-org:serviceId:SwitchPower1", "SetTarget", {newTargetValue = value}, tonumber(id))
end

-- Send an http request to Chumby
function CommandRadio(Cmd)
  local url=sFormat("%s,%s","http://192.168.1.102/cgi-bin/custom/control.cgi?Radio",Cmd)
  local status, result = luup.inet.wget(url, 10)
end

-- Log something to Chumby through http
function LogToRadio(Info)
  local url=sFormat("%s,%s","http://192.168.1.102/cgi-bin/custom/control.cgi?Log",Info)
  local status, result = luup.inet.wget(url, 10)
end

function StartRadio()
  LogToRadio("Sim:StartingRadio")
  -- Get out of night mode
  CommandRadio("DayMode")
  -- Start music
  CommandRadio("StartMusic")
  -- Set Volume to max
  CommandRadio("SetMaxVolume")
end

function StopRadio()
  LogToRadio("Sim:StoppingRadio")
  -- Set Volume to middle
  CommandRadio("SetMidVolume")
  -- Stop music
  CommandRadio("StopMusic")
  -- Night Mode
  CommandRadio("NightMode")
end

-- verify if Vswitch away is on, otherwise, we end here
local Away = luup.variable_get("urn:upnp-org:serviceId:VSwitch1", "Status", 6)
if (Away == "0") then
  luup.variable_set("urn:upnp-org:serviceId:VSwitch1", "Text1", "NoSim", 9)
  luup.variable_set("urn:upnp-org:serviceId:VSwitch1", "Text2", "Home", 9)
  return false
else
  luup.variable_set("urn:upnp-org:serviceId:VSwitch1", "Text1", "SimOk", 9)
  luup.variable_set("urn:upnp-org:serviceId:VSwitch1", "Text2", "Away", 9)
end

local tDevices = {
  {Name="Radio", id=0, DelayMin=1, DelayMax=10, TimeOnMin=5, TimeOnMax=45, Threshold=0 },
  {Name="Kitchen", id=4, DelayMin=1, DelayMax=45, TimeOnMin=1, TimeOnMax=10, Threshold=30 },
  {Name="LivRoom", id=3, DelayMin=1, DelayMax=45, TimeOnMin=1, TimeOnMax=10, Threshold=60 },
  {Name="Desktop", id=15, DelayMin=1, DelayMax=45, TimeOnMin=1, TimeOnMax=10, Threshold=100}
}

-- Force a poll of the 4in1 sensor before going on with the rest of the code
-- works, but does not wait for the end of the poll, so, useless
-- local nill, nill, jobid, nill = luup.call_action("urn:micasaverde-com:serviceId:HaDevice1", "Poll", {}, 11)

local CurrentLight = luup.variable_get("urn:micasaverde-com:serviceId:LightSensor1", "CurrentLevel", 11)
local CurrentTemp = luup.variable_get("urn:upnp-org:serviceId:TemperatureSensor1", "CurrentTemperature", 11)
LogToRadio(sFormat("LightLevel:%s",CurrentLight))
LogToRadio(sFormat("TempLevel:%s",CurrentTemp))

-- get current hour, radio will be on only if hour is even
local Radio=math.fmod(tonumber(os.date("%k")),2)
if (Radio == 0) then
  local Delay = mRandom(tDevices[1].DelayMin, tDevices[1].DelayMax)
  local TimeOn= mRandom(tDevices[1].TimeOnMin, tDevices[1].TimeOnMax)
  local trace=sFormat("Sim:Radio:in_%d_min:for_%d_min",Delay,TimeOn)
  Delay=Delay*60
  TimeOn=TimeOn*60
  luup.call_timer("StartRadio", 1, Delay, "", "")
  luup.call_timer("StopRadio", 1, Delay + TimeOn, "", "")
  LogToRadio(trace)
else
  LogToRadio("Sim:Radio:off")
end

-- Loop for the lights
for i = 2,4 do
  local trace=""
  if (tonumber(CurrentLight) < tDevices[i].Threshold) then
    local Delay = mRandom(tDevices[i].DelayMin, tDevices[i].DelayMax)
    local TimeOn= mRandom(tDevices[i].TimeOnMin, tDevices[i].TimeOnMax)
    trace=sFormat("Sim:Light%s(%d):in_%d_min:for_%d_min",tDevices[i].Name,tDevices[i].Threshold,Delay,TimeOn)
    Delay=Delay*60
    TimeOn=TimeOn*60
    luup.call_timer("TurnLight", 1 ,Delay, "", sFormat("1,%d",tDevices[i].id))
    luup.call_timer("TurnLight", 1 ,Delay + TimeOn, "", sFormat("0,%d",tDevices[i].id))

  else
    trace=sFormat("Sim:Light%s(%d):TooMuchLight",tDevices[i].Name,tDevices[i].Threshold)
  end
  LogToRadio(trace)
end

Now, I just need to find good values for the random delays and up times, as well as light levels. But other than that, it seems to work pretty well, here are some logs from a few tests today :

20130216-1715 : LightLevel:869
20130216-1715 : TempLevel:23
20130216-1715 : Sim:Radio:off
20130216-1715 : Sim:LightKitchen(50):TooMuchLight
20130216-1715 : Sim:LightLivRoom(50):TooMuchLight
20130216-1715 : Sim:LightDesktop(100):TooMuchLight
20130216-1911 : LightLevel:5
20130216-1911 : TempLevel:24
20130216-1911 : Sim:Radio:off
20130216-1911 : Sim:LightKitchen(30):in_36_min:for_2_min
20130216-1911 : Sim:LightLivRoom(60):in_38_min:for_3_min
20130216-1911 : Sim:LightDesktop(100):in_27_min:for_8_min
20130216-1938 : Sim:TurnLightOn:15
20130216-1946 : Sim:TurnLightOff:15
20130216-1947 : Sim:TurnLightOn:4
20130216-1949 : Sim:TurnLightOff:4
20130216-1949 : Sim:TurnLightOn:3
20130216-1952 : Sim:TurnLightOff:3
20130216-2011 : LightLevel:1
20130216-2011 : TempLevel:24
20130216-2011 : Sim:Radio:in_6_min:for_25_min
20130216-2011 : Sim:LightKitchen(30):in_22_min:for_9_min
20130216-2011 : Sim:LightLivRoom(60):in_22_min:for_9_min
20130216-2011 : Sim:LightDesktop(100):in_36_min:for_9_min
20130216-2017 : Sim:StartingRadio
20130216-2033 : Sim:TurnLightOn:4
20130216-2033 : Sim:TurnLightOn:3
20130216-2042 : Sim:StoppingRadio
20130216-2042 : Sim:TurnLightOff:4
20130216-2042 : Sim:TurnLightOff:3
20130216-2047 : Sim:TurnLightOn:15
20130216-2056 : Sim:TurnLightOff:15

The random numbers do not always look very random to me, but whatever, pretty happy with my purchase, and thanks to those who helped with my initial questions :slight_smile:

Regards.

That’s a nice code for a one week Vera owner.

Just for info, there is already plug-in for this purpose.
One is called “Vacation Ghost” and an other is called “Deus Ex machina”.

In the Vera web interface go to “APP” tab and “Install app” sub-tab.
After login, you will have a list of all available plugin (validated by MCV).

Thanks to the community contribution (unfortunalty I’m not familiar with coding so I can’t yet contribute), it’s plenty of plug-in for a wide range of purpose.

Have a nice WE… playing with your Vera :wink:

Thanks, I knew about Vacation Ghost, but it didn’t exactly fit my purposes, and anyway, I prefer to know what I’m doing and code myself if possible :wink:

Didn’t know about the other, will have a look :slight_smile:

Regards.

Hmmm, first bug : I connected today, while at work, to the UI interface, to change a setting on a device, and save the configuration.

What happens, apparently, in such a case, is that the Veralite restart the scenes (probably those on schedules) : this can be seen in the dashborad overview, as the next scene is suddenly exactly 1 hour from the time you saved.

In my case, this apparently happened while there were still call_timer waiting to be triggered : this caused the call to one “turn light off” to be cancelled, and as there was too much light the rest of the day, I never called another on/off, and so the light stayed on for the remaining of the day :frowning:

Problem solved (kinda) by forcing an “off” if there is too much light, but that’s a little bothering : it means that the Veralite breaks a running scene if you save the configuration meanwhile … not a very good behavior.

Regards.

Welcome to the Vera world.
That’s the dark side of the medal… Vera is not perfect but AFAIK it’s the more flexible, cost effective and autonomous box on the market, the community is also a big +.

Reagrding your issue, that’s one of the reason it’s generaly advised to use multiple scene instead of one “big” scene.

Hope it helps.

That’s why there are things like the Count Down Timer and the Program Logic Timer Switch plugins. They handle the persistent state of timer based operations … and survive a Vera Restart.

This is NOT the case for scene schedules and any arbitrary timer that you launch from luup code.

If you call a timed function from luup code … you need to ask your self:
Is it OK if the timed function never happens ? If the answer is NO you need to write or use a plugin that will guarantee the operation.

If the Answer is NO … even if Vera fails … then you need dedicated hardware solution.

Thanks for the clarifications :slight_smile:

Regards.