Scen aktiverad på tid i lua
Ok, insåg inte att HC2 använder Yahoo weather, så det går lika bra att använda api/weather (fördelen med att anropa det själv är att man även kan få forecasts... - och jag vet inte hur ofta HC2 frågar Yahoo...)
Koden blir iallafall lite enklare.
Obs, att nu stängs markiserna om det är dåligt väder eller det blåser för hårt... men den reagerar förmodligen inte så snabbt på vind då Yahoo weather inte uppdateras så ofta. Nu pollar vi det varannan minut... Ofta har markiser en liten propeller som trigger markisen att rulla in om det kommer en vindby. En egen z-wave vindmätare skulle kanske kunna fixa det.
Koden blir iallafall lite enklare.
Obs, att nu stängs markiserna om det är dåligt väder eller det blåser för hårt... men den reagerar förmodligen inte så snabbt på vind då Yahoo weather inte uppdateras så ofta. Nu pollar vi det varannan minut... Ofta har markiser en liten propeller som trigger markisen att rulla in om det kommer en vindby. En egen z-wave vindmätare skulle kanske kunna fixa det.
Code: Select all
--[[
%% properties
%% events
5 CentralSceneEvent
%% globals
--]]
--[[
-- EventRunnerLight. Single scene instance framework
-- Copyright 2018 Jan Gabrielsson. All Rights Reserved.
-- Email: jan@gabrielsson.com
--]]
_version = "1.1"
osTime = os.time
osDate = os.date
_debugFlags = { post=false,invoke=false,triggers=false,dailys=false,timers=false,rule=false,fibaro=true,fibaroGet=false }
if dofile then dofile("EventRunnerDebug.lua") end -- Support for running off-line on PC/Mac
---- Single scene instance, all fibaro triggers call main(sourceTrigger) ------------
function printf(...) fibaro:debug(string.format(...)) end
-- Table how much to open scheds depending on time and month, other time values are interpolated
SouthValue = {
Jan = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Feb = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Mar = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Apr = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
May = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Jun = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Jul = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Aug = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Sep = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",99}},
Oct = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Nov = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Dec = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
}
WestValue = {
Jan = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Feb = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Mar = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Apr = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
May = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Jun = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Jul = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Aug = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Sep = {{"09:00",99},{"10:00",99},{"11:00",99},{"11:30",99},{"12:30",99},{"13:00",99},{"14:00",85},{"15:00",60},{"17:00",45},{"18:00",99},{"19:00",99},{"20:00",99}},
Oct = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Nov = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
Dec = {{"09:00",80},{"10:00",65},{"11:00",50},{"11:30",33},{"12:30",50},{"13:00",65},{"14:00",80},{"15:00",100}},
}
local houseSheds = {
--South
{name="Matsal",start="09:00",stop="18:00",id=491,tab=SouthValue}, --Matsal
{name="Kök syd",start="09:00",stop="18:00",id=485,tab=SouthValue}, --Kök syd
{name="Sveas Rum",start="09:00",stop="18:00",id=497,tab=SouthValue}, --Sveas Rum
{name="Augusts Rum",start="09:00",stop="18:00",id=500,tab=SouthValue}, --Augusts Rum
--West
{name="Vardagsrum Nere",start="09:00",stop="18:00",id=488,tab=WestValue}, --Matsal
{name="Bibliotek",start="09:00",stop="18:00",id=482,tab=WestValue}, --Kök syd
{name="Lekrum Väst",start="09:00",stop="18:00",id=506,tab=WestValue}, --Vardagsrum Uppe
--Vardagsrum Uppe
{name="Vardagsrum Uppe",start="09:00",stop="18:00",id=503,tab=WestValue} --Vardagsrum Uppe
}
function shedsValue(time,shed) -- Calculates how much sheds should be open given time and month
local mt,stop,start = shed.tab[osDate("%b")]
for _,t in ipairs(mt) do if t[1] <= time then start = t else break end end
start = start or mt[1][1] -- lowest/equal before time or the first value
for _,t in ipairs(mt) do if t[1] >= time then stop = t break end end
stop = stop or mt[#mt][1] -- highest/equal after time or the last value
if time < mt[1][1] or time>mt[#mt][1] then return 0 end -- Time outside min & max returns 0
local x1,y1,x2,y2 = toTime(start[1]),start[2],toTime(stop[1]),stop[2]
return x1==x2 and y1 or math.floor((y2-y1)/(x2-x1)*(toTime(time)-x1)+y1+0.5) -- linear extrapolation for times not in table
end
local keepShedsClosed = false
local goodWeather = {[30]=true,[36]=true,[34]=true,[32]=true,[28]=true} -- conditions when sheds should be open
local maxWind = 25.0
function main(sourceTrigger)
local event = sourceTrigger
if event.type=='schedule' then
local shed = event.shed
local value = shedsValue(osDate("%H:%M"),shed)
local name,id = event.shed.name,event.shed.id
if not keepShedsClosed then
printf("Setting %s with id %s to value %s",name,id,value)
fibaro:call(id,"setValue",value)
else
printf("Keeping %s with id %s closed",name,id)
end
if osDate("%H:%M") > shed.stop then time = "n/"..shed.start else time = "+/00:30" end
printf("Scheduling %s for %s",name,osDate("%X",toTime(time)))
post(event,time)
end
-- setUp initial posts of daily events
if event.type == 'autostart' or event.type == 'other' then
local now,time = osDate("%H:%M")
for _,shed in ipairs(houseSheds) do
time = "t/"..osDate("%H:%M:%S")
if now <= shed.start or now > shed.stop then time = "n/"..shed.start end
printf("Scheduling %s for %s",shed.name,osDate("%X",toTime(time)))
post({type='schedule', shed=shed},time)
end
post({type='checkWeather'}) -- and also start checking weather every 2 minutes
end
if event.type=='checkWeather' then
local weather = api.get("/weather")
local wind = weather.Wind
local wcode = weather.ConditionCode
if wind <= maxWind and goodWeather[wcode] then -- good weather, keep sheds open
post({type='closeSheds', close=false}) -- open sheds
else
post({type='closeSheds', close=true}) -- close sheds
end
post(event,"+/00:02") -- check weather every other minute
end
if event.type == 'closeSheds' and event.close and not keepShedsClosed then -- close all Sheds
keepShedsClosed = true
for _,shed in ipairs(houseSheds) do
fibaro:call(shed.id,"setValue",0)
end
elseif event.type == 'closeSheds' and (not event.close) and keepShedsClosed then -- restore all sheds
local now = osDate("%H:%M") -- open sheds again
keepShedsClosed = false
for _,shed in ipairs(houseSheds) do
fibaro:call(shed.id,"setValue",shedsValue(now,shed))
end
end
if event.type=='event' and event.event.data.deviceId==5 then -- Toggle sheds at keypress (any)
post({type='sheds', close=(not keepShedsClosed)})
end
end -- main()
------------------------ Framework, do not change ---------------------------
-- Spawned scene instances post triggers back to starting scene instance ----
local _trigger = fibaro:getSourceTrigger()
local _type, _source = _trigger.type, _trigger
local _MAILBOX = "MAILBOX"..__fibaroSceneId
if _type == 'other' and fibaro:args() then
_trigger,_type = fibaro:args()[1],'remote'
end
function _midnight() t=osDate("*t"); t.min,t.hour,t.sec=0,0,0; return osTime(t) end
function hm2sec(hmstr)
local sun,offs = hmstr:match("^(%a+)([+-]?%d*)")
if sun and (sun == 'sunset' or sun == 'sunrise') then
hmstr,offs = fibaro:getValue(1,sun.."Hour"), tonumber(offs) or 0
end
local h,m,s = hmstr:match("(%d+):(%d+):?(%d*)")
return h*3600+m*60+(tonumber(s) or 0)+(offs or 0)*60
end
function toTime(time)
if type(time) == 'number' then return time end
local p = time:sub(1,2)
if p == '+/' then return hm2sec(time:sub(3))+osTime() -- Plus now
elseif p == 'n/' then
local t1 = _midnight()+hm2sec(time:sub(3))-osTime() -- Next
return (t1 > 0 and t1 or t1+24*60*60)+osTime()
elseif p == 't/' then return _midnight()+hm2sec(time:sub(3)) -- Today
else return hm2sec(time) end
end
function post(event, time) return setTimeout(function() main(event) end,((time and toTime(time)-osTime()) or 0)*1000) end
function cancel(ref) if ref then clearTimeout(ref) end return nil end
function postRemote(sceneID,event) event._from=__fibaroSceneId; fibaro:startScene(sceneID,{json.encode(event)}) end
---------- Producer(s) - Handing over incoming triggers to consumer --------------------
if ({property=true,global=true,event=true,remote=true})[_type] then
local event = type(_trigger) ~= 'string' and json.encode(_trigger) or _trigger
local ticket = string.format('<@>%s%s',tostring(_source),event)
repeat
while(fibaro:getGlobal(_MAILBOX) ~= "") do fibaro:sleep(100) end -- try again in 100ms
fibaro:setGlobal(_MAILBOX,ticket) -- try to acquire lock
until fibaro:getGlobal(_MAILBOX) == ticket -- got lock
fibaro:setGlobal(_MAILBOX,event) -- write msg
fibaro:abort() -- and exit
end
---------- Consumer - Handing over incoming triggers to main() --------------------
local function _poll()
local l = fibaro:getGlobal(_MAILBOX)
if l and l ~= "" and l:sub(1,3) ~= '<@>' then -- Something in the mailbox
fibaro:setGlobal(_MAILBOX,"") -- clear mailbox
post(json.decode(l)) -- and "post" it to our "main()" in new "thread"
end
setTimeout(_poll,250) -- check every 250ms
end
---------- Startup --------------------
if _type == 'autostart' or _type == 'other' then
printf("Starting EventRunnerLite demo")
if not _OFFLINE then
if not string.find(json.encode((api.get("/globalVariables/"))),"\"".._MAILBOX.."\"") then
api.post("/globalVariables/",{name=_MAILBOX})
end
fibaro:setGlobal(_MAILBOX,"")
_poll() -- start polling mailbox
main(_trigger)
else
collectgarbage("collect") GC=collectgarbage("count")
_System.runOffline(function() main(_trigger) end)
end
end