Jag har en grundfilosofi, och det är att min MHA (Magiska Hem Automation) skall klara sig stand-alone - dvs om internet faller så skall systemet i alla fall klara sig utan yttre kontakt. En grundläggande del där är att klara av helger och semester utan att behöva ladda ned någon google calender (som iofs vore nice, men utan plug in i HC2 är det rätt omöjligt med de krav jag har). Någon dag kanske jag skriver en plug-in för Google, om det nu någonsin blir av
I vilket fall, utöver stand-alone, så är alla mina scener i praktien drivna av antingen globala variabler, eller av sensorer (och/eller deras värde) - eller en kombo av detta. Någon direkt tidskoppling finns inte, men vid vissa tider så ställs TOD om.
Följande variabler finns, och dess möjliga värden:
- TOD = Dag, Kväll, Middag, Morgon, Natt, TurnDown
Dagsljus = Ljust, Mörkt
Hemma = Hemma, Borta
Projektor = På, Av
WorkToday = False, True
WorkTomorrow = False, True
Code: Select all
--[[
%% autostart
%% properties
%% globals
--]]
-- Functions to calculate Eastern and vacation days
function Vacation_Days(dateForCheck)
-- Ange vilka datum som skall anses som lediga datum
local LedigaDatum = { "2014-05-02" , "2014-05-30" }
local datum
for z,datum in pairs(LedigaDatum) do
TestDatum = os.date("*t", os.time({year = tonumber(string.sub(datum,1,4)), month = tonumber(string.sub(datum,6,7)), day = tonumber(string.sub(datum,9))}))
if ( TestDatum.year == dateForCheck.year and TestDatum.month == dateForCheck.month and TestDatum.day == dateForCheck.day ) then
return true
end
end
return false
end
function Holidays_CalculateEaster(year)
golden = (year % 19) + 1
c = math.floor(year/400) + math.floor(8*(math.floor(year/100)+11)/25) - math.floor(year/100)
s = (11 * golden + c) % 30
if (s < 0) then
s = s + 30
end
pfm = os.time{year=year, month=4, day=19} - s * 24 * 60 * 60
if (pfm == os.time{year=year, month=4, day=19}) then
pfm = pfm - 24 * 60 * 60
elseif (pfm == os.time{year=year, month=4, day=18} and golden > 11) then
pfm = pfm - 24 * 60 * 60
end
sunday = pfm + (7 - tonumber(os.date("%w", pfm))) * 24 * 60 * 60
friday = sunday - 2 * 24 * 60 * 60
return {year, tonumber(os.date("%m", friday)), tonumber(os.date("%d", friday))}
end
function WorkDay(dateToCheck)
local easterDay
local returnValue
returnValue = true
-- Indatum är en lördag eller Söndag
if ( dateToCheck.wday == 1 or dateToCheck.wday == 7 ) then
returnValue = false
-- Indatum är nationaldag
elseif ( dateToCheck.month == 6 and dateToCheck.day == 6 ) then
returnValue = false
-- Indatum är Nyårsdag eller trettondag
elseif ( dateToCheck.month == 1 and (dateToCheck.day == 1 or dateToCheck.day == 6 ) ) then
returnValue = false
-- Indatum är 1:a maj
elseif ( dateToCheck.month == 5 and dateToCheck.day == 1 ) then
returnValue = false
-- Indatum är Julafton,Juldag, Annandag eller Nyårsafton
elseif ( dateToCheck.month == 12 and (dateToCheck.day == 24 or dateToCheck.day == 25 or dateToCheck.day == 26 or dateToCheck.day == 31) ) then
returnValue = false
end
-- Långfredag
easterDay = Holidays_CalculateEaster(dateToCheck.year)
if ( easterDay[1] == dateToCheck.year and easterDay[2] == dateToCheck.month and easterDay[3] == dateToCheck.day ) then
returnValue = false
end
-- AnnandagPåsk
easterDay2 = os.date("*t", os.time({year = easterDay[1], month = easterDay[2], day = easterDay[3]})+3*24*60*60)
if ( easterDay2.year == dateToCheck.year and easterDay2.month == dateToCheck.month and easterDay2.day == dateToCheck.day ) then
returnValue = false
end
-- Kristihimmelfärdsdag? +41 dagar från Långfredag?
datum3 = os.date("*t", os.time({year = easterDay[1], month = easterDay[2], day = easterDay[3]})+41*24*60*60)
if ( datum3.year == dateToCheck.year and datum3.month == dateToCheck.month and datum3.day == dateToCheck.day ) then
returnValue = false
end
-- hitta midsommardagen för att kunna kontrollera midsommarafton
-- midsommardagen = den lördag som infaller under tiden den 20-26 juni -> midsommarafton bör vara den fredag som inträffar under tiden 19-25 juni
if ( dateToCheck.month == 6 and (dateToCheck.day >= 19 and dateToCheck.day <= 25) and dateToCheck.wday == 6 ) then
returnValue = false
end
if ( Vacation_Days(dateToCheck) ) then
returnValue = false
end
return returnValue
end
--Settings
LVariablesDevice = 14; -- ID of helperdevice for GlobalVars!
LExecuteSecond = 60; -- Execute Every N-th second
-- Moved time settings to inside while loop for generating new values correct
LMidnightHour ="0100"; --Time which is considered to be midnight
LMidnightTime =0; -- Time when values are reset if empty it will run imediately
--kill any extra instances of the same scene
if (fibaro:countScenes() > 1) then fibaro:abort() end;
--Loop
while true do
-- Current Time
LCurrentDate = os.date("*t"); -- Current Date in table format
LCurrentTime = os.time(); -- Current time in unix format
if (LMidnightTime < LCurrentTime) then
-- Check if workday
if WorkDay(os.date("*t")) then
fibaro:setGlobal("WorkToday","True");
else
fibaro:setGlobal("WorkToday","False");
end
if WorkDay(os.date("*t", os.time()+24*60*60)) then
fibaro:setGlobal("WorkTomorrow","True");
else
fibaro:setGlobal("WorkTomorrow","False");
end
-- Generate NEW values for different TOD
LMorningHour ="05" .. string.format("%02d",math.random(48,58)); --Time which is considered to be morning
LDayHour ="08" .. string.format("%02d",math.random(00,11)); --Time which is considered to be day
LDinnerHour ="16" .. string.format("%02d",math.random(02,12)); --Time which is considered to be dinner
LEveningHour ="18" .. string.format("%02d",math.random(24,36)); --Time which is considered to be evening
LTurndownHour ="21" .. string.format("%02d",math.random(01,16)); --Time which is considered to be turndown before night
LNightHour = "22" .. string.format("%02d",math.random(12,32)); -- Time which is considered to be night
-- MorningTime
if ( fibaro:getGlobalValue("WorkToday") == "False" ) then
LMorningTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LMorningHour, 1 , 2), min=string.sub(LMorningHour, 3)}+7200;
else
LMorningTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LMorningHour, 1 , 2), min=string.sub(LMorningHour, 3)};
end
-- DayTime
if ( fibaro:getGlobalValue("WorkToday") == "False" ) then
LDayTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LDayHour, 1 , 2), min=string.sub(LDayHour, 3)}+7200;
else
LDayTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LDayHour, 1 , 2), min=string.sub(LDayHour, 3)};
end
-- DinnerTime
LDinnerTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LDinnerHour, 1 , 2), min=string.sub(LDinnerHour, 3)};
-- EveningTime
LEveningTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LEveningHour, 1 , 2), min=string.sub(LEveningHour, 3)};
-- TurndownTime
LTurndownTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LTurndownHour, 1 , 2), min=string.sub(LTurndownHour, 3)};
-- NightTime
if ( fibaro:getGlobalValue("WorkTomorrow") == "False" ) then
LNightTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LNightHour, 1 , 2), min=string.sub(LNightHour, 3)}+3600;
else
LNightTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day, hour=string.sub(LNightHour, 1 , 2), min=string.sub(LNightHour, 3)};
end
-- MidnightTime
LMidnightTime = os.time{year=LCurrentDate.year, month=LCurrentDate.month, day=LCurrentDate.day+1, hour=string.sub(LMidnightHour, 1 , 2), min=string.sub(LMidnightHour, 3)};
-- Debuginformation
fibaro:debug(" -|- MorningTime: "..os.date("%Y-%m-%d %H:%M:%S",LMorningTime));
fibaro:debug(" -|- DayTime: "..os.date("%Y-%m-%d %H:%M:%S",LDayTime));
fibaro:debug(" -|- DinnerTime: "..os.date("%Y-%m-%d %H:%M:%S",LDinnerTime));
fibaro:debug(" -|- EveningTime: "..os.date("%Y-%m-%d %H:%M:%S",LEveningTime));
fibaro:debug(" -|- TurndownTime: "..os.date("%Y-%m-%d %H:%M:%S",LTurndownTime));
fibaro:debug(" -|- NightTime: "..os.date("%Y-%m-%d %H:%M:%S",LNightTime));
fibaro:debug(" -|- MidnightTime: "..os.date("%Y-%m-%d %H:%M:%S",LMidnightTime));
fibaro:debug("Work Today: " .. fibaro:getGlobalValue("WorkToday"));
fibaro:debug("Work Tomorrow: " .. fibaro:getGlobalValue("WorkTomorrow"));
end
if (LCurrentTime > LNightTime or LCurrentTime < LMorningTime) then
if (fibaro:getGlobalValue("TOD") == "TurnDown") then
fibaro:setGlobal("TOD","Natt");
fibaro:debug("Natt");
end
elseif (LCurrentTime > LTurndownTime) then
if (fibaro:getGlobalValue("TOD") == "Kväll") then
fibaro:setGlobal("TOD","TurnDown");
fibaro:debug("TurnDown");
end
elseif (LCurrentTime > LEveningTime) then
if (fibaro:getGlobalValue("TOD") == "Middag") then
fibaro:setGlobal("TOD","Kväll");
fibaro:debug("Kväll");
end
elseif (LCurrentTime > LDinnerTime) then
if (fibaro:getGlobalValue("TOD") == "Dag") then
fibaro:setGlobal("TOD","Middag");
fibaro:debug("Middag");
end
elseif (LCurrentTime > LDayTime) then
if (fibaro:getGlobalValue("TOD") == "Morgon") then
fibaro:setGlobal("TOD","Dag");
fibaro:debug("Dag");
end
elseif (LCurrentTime > LMorningTime) then
if (fibaro:getGlobalValue("TOD") == "Natt") then
fibaro:setGlobal("TOD","Morgon");
fibaro:debug("Morgon");
end
end
-- Check if anyone is at home or not
fibaro:call(LVariablesDevice, "pressButton", "1"); -- Check if anyone is at Home
--Sleep XX seconds
fibaro:sleep(LExecuteSecond*1000);
end
Code: Select all
fibaro:call(LVariablesDevice, "pressButton", "1"); -- Check if anyone is at Home
Code: Select all
plugwise = Net.FHttp("192.168.1.1", 80);
response = plugwise:GET("/Info.live.htm");
if(string.find(response,"xx:xx:xx:xx:F7:A1','eth")
or (string.find(response,"xx:xx:xx:xx:24:AF','eth")))
then
fibaro:setGlobal("Hemma", "Hemma");
else
fibaro:setGlobal("Hemma", "Borta");
end
Sedan har vi en scen som hantera om det är ljust ute eller inte, men den är inte speciell på något sätt. Om ljussensorn i arbetsrummet har över 240lux så sätts variabeln Dagljus = Ljust, och när det fallet under 210lux så blir det = Mörkt. Skälet till att jag testar på olika värden är såklart för att det inte skall uppstå kaos och tända/släcka hela tiden.... Det händer att jag ljusterar värdena ibland. Och jag har någon udda fundering på att lägga in någon form av säsongsvariabel, typ sommartid så skall känsligheten ändras - men det är överkurs just nu.
Det finns säkert mera som jag finner självklart (jag har ju programmerat allt), men jag kommer inte direkt på något. Jag har såklart en bunt scener som tänder och släcker lite, och jag tänkte bara nämna två varianter här, Hallen (med rörelse sensor) respektive Fönsterbelysning (den som alltid tänds oberoende om någon är hemma eller inte). Men först så kommer ytterligare en VD som jag kopierat från Fibaro's forum, "Lights Automation":
http://forum.fibaro.com/viewtopic.php?t=2693
En för övrigt grymt bra variant att få timer på lampor tycker jag då.
Så det finns då t.ex. en scen som känner av om någon rör sig i hallen, eller ytterdörren öppnas, och tänder hallbelysningen:
Code: Select all
--[[
%% autostart
%% properties
13 value
59 value
%% globals
TOD
--]]
local startSource = fibaro:getSourceTrigger();
if (
( ( tonumber(fibaro:getValue(13, "value")) > 0 or tonumber(fibaro:getValue(59, "value")) > 0 ) and fibaro:getGlobalValue("TOD") ~= "Natt" )
or
startSource["type"] == "other"
)
then
fibaro:call(68, "setSlider", "3", "1800");
end
if ( tonumber(fibaro:getValue(10, "value")) > 0
and tonumber(fibaro:getValue(13, "value")) == 0
and tonumber(fibaro:getValue(59, "value")) == 0 )
then
fibaro:call(68, "setSlider", "3", "-120");
end
En ytterligare bra sak med VD som jag kopierat från Fibaro forumet, är att om någon tänder lampan i hallen manuellt (eller i köket där det finns 4 lampor till kopplade till denna VD) är att det automagiskt släcks efter en fördefinierad tid - en timme i mitt fall. Så ingen lampa blir tänd i onödan.
Sedan kommer vi då till Fönsterbelysningen, och här kan man notera att jag har en programmerad fördröjning mellan lamporna:
Code: Select all
--[[
%% autostart
%% properties
%% globals
TOD
Dagsljus
--]]
-- Current Time
LCurrentDate = os.date("*t"); -- Current Date in table format
if ( fibaro:getGlobalValue("TOD") ~= "Natt" and fibaro:getGlobalValue("Dagsljus") == "Mörkt" )
then
fibaro:call(30, "turnOn");
fibaro:call(33, "turnOn");
fibaro:sleep(math.random(5000,8000));
fibaro:call(36, "turnOn");
fibaro:sleep(math.random(8000,12000));
fibaro:call(42, "turnOn");
fibaro:call(45, "turnOn");
-- Sovrum specialbehandlas under helgdagar för extra sen morgon ;-)
if ( fibaro:getGlobalValue("TOD") ~= "Morgon" or
( ( fibaro:getGlobalValue("WorkToday") == "True" )
and fibaro:getGlobalValue("TOD") == "Morgon"
)
)
then
fibaro:sleep(math.random(8000,12000));
fibaro:call(48, "turnOn");
end
end
Code: Select all
fibaro:sleep(math.random(8000,12000));
Kom på en liten rolig scen jag har förresten: Jag låter stereon gå på / av beroende på lite saker:
Code: Select all
--[[
%% properties
%% globals
Hemma
TOD
Projektor
--]]
if ( fibaro:getGlobalValue("Hemma") ~= "Hemma" )
then
-- Power OFF
fibaro:call(100, "pressButton", "2");
end
if (
fibaro:getGlobalValue("Hemma") == "Hemma" and
fibaro:getGlobalValue("Projektor") == "Av" and
fibaro:getGlobalValue("TOD") ~= "Natt" )
then
-- Internet Radio ON
fibaro:call(100, "pressButton", "9");
-- Set Volume to -50dB
fibaro:sleep(10000);
fibaro:call(100, "pressButton", "5");
-- Select Preset D4 - P4 Radio Stockholm
fibaro:sleep(2000);
fibaro:call(100, "pressButton", "26");
end