--[[ %% autostart %% properties %% globals --]] --[[ MAIN SCENE FOR TIME BASED EVENTS CONTROL Copyright © 2016 Zoran Sankovic - Sankotronic. All Rights Reserved. Version 1.3.0 -- VERSION HISTORY 1.3.0 - cleaned some bugs, added some more checks to prevent scene from stop running due to errors. Optimized and compacted code, removed unnecessary comments. DemoMode only stops changing timers while user code and scheduled events will continue to execute. Darkness can now be changed by measured lux level or global variable that is set to lux value measured by light measuring devices placed outside. Scene is now running on setTimeout function instead on sleep for better timing and also alignes to 0 seconds or exact minutes. 1.2.5 - since there was some misunderstanding with SleepState usage and TimeOfDay setting, useSleepState is now added and by default set to false. When useSleepState is set to false then Night will change to Morning at surnise time adjusted by marginSunrise so if you wakeup before sunrise then you will still be at Night. If useSleepState is set to true then Night will change to Morning when SleepState is set to Awake if it happen before sunrise time. Some minor bug cleaning 1.2.4 - replaced functions for time calculation that are provided by Fibaro international forum member @Tor Magnus added function to change global variable values by scheduled time. added possibility to define different buttons of VD to be pressed at different scheduled times. See example bellow. 1.2.3 - added support for localisation so that scene knows where you are and to properly set seasons. Also added checking of users GPS position and calculation of distance from home of each user in meters. Further usage of this will be added when Fibaro rectifies battery drain when location services are turned on for Fibaro app. Sorry! 1.2.2 - "Sunrise & Sunset" VD is now generating missing global values needed for setting up of sunrise, sunset and time of day times. User need to first install this VD and define the rest of globals listed bellow and can start using this scene. 1.2.1 - removed unecessary global variables MarginDay, MarginNight and marignBlinds since calculation is done by "Sunrise & Sunset" VD Please before using this scene import "Sunrise & Sunset" VD to set time for Day, Night and Blinds. 1.2 - added support for repeating and scheduled scene and VD push button activations. Also added control of holiday lights which are turned of when time of day changes from Morning to Day, and turning then On again at evening before sunset for time defined in variable marginHoliday. done code cleaning and making it more readable by removing most of the code from main loop to different functions and adding more instructions and explanations for users how to setup this scene. -- SCENE DESCRIPTION This scene will take care of all time based events mostly by changing global variables at specified time, but can also be used to call other scenes at preferred time or pressing buttons on VDs! Before usage need to configure following global variables: -- LIST OF GLOBAL VARIABLES NEEDED "HomeTable" - predefined global variable table with device and scene IDs. Recommended to use since z-wave devices can change their ID with re-inclusion and then is necesary to edit only scene which make this table and only device ID in scene headers. Much less time and effort is needed than without that option! "Darkness" - global variable, possible values: 0 - Day time, 1 - Night time, value is set by this scene "SleepState" - predefined global variable with values "Awake", "Sleep" or values in your language that you can map in code bellow. Value is changed by other scenes or VD and it is up to you "SeasonState" - predefined global variable with values of season names in your language. Just remember to map your names in code bellow - value is set by this scene "WeekDay" - predefined global variable with values of weekday names in your language. Remember to map your names in code bellow - value set by this scene "Month" - predefined global variable with values of month names in your language. Remember to map your names in code bellow - value set by this scene "TimeOfDay" - predefined global variable with values of "Morning", "Day", "Evening", "Night" in your language. Remember to map your values in bellow code - value is set by this scene depending on "Sunrise & Sunset" VD settings "DemoMode" - predefined global variable with values: "Yes", "No" - value changed by VD and if set to "Yes" then scene will no more change time based variables like Darkness, TimeOfDay, SeasonState so they can be changed by VD to make test of the system or just demostration "HolidayTime" - predefined global variable with two possible values: "Yes" from 27th November till 6th January, "No" for the rest of the year. "HolidayLights" - predefined global variable with two possible values: "On" - holiday lights are turned On "Off" - holiday lights are turned Off --]] local hc=fibaro if(hc:countScenes()>1)then os.exit()end -- LOCAL VARIABLES DEFINITIONS -- please do not change this part until TIME BASED SCENES AND VD SETUP part. local currenttime=os.date('*t') local currentmonth=currenttime['month'] local currentday=currenttime['day'] local currentwday=currenttime['wday'] local currenthour=currenttime['hour'] local currentmin=currenttime['min'] local TimeCurrent=os.date("%H:%M", os.time()) local sunset=hc:getValue(1,"sunsetHour") local sunrise=hc:getValue(1,"sunriseHour") local count=1 local sunrisetime=hc:getGlobalValue("SunriseTime") or sunrise local marginSunrise=tonumber(hc:getGlobalValue("MarginSunrise")) or 0 local sunsettime=hc:getGlobalValue("SunsetTime") or sunset local marginSunset=tonumber(hc:getGlobalValue("MarginSunset")) or 0 local daytime=hc:getGlobalValue("DayTime") or "09:00" local marginDay=hc:getGlobalValue("MarginDay") or "02:00" local nighttime=hc:getGlobalValue("NightTime") or "21:00" local marginNight=hc:getGlobalValue("MarginNight") or "02:00" local blindtime=hc:getGlobalValue("OpenBlindTime") or "11:00" local marginBlinds=hc:getGlobalValue("MarginBlinds") or "04:00" local api_hc=api.get("/settings/location") local HClat=tonumber(string.format("%.8f",api_hc.latitude))local HClon=tonumber(string.format("%.8f",api_hc.longitude)) local latitude=tonumber(hc:getGlobalValue("Latitude")) or HClat local longitude=tonumber(hc:getGlobalValue("Longitude")) or HClon local homelocation=tostring(longitude)..";"..tostring(latitude) local userlocation,userdistance={},{} -- end of local variables definitions -- PART OF CODE FOR USERS TO EDIT AND SETUP -- DARKNESS LIGHT SENSOR SETUP -- NEW! -- if you setup light sensor here then scene will change global Darkness -- according to sensor setup instead of using sunrise and sunset times -- for example {400,320} local luxID = {} -- or you can setup global variables names that are set by other light sensors -- for example {"LuxGarden","LuxShade"} local luxGlo = {} local luxLevelmin = 100 local luxLevelmax = 300 -- luxDelayTime is set in minutes and is used to avoid frequent change of Darkness -- default setting is 5 minutes local luxDelayTime = 5 -- do not change this variables local luxDelay=(60*luxDelayTime) local lastChange=os.time()-luxDelay -- END DARKNESS LIGHT SENSOR SETUP -- GLOBAL VARIABLES -- enter names and value mapping of your global variables or leave as it is -- get the table of device & scene ID's from global variable HomeTable. If -- using then uncomment bellow line else leave it as it is! -- local jT = json.decode(hc:getGlobalValue("HomeTable")) -- "Darkness" is global variable with two possible states 0 - for day time and 1 -- for night time and it is changed at sunrise & sunset by main scene that is -- responsible for all time based events. See my other posts for details local darkness = "Darkness" local darknessMapping = {Light="0", Dark="1"} -- "SleepState" is predefined global variable with possible values: -- "Sleep", "Awake". local sleepState = "SleepState" local sleepStateMapping = {Sleep="Sleep", Awake="Awake"} -- if you want that TimeOfDay changes to Morning (or Day) if you wakeup -- before sunrise time inestead at sunrise time then set useSleepState -- to true therwise leave it false local useSleepState = false -- predefined global variable that keeps current day of week. -- make sure that value mapping corresponds to day names in -- your language local weekDay = "WeekDay" local weekDayMapping = {Sunday ="Sunday", Monday ="Monday", Tuesday ="Tuesday", Wednesday ="Wednesday", Thursday ="Thursday", Friday ="Friday", Saturday ="Saturday"} -- enter week days in your language and mapped in previous variable local weekDayMap = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"} -- predefined global variable that keeps current month name. -- make sure that value mapping corresponds to month names in -- your language local month = "Month" local monthMapping = {January ="January", February ="February", March ="March", April ="April", May ="May", June ="June", July ="July", August ="August", September="September", October ="October", November ="November", December ="December"} -- enter month names in your language and mapped in previous variable local monthMap = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"} -- predefined global variable that keeps current season and map -- your values local seasonState = "SeasonState" local seasonStateMapping = {Spring="Spring", Summer="Summer", Autumn="Autumn", Winter="Winter"} -- predefined global variable that keeps current time of day and map -- your values local timeOfDay = "TimeOfDay" local timeOfDayMapping = {Morning="Morning", Day="Day", Evening="Evening", Night="Night"} -- predefined global variable that determines normal or demo -- mode of the system. Demo mode can be used for testing or -- demostration of the system set by "Home state" VD local demoMode = "DemoMode" local demoModeMapping = {On="Yes", Off="No"} -- GPS LOCATION AND USERS SETUP -- define users for which you want to get GPS location. Enter users inside -- braces separated by comma local userID = {} -- PUSH MESSAGES AND MOBILE DEVICE SETUP -- define mobile devices to send push messages. Enter devices inside -- braces separated by comma local iosDeviceID = {} -- flag for each user if 1 then send notifications else if 0 do not -- send notifications. You can add code in function extraUserCodeFirst() -- where you can change user flags depending on some global variable. local iosDeviceFlag = {} -- TIME BASED SCENES AND VD SETUP -- REPEATING SCENES SETUP -- here you can setup scenes that will be executed at predefined interval -- in minutes. Lowest value is every 1 minute and longest interval is up to -- you. 24h = 1440m, 1week = 10080m, 30d = 43200m etc. -- enter scene names that will run repeatedly every X minutes separated -- by comma. This is needed for debugging and can be used to send push -- notification local runSceneRepeatName = {} -- enter scene IDs that will run repeatedly every X minutes separated -- by comma. local runSceneRepeatID = {} -- enter at which interval time in minutes will scenes run separated -- by comma. local runSceneRepeatTime = {} -- enter here flag for sending push message when scene is executed -- 1 for sending message, 0 no messages local runSceneRepeatPushFlag = {} -- enter here message content that will be sent to you when scene is -- executed. If above flag is 0 for any of the scenes then just put -- empty "" for it. local runSceneRepeatPushMessage = {} -- for each scene enter variable with name "count" (must be all same name) -- separated by comma. This is used to count interval at which scene will -- be started and is neccessary for proper execution! local runSceneRepeatCount = {} -- enter here "Yes" for each scene if you want them to run immediatelly when -- this scene starts running after reboot or saving or enter "No" if you -- want scene to run after defined interval after scene is restarted local runSceneAtStart = {} -- SCHEDULED SCENES SETUP -- here you can setup scenes that will be executed at predefined time of -- day in format "00:00". You can set up more than one time during day. -- Also you can enter flag for each day of the week when scene will be -- executed or not. See more details bellow. local runSceneSchedName = {} -- enter scene IDs that will run at scheduled time separated by comma. local runSceneSchedID = {} -- enter at what time of day will scenes run separated by comma. -- You can define more than one time in format "00:00" for one scene -- or even use local or global variables like sunsettime or sunrisetime -- Example: {{"13:30", "19:20"}, {sunrisetime, "13:00", sunsettime}} -- in above example first scene will run at 13:30 and 19:20 while -- second scene will run at sunrisetime, 13:00 and at sunsettime -- IMPORTANT NOTE - if you use variable to set time then make sure that -- you add refreshing of value in function extraUserCodeFirst() like -- this for above example: -- runSceneSchedHour[2][1] = sunrisetime -- runSceneSchedHour[2][3] = sunsettime where first square brackets -- [2] with number inside refers to second scene and second square -- brackets [1] with number inside refers to time in order which means -- sunrisetime is 1st time [1] for 2nd [2] scene and sunsettime is -- 3rd [3] time for 2nd [2] scene in a row added to the variable. local runSceneSchedHour = {} -- enter here flag for each day of the week for scene to run at above -- scheduled time. if flag 1 the scene will run and if flag 0 then -- will not be run for that day. Remeber, Sunday is first day of the -- week on HC2! Example for two scenes: -- {{1, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 0}} - in this example -- first scene will run only on Sunday, and second scene will run on -- weekdays byt not on weekends (Saturday and Sunday). local runSceneSchedWeek = {} -- enter here flag for sending push message when scene is executed -- 1 for sending message, 0 no messages local runSceneSchedPushFlag = {} -- enter here message content that will be sent to you when scene is -- executed. If above flag is 0 for any of the scenes then just put -- empty "" for it. local runSceneSchedPushMessage = {} -- REPEATING VIRTUAL DEVICE SETUP -- here you can setup VD that will be executed at predefined interval -- in minutes. Lowest value is every 1 minute and longest interval is up to -- you. 24h = 1440m, 1week = 10080m, 30d = 43200m etc. -- enter VD IDs that will run repeatedly every X minutes separated -- by comma. local runVDRepeatID = {} -- enter here which button to press to execute command local runVDRepeatButton = {} -- enter at which interval time in minutes will VD run separated by comma. local runVDRepeatTime = {} -- enter here flag for sending push message when VD is executed 1 for -- sending message, 0 no messages local runVDRepeatPushFlag = {} -- enter here message content that will be sent to you when VD is -- executed. If above flag is 0 for any of the VD then just put -- empty "" for it. local runVDRepeatPushMessage = {} -- for each VD enter variable with name "count" (can be all same name) -- separated by comma. This is used to count interval at which VD will -- be executed and is neccessary for proper execution! local runVDRepeatCount = {} -- enter here "Yes" for each VD if you want them to run immediatelly when -- this scene starts running after reboot or saving or enter no if you -- want VD to run after defined interval local runVDAtStart = {} -- SCHEDULED VD SETUP -- here you can setup VDs that will be executed at predefined time of -- day in format "00:00". You can set up more than one time during day. -- Also you can enter flag for each day of the week when VD will be -- executed or not. See more details bellow. -- enter VD IDs that will run at scheduled time separated by comma. local runVDSchedID = {} -- enter here which button to press to execute command for each time that -- you enter bellow. Example for Sonos remote VD from Krikroff. If you set -- runVDSchedButton = {{"7", "9"}} and -- runVDSchedHour = {{"07:00", "11:00}} -- Then button "2" (Play) will be pressed at 07:00 to start music and -- button "9" (Stop) will be pressed at 11:00 to stop music. local runVDSchedButton = {{}} -- enter at what time of day will VD button be pressed separated by comma. -- You can define more than one time in format "00:00" for one VD -- or even use local or global variables like sunsettime or sunrisetime -- Example: {{"13:30", "19:20"}, {sunrisetime, "13:00", sunsettime}} -- in above example first VD button will be pressed at 13:30 and 19:20 -- while second VDs button will be pressed at sunrisetime, 13:00 and -- at sunsettime local runVDSchedHour = {{}} -- enter here flag for each day of the week for VD to press button -- at above scheduled time. if flag 1 the VD button will be pressed and -- if flag 0 then will not be pressed for that day. Remeber, Sunday is -- first day of the week on HC2! Example for two VDs: -- {{1, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 0}} - in this example -- first VDs button will be pressed only on Sunday, and second VDs -- button will be pressed on weekdays but not on weekends (Saturday -- and Sunday). local runVDSchedWeek = {{1, 1, 1, 1, 1, 1, 1}} -- enter here flag for sending push message when VD buttons is pressed -- 1 for sending message, 0 no messages local runVDSchedPushFlag = {} -- enter here message content that will be sent to you when VD is -- executed. If above flag is 0 for any of the VDs then just put -- empty "" for it. local runVDSchedPushMessage = {} -- SCHEDULED GLOBAL VARIABLE CHANGE SETUP -- here you can setup global variable which value will be changed at -- predefined time of day in format "00:00". You can set up more than one -- time during day. Also you can enter flag for each day of the week when -- global variable value will change or not. See more details bellow. -- enter global variable name which value you want to change at scheduled -- time separated by comma. local chgGlobalSchedName = {} -- enter here what value will be set to global variable for each time that -- is entered bellow local chgGlobalValue = {{}} -- enter at what time of day will global value change separated by comma. -- You can define more than one time in format "00:00" for one VD -- or even use local or global variables like sunsettime or sunrisetime -- Example: {{"13:30", "19:20"}, {sunrisetime, "13:00", sunsettime}} -- in above example first global variable value will be changed at 13:30 -- and another value at 19:20 while second global variable value will be -- changed at sunrisetime, 13:00 and at sunsettime local chgGlobalHour = {{}} -- enter here flag for each day of the week for VD to press button -- at above scheduled time. if flag 1 the VD button will be pressed and -- if flag 0 then will not be pressed for that day. Remeber, Sunday is -- first day of the week on HC2! Example for two VDs: -- {{1, 0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1, 0}} - in this example -- first VDs button will be pressed only on Sunday, and second VDs -- button will be pressed on weekdays but not on weekends (Saturday -- and Sunday). local chgGlobalWeek = {{1, 1, 1, 1, 1, 1, 1}} -- enter here flag for sending push message when VD buttons is pressed -- 1 for sending message, 0 no messages local chgGlobalPushFlag = {} -- enter here message content that will be sent to you when VD is -- executed. If above flag is 0 for any of the VDs then just put -- empty "" for it. local chgGlobalPushMessage = {} -- DEBUGGING VARIABLES -- setup debugging, true is turned on, false turned off. local deBug = true -- for showing events as they happen local exDebug = false -- for checking repeating and scheduled scene -- & VD variable values if correct local gpsDebug = false -- GPS user location check and calculation local sumDebug = true -- it shows summation of global var changes -- EXTRA FUNCTION WHERE YOU CAN ADD YOUR CODE -- use this function to add code that will be executed before all other -- code in the loop function extraUserCodeFirst() -- if you use variable for scheduled execution of scene or VD then you -- need to add here equanation to get last value calcualted -- your code goes here end -- use this function to add code that will be executed after all other -- code in the loop function extraUserCodeLast() -- your code goes here end -- END OF CODE PART FOR USERS TO EDIT AND SETUP -- BELLOW CODE NO NEED TO MODIFY BY USER -- FUNCTIONS CODE PART local version,midnight="1.3.0","00:00" local interval,pause,alignment=60,100,true -- debug colors local crc,okc,ekc,erc,evc,xec,cnc,xcc,tmc,stc="green","lightgreen","violet","red","orange","yellow","cyan","pink","magenta","lightgray" -- other locals local abort,miss,am="Please check. Scene aborting"," is missing ","Aligning to next minute..." local crt="Main scene FTBE version "..version.." - © 2016-2018 Sankotronic" function logbug(color,message)for line in message:gmatch("[^\010\013]+")do local txt=line:gsub("([\038\060\062])",function(c)return"&#"..string.byte(c)..";"end) hc:debug(('%s'):format(color,txt))end end function calculateTime(baseTime,diffHour,diffMinute) if diffHour~=nil and diffMinute~=nil then local origHour,origMinute=string.match(baseTime,"(%d+):(%d+)")local newMinute=(origMinute+diffMinute)%60 local excessHour=math.floor((origMinute+diffMinute)/60)local newHour=(origHour+diffHour+excessHour)%24 return string.format("%02d:%02d",newHour,newMinute) else return baseTime end end function calculateTimeString(baseTime,duration,operand) local diffHour,diffMinute=string.match(duration,"(%d+):(%d+)")if diffMinute==nil then diffMinute="00" end if operand=="sub" then diffHour=0-diffHour diffMinute=0-diffMinute end return calculateTime(baseTime,diffHour,diffMinute) end function sendPush(message) if (#iosDeviceID==#iosDeviceFlag)then if #iosDeviceID>0 then for i=1,#iosDeviceID do if iosDeviceFlag[i]==1 then hc:call(iosDeviceID[i],"sendPush",message) if deBug then logbug("lightgray", "Push notification sent to user "..hc:getName(iosDeviceID[i])) end end end end else if deBug then logbug(erc,"User and flag count is different, not setup correctly. Please check")end end end function getUserPosition() if #userID>0 then for i=1,#userID do if(hc:getValue(userID[i],'Location')==nil)then if gpsDebug then logbug(evc,"No GPS position for "..hc:getName(userID[i]))end else userlocation[i]=hc:getValue(userID[i],'Location')userdistance[i]=tonumber(hc:calculateDistance(userlocation[i],homelocation)) if gpsDebug then logbug(okc,hc:getName(userID[i]).." distance from home is: "..string.format("%.2f",userdistance[i]).." meters")end end end end end function doTimeOfDay() if(((TimeCurrent>=sunrisetime)and(TimeCurrent=midnight)and(TimeCurrent=daytime)and(TimeCurrent=sunsettime)and(TimeCurrent0 then for i,v in pairs(luxID)do totalLux=totalLux+tonumber(hc:getValue(v,'value'))end averageLux=math.floor(totalLux/#luxID) elseif #luxGlo>0 then for i,v in pairs(luxGlo)do totalLux=totalLux+tonumber(hc:getGlobalValue(v))end averageLux=math.floor(totalLux/#luxGlo) else averageLux=50 end if exDebug then logbug(cnc,string.format("Set lux level min %s, max %s. Measured average lux level is %s.",luxLevelmin,luxLevelmax,averageLux))end return averageLux end function doDarkness() local dkc="Darkness changed to %s at lux: %s" local ct,now=os.date("%H:%M",os.time()),os.time() local val_dark=hc:getGlobalValue(darkness) or darknessMapping.Light if #luxID>0 then local luxLevel=checkLux() if luxLevel<=luxLevelmin and now-lastChange>=luxDelay and val_dark~=darknessMapping.Dark then if exDebug then logbug(evc,string.format(dkc,"Dark",luxLevel))end hc:setGlobal(darkness,darknessMapping.Dark)lastChange=now elseif luxLevel>=luxLevelmax and now-lastChange>=luxDelay and val_dark~=darknessMapping.Light then if exDebug then logbug(evc,string.format(dkc,"Light",luxLevel))end hc:setGlobal(darkness,darknessMapping.Light)lastChange=now end if deBug then logbug(xec,string.format("Luxmin: %s, Luxmax: %s, Delay: %s min, Last change: %s",luxLevelmin,luxLevelmax,os.date("%M",luxDelay),os.date("%H:%M:%S",lastChange)))end else if TimeCurrent>=sunrisetime and TimeCurrent=1 and currentmonth<3)then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Winter)else hc:setGlobal(seasonState,seasonStateMapping.Summer)end elseif currentmonth==3 then if currentday<21 then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Winter)else hc:setGlobal(seasonState, seasonStateMapping.Summer)end else if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Spring)else hc:setGlobal(seasonState,seasonStateMapping.Autumn)end end elseif(currentmonth>3 and currentmonth<6)then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Spring) else hc:setGlobal(seasonState,seasonStateMapping.Autumn)end elseif currentmonth==6 then if currentday<21 then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Spring)else hc:setGlobal(seasonState,seasonStateMapping.Autumn)end else if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Summer)else hc:setGlobal(seasonState,seasonStateMapping.Winter)end end elseif(currentmonth>6 and currentmonth<9)then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Summer)else hc:setGlobal(seasonState,seasonStateMapping.Winter)end elseif currentmonth==9 then if currentday<23 then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Summer)else hc:setGlobal(seasonState,seasonStateMapping.Winter)end else if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Autumn)else hc:setGlobal(seasonState,seasonStateMapping.Spring)end end elseif(currentmonth>9 and currentmonth<12)then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Autumn)else hc:setGlobal(seasonState,seasonStateMapping.Spring)end elseif currentmonth==12 then if currentday<21 then if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Autumn)else hc:setGlobal(seasonState,seasonStateMapping.Spring)end else if latitude>=0 then hc:setGlobal(seasonState,seasonStateMapping.Winter)else hc:setGlobal(seasonState,seasonStateMapping.Summer)end end end hc:setGlobal(month,monthMap[currentmonth]) if deBug and hc:getGlobalValue(seasonState)~=nil and hc:getGlobalValue(month)~=nil then logbug(xec," Season is "..hc:getGlobalValue(seasonState)..", Month is "..hc:getGlobalValue(month)) else logbug(xec,"Missing global variable for Season and/or Month")end end function doSceneRepeat() for i=1,#runSceneRepeatID do if exDebug then logbug(evc,"Repeating scene "..runSceneRepeatName[i].." interval is: "..runSceneRepeatTime[i].." min current count is: "..runSceneRepeatCount[i].." min.")end if runSceneRepeatTime[i]==runSceneRepeatCount[i] then hc:startScene(runSceneRepeatID[i]) if deBug then logbug(xec,"Repeating scene "..runSceneRepeatName[i].." started after "..runSceneRepeatCount[i].." min.")end if runSceneRepeatPushFlag[i]==1 then sendPush(runSceneRepeatPushMessage[i])end runSceneRepeatCount[i]=1 else runSceneRepeatCount[i]=runSceneRepeatCount[i]+1 end end end function doSceneSched() for i=1,#runSceneSchedID do if exDebug then logbug(evc,"Scheduled scene "..runSceneSchedName[i].." weekday flag is: "..runSceneSchedWeek[i][currentwday])end if runSceneSchedWeek[i][currentwday]==1 then for t=1,#runSceneSchedHour[i] do if exDebug then logbug(ekc,"Scheduled scene "..runSceneSchedName[i].."run time["..i.."]["..t.."] is: "..runSceneSchedHour[i][t].."h current time is: "..TimeCurrent.."h")end if runSceneSchedHour[i][t]==TimeCurrent then hc:startScene(runSceneSchedID[i]) if deBug then logbug(xec,"Scheduled scene "..runSceneSchedName[i].." started at "..runSceneSchedHour[i][t].."h")end if runSceneSchedPushFlag[i]==1 then sendPush(runSceneSchedPushMessage[i]) end end end end end end function doVDRepeat() for i=1,#runVDRepeatID do if exDebug then logbug(evc,"Repeating VD "..hc:getName(runVDRepeatID[i]).." press button interval is: "..runVDRepeatTime[i].." min current count is: "..runVDRepeatCount[i].." min.")end if runVDRepeatTime[i]==runVDRepeatCount[i] then hc:call(runVDRepeatID[i],"pressButton",runVDRepeatButton[i]) if deBug then logbug(xec,"Repeating VD "..hc:getName(runVDRepeatID[i]).." pressed button "..runVDRepeatButton[i].." after "..runVDRepeatCount[i].." min.")end if runVDRepeatPushFlag[i]==1 then sendPush(runVDRepeatPushMessage[i])end runVDRepeatCount[i]=1 else runVDRepeatCount[i]=runVDRepeatCount[i]+1 end end end function doVDSched() for i=1,#runVDSchedID do if exDebug then logbug(evc,"Scheduled VD "..hc:getName(runVDSchedID[i]).." weekday flag is: "..runVDSchedWeek[i][currentwday])end if runVDSchedWeek[i][currentwday]==1 then for t=1,#runVDSchedHour[i] do if exDebug then logbug(ekc,"Scheduled VD "..hc:getName(runVDSchedID[i]).." run time["..i.."]["..t.."] is: "..runVDSchedHour[i][t].."h current time is: "..TimeCurrent.."h")end if runVDSchedHour[i][t]==TimeCurrent then hc:call(runVDSchedID[i],"pressButton",runVDSchedButton[i][t]) if deBug then logbug(xec,"Scheduled VD "..hc:getName(runVDSchedID[i]).." button "..runVDSchedButton[i][t].." pressed at "..runVDSchedHour[i][t].."h")end if runVDSchedPushFlag[i]==1 then sendPush(runVDSchedPushMessage[i])end end end end end end function doGlobalSched() for i=1,#chgGlobalSchedName do if exDebug then logbug(evc,"Scheduled global "..chgGlobalSchedName[i].." weekday flag is: "..chgGlobalWeek[i][currentwday])end if chgGlobalWeek[i][currentwday]==1 then for t=1,#chgGlobalHour[i] do if exDebug then logbug(ekc,"Scheduled global "..chgGlobalSchedName[i].." run time["..i.."]["..t.."] is: "..chgGlobalHour[i][t].."h current time is: "..TimeCurrent.."h")end if chgGlobalHour[i][t]==TimeCurrent then hc:setGlobal(chgGlobalSchedName[i],chgGlobalValue[i][t]) if deBug then logbug(xec,"Scheduled global "..chgGlobalSchedName[i].." changed value to "..chgGlobalValue[i][t].." at "..chgGlobalHour[i][t].."h")end if chgGlobalPushFlag[i]==1 then sendPush(chgGlobalPushMessage[i])end end end end end end -- CHECK AND INITIALIZE SCENES & DEVICES function chkUserSetting() if #runSceneRepeatID>0 then if((#runSceneRepeatID==#runSceneRepeatName)and(#runSceneRepeatID==#runSceneRepeatTime)and (#runSceneRepeatID==#runSceneRepeatPushFlag)and(#runSceneRepeatID==#runSceneRepeatCount)and (#runSceneRepeatID==#runSceneAtStart)and(#runSceneRepeatID==#runSceneRepeatPushMessage))then for i=1,#runSceneRepeatID do if runSceneAtStart[i]=="Yes" then runSceneRepeatCount[i]=runSceneRepeatTime[i]else runSceneRepeatCount[i]=1 end end if deBug then logbug(okc,"Repeating scene timers initialized!")end else if deBug then logbug(erc,"Repeating scene setup error! Missing argument. Please check. Scene is stopped!")end os.exit()end end if #runVDRepeatID>0 then if((#runVDRepeatID==#runVDRepeatButton)and(#runVDRepeatID==#runVDRepeatTime)and (#runVDRepeatID==#runVDRepeatPushFlag)and(#runVDRepeatID==#runVDRepeatCount)and (#runVDRepeatID==#runVDAtStart)and(#runVDRepeatID==#runVDRepeatPushMessage))then for i=1,#runVDRepeatID do if runVDAtStart[i]=="Yes" then runVDRepeatCount[i]=runVDRepeatTime[i]else runVDRepeatCount[i]=1 end end if deBug then logbug(okc,"Repeating VD timers initialized!")end else if deBug then logbug(erc,"Repeating VD setup error! Missing argument. Please check. Scene is stopped!")end os.exit()end end if #runSceneSchedID>0 then local check=false if((#runSceneSchedID==#runSceneSchedName)and(#runSceneSchedID==#runSceneSchedHour)and (#runSceneSchedID==#runSceneSchedWeek)and(#runSceneSchedID==#runSceneSchedPushFlag)and (#runSceneSchedID==#runSceneSchedPushMessage))then for i=1,#runSceneSchedID do if #runSceneSchedHour[i]==0 then if deBug then logbug(erc,"Scheduled scene "..runSceneSchedName[i].." is missing time. Please chcek. Scene is stopped!")end check=true end if #runSceneSchedWeek[i]~=7 then if deBug then logbug(erc,"Scheduled scene "..runSceneSchedName[i].." is missing flags for whole week. Please check. Scene is stopped!")end check=true end end else if deBug then logbug(erc,"Scheduled scene setup error! Missing argument. Please check. Scene is stopped!")end check=true end if check then os.exit() end end if #runVDSchedID>0 then local check=false if((#runVDSchedID==#runVDSchedButton)and(#runVDSchedID==#runVDSchedHour)and (#runVDSchedID==#runVDSchedWeek)and(#runVDSchedID==#runVDSchedPushFlag)and (#runVDSchedID==#runVDSchedPushMessage))then for i=1,#runVDSchedID do if #runVDSchedHour[i]==0 then if deBug then logbug(erc,"Scheduled VD "..hc:getName(runVDSchedID[i]).." is missing time. Please chcek. Scene is stopped!")end check=true elseif #runVDSchedButton[i]==0 then if deBug then logbug(erc,"Scheduled VD "..hc:getName(runVDSchedID[i]).." is missing button. Please chcek. Scene is stopped!")end check=true elseif #runVDSchedHour[i]~=#runVDSchedButton[i] then if deBug then logbug(erc,"Scheduled VD "..hc:getName(runVDSchedID[i]).." number if time and buttons mismatch. Please chcek. Scene is stopped!")end check=true end if #runVDSchedWeek[i]~=7 then if deBug then logbug(erc,"Scheduled VD "..hc:getName(runVDSchedID[i]).." is missing flags for whole week. Please chcek. Scene is stopped!")end check=true end end else if deBug then logbug(erc,"Scheduled VD setup error! Missing argument. Please check. Scene is stopped!")end check=true end if check then os.exit() end end if #chgGlobalSchedName>0 then local check=false if((#chgGlobalSchedName==#chgGlobalValue)and(#chgGlobalSchedName==#chgGlobalHour)and (#chgGlobalSchedName==#chgGlobalWeek)and(#chgGlobalSchedName==#chgGlobalPushFlag)and (#chgGlobalSchedName==#chgGlobalPushMessage))then for i=1,#chgGlobalSchedName do if #chgGlobalHour[i]==0 then if deBug then logbug(erc,"Scheduled global "..chgGlobalSchedName[i].." is missing time. Please chcek. Scene is stopped!")end check=true elseif #chgGlobalValue[i]==0 then if deBug then logbug(erc,"Scheduled global "..chgGlobalSchedName[i].." is missing value. Please chcek. Scene is stopped!")end check=true elseif #chgGlobalHour[i]~=#chgGlobalValue[i]then if deBug then logbug(erc,"Scheduled global "..chgGlobalSchedName[i].." number of time and value mismatch. Please chcek. Scene is stopped!")end check=true end if #chgGlobalWeek[i]~=7 then if deBug then logbug(erc,"Scheduled global "..chgGlobalSchedName[i].." is missing flags for whole week. Please chcek. Scene is stopped!")end check=true end end else if deBug then logbug(erc,"Scheduled global variable setup error! Missing argument. Please check. Scene is stopped!")end check=true end if check then os.exit()end end end -- MAIN LOOP PART function mainLoop() currenttime=os.date('*t') currentmonth=currenttime['month']currentday=currenttime['day']currentwday=currenttime['wday'] currenthour=currenttime['hour']currentmin=currenttime['min']TimeCurrent=os.date("%H:%M", os.time()) sunrise=hc:getValue(1,"sunriseHour")or "19:00" sunset=hc:getValue(1,"sunsetHour")or "07:00" marginSunrise=tonumber(hc:getGlobalValue("MarginSunrise"))or 0 marginSunset=tonumber(hc:getGlobalValue("MarginSunset"))or 0 marginDay=hc:getGlobalValue("MarginDay")or "02:00" marginNight=hc:getGlobalValue("MarginNight")or "02:00" marginBlinds=hc:getGlobalValue("MarginBlinds")or "04:00" latitude=tonumber(hc:getGlobalValue("Latitude"))or HClat longitude=tonumber(hc:getGlobalValue("Longitude"))or HClon homelocation=tostring(latitude)..";"..tostring(longitude) sunrisetime=calculateTime(sunrise,0,marginSunrise)hc:setGlobal("SunriseTime",sunrisetime) sunsettime=calculateTime(sunset,0,marginSunset)hc:setGlobal("SunsetTime",sunsettime) daytime=calculateTimeString(sunrisetime,marginDay,"add")hc:setGlobal("DayTime",daytime) nighttime=calculateTimeString(sunsettime,marginNight,"add")hc:setGlobal("NightTime",nighttime) blindtime=calculateTimeString(sunrisetime,marginBlinds,"add")hc:setGlobal("OpenBlindTime",blindtime) if deBug then logbug(okc,"Day time: ".. daytime..", Night time: "..nighttime..", Time to raise blinds: "..blindtime)end extraUserCodeFirst() if((demoMode=="")or(hc:getGlobalValue(demoMode)==demoModeMapping.Off))then if #userID>0 then getUserPosition()end doDarkness()doTimeOfDay()doTimeOfYear() else if deBug then logbug("cyan","DEMO MODE ON! Home timers and geolocation will NOT update. User code will execute") end end if #runSceneRepeatID>0 then doSceneRepeat()end if #runSceneSchedID>0 then doSceneSched()end if #runVDRepeatID>0 then doVDRepeat()end if #runVDSchedID>0 then doVDSched()end if #chgGlobalSchedName>0 then doGlobalSched()end extraUserCodeLast() if sumDebug then if hc:getGlobalValue(timeOfDay)~=nil and hc:getGlobalValue(darkness)~=nil then logbug(okc,"Darkness: "..hc:getGlobalValue(darkness).." Sunrise: "..sunrise.." (set:"..sunrisetime..")".." Sunset: " ..sunset.." (set:"..sunsettime..")".." TimeOfDay: "..hc:getGlobalValue(timeOfDay)) else logbug(okc,"Sunrise: "..sunrise.." (set:"..sunrisetime..")".." Sunset: "..sunset.." (set:"..sunsettime.. ")") logbug(xec,"Missing global variable for Darkness and/or Time Of Day") end end logbug(xec,"Scene idle") end -- MAIN CODE PART function start()local t=os.date("*t") if t.hour==2 and t.min==5 and t.sec~=0 and alignment then logbug(cnc,string.format("Current time: %s:%s:%s. "..am,t.hour,t.min,t.sec))hc:sleep(1000*(60-t.sec))end setTimeout(mainLoop,0)logbug(okc,"Scene running")setTimeout(start,1000*interval) end -- MAIN CODE PART logbug(crc,crt)chkUserSetting() local t=os.date("*t")if t.sec~=0 and alignment then logbug(cnc,string.format("Current seconds: %s sec. "..am,t.sec))hc:sleep(1000*(60-t.sec))end start()