EventRunner

jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

17 Mar 2019, 19:47

Jag har sedan någon tid utvecklat en scen för HC2 som har fått namnet EventRunner (ER).
https://forum.fibaro.com/topic/31180-tu ... ent-model/
Några här på forumet är bekanta med GEA, och ER har likheter och olikheter.
- Man skriver regler som triggar på tider och/eller när sensorer/lampor/globals etc ändrar status
- Man kan lätt integrera sina egna Lua funktioner i reglerna
- När sensorer/lampor/globals ändrar status genereras 'events' som reglerna triggar på. Man kan också posta egna events och ha regler som triggar på dessa. På det sättet slipper man att alltid använda fibaro globals för att trigga regler.
- ER scener kan skicka events mellan varandra, och på så sätt trigga regler i andra ER scener.
- ER har designats för att scener ska kunna kodas och testas offline på en PC/Mac före man flyttar över dem till HC2:an

Disclaimer: Tanken med reglerna är att det ska vara lätt (och kompakt) att skriva hemmaautomatiseringsregler. Tyvärr innebär hemmaautomatiseringsregler att uttrycka logiska samband mellan asynkrona events. Så även om det är lätt att skriva regler är det inte alltid lätt att få det att fungera som man vill.

Liksom GE så består ER av många rader kod (1000+) men det är i början av scenen, inom funktionen main(), som man definerar sina regler. Resten ska man inte behöva bekymra sig om.

För att komma igång.
Gå till https://raw.githubusercontent.com/janga ... Runner.lua
och kopiera den koden till en scen i HC2:an.
Sätt scenens "Max. running instances:" till 10 och "Run scene:" till "Automatic"
Kör scenen. Det finns en fördefinerad regel i main() som om allt fungerar skriver "Ding", och "Dong!" i scen-loggen var 5:e sekund.
Om det funkar kan vi gå vidare och titta på hur regler ser ut.

Code: Select all

function main()
  local rule,define = Rule.eval, Util.defvar
  
  lampa1 = 88
  sensor = 89
  lampa2 = 90
  
  rule("@sunset-00:15 => lampa1:on")
  rule("@sunrise+00:15 => lampa1:off")
  rule("sensor:breached => lampa2:on")
  
end -- main
I exemplet ovan definerar vi 3 regler. Regler är alltid strängar som vi ger till funktionen 'rule' (förkortning av Rule.eval). Regler har alltid formen "<condition> => <actions>", dvs innehåller pil "=>" som separerar vilkoret som måste vara sant (på vänster sida) från vilka kommandon som isåfall ska utföras (höger sida)

Vår första regel ha villkoret "@sunset-00:15".
'@' definerar ett klockslag då regeln ska utföras.
'sunset' och 'sunrise' är konstanter för soluppgåg och solnedgång.

Man kan också använda tidskonstanter som "15:00" eller "17:10:30" etc.

Alla tidskonstanter omräknas till sekunder internt och våra regler tillåter aritmetiska operationer (+,-,*,/) så vi kan skriva en regel som "@sunset-00:15 => lampa1:on" som triggas vid solnedgång minus 15 minuter.
Oftast will vi ha en regel per klockslag men vi kan skriva "@{sunset-00:15, 15:00} => lampa1:on" om vi vill slå på samma lampa på 2 tider på dagen.

Högersidan har kommandot "lampa1:on". 'lampa1' definerade vi utanför regeln till 88 som en global lua variabel så den kan vi använda inuti regeln. Vi kan inte använda lokala lua variabler (local var) men vi ska se senare hur vi kan ta in definitioner från en HomeTable.
Så kommandot blir 88:on. 88 är ett deviceID, och ':on' är ett kommando som slår på deviceID 88 i det här fallet. Det översätts internt till ett 'fibaro:call(88,"turnOn")'. Många kommandon har formatet <deviceID>:<kommando> och formatet har valts mest för att det är ett kompakt format.

De vanligaste kommandona är:
':on' - slå på device ("turnOn").
':isOn' - returnera sant om device är på.
':off' - slå av device ("turnOff")
':isOff' - returnera sant om device är av
':safe' - returnera sant om sensor är av (samma som :isOff)
':breached' - returnera sant om sensor är triggad (samma som :isOn)
':value' - returnera device 'value' (fibaro:getValue(device,'value'))
Fibaro's globala variabler skrivs som namnet med ett '$' före.

Vänstersidan för ett kommando kan också vara en lista/tabell av flera deviceID, och det fungerar som man tänker sig att det borde:

Code: Select all

lampor={44,45,46}
sensorer={33,34,335}
rule("sensorer:breached => lampor:on") -- om någon sensor triggas, slå på alla lamporna.
Regler kan göras lite mer komplexa med villkor och sekvenser.

Code: Select all

rule("@sunrise-00:30 & $HomeStatus=='home' => lampa1:on; lampa2:on")
Vänstersidan, villkoret, körs vid solnedgång minus 30min och om fibaro globalen 'HomeStatus' är lika med 'home'.
AND, OR, NOT skrivs som '&', '|','!'
Högersidan har en sekvens av kommandon seprarerade med ';'

Andra bra funktioner är tidsintervall och dag tester

Code: Select all

rule("sensorer:breached & 23:00..07:00 & wday('fri-sun') => 99:value=30") 
Om ngn av sensorerna triggas och det är mellan 23 och 07 och en fredag,lördag eller söndag så sätter vi dimmer värdet på deviceID 99 till 30, dvs vi vill bara ha ledljus på natten...

Om vi vill att ett villkor ska vara sant en viss tid innan vi utför kommandon så används 'for'

Code: Select all

rule("for(00:05,sensorer:safe) & 09:00-15:00 & wday('mon-fri') => lampor:off")
Om alla sensorer är safe i 5 min, och det är mellan 9 och 15 en vardag, släck lamporna.

Den klassiska scenen tänd lampa när sensor triggas och släck när den är säker för en tid blir

Code: Select all

rule("sensorer:breached => lampor:on")
rule("for(00:05,sensorer:safe) => lampor:off")
men här generaliserat till många sensorer och många lampor

Det finns många funktioner som går att använda i regler - jag kommer att posta några "best practices" och tricks, men tillsvidare finns det ganska bra information i de här inläggen i Fibaro's forum.
Tidsregler - https://forum.fibaro.com/topic/31180-tu ... ent=157463
Trigger regler - https://forum.fibaro.com/topic/31180-tu ... ent=159638
Syntax och funktioner: https://forum.fibaro.com/topic/31180-tu ... ent=159939

En viktig sak är att externa triggers; sensorer/lampor/globals som regler ska trigga på måste deklareras i scenhuvudet precis som vanliga scener. Annars triggas inte scenen.

EventRunner har en mängd finesser, det är lätt att integrera med Philips Hue, node-red, det finns en pub/sub mekanism mellan scener - och framförallt det går att utveckla och testa scenerna offline (stega sig igenom koden när scenen kör och inspektera variabler, använder ZeroBrane IDE).

jompa har ett tidigare inlägg där han har en exempelscen med ER viewtopic.php?p=21734#p21734

Återkommer med inlägg om det men ni får gärna fråga i forumet hur man skriver regler för att åstadkomma olika saker.
Dessutom gärna feedback på det här inlägget, felaktigheter, stavfel, eller om det bara är svårt att förstå...

P.S Uppdateringar till EventRunner.lua (och andra filer) görs löpande på mitt GitHub https://github.com/jangabrielsson/EventRunner
Last edited by jang on 21 Mar 2019, 13:42, edited 1 time in total.
jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

19 Mar 2019, 21:03

Syntaxen för reglerna i EventRunner är designade för att göra det lätt och kompakt att uttrycka typiska automatiseringar.
Ex. blir uppgiften i det tidigare inlägget "Rörelse mellan 22 & 07" viewtopic.php?f=38&t=6872#p21883

Code: Select all

  local sensor = 195
  local lamp = 62
  rule("sensor:breached & 22:00..07:00 => lamp:value=3")
  rule("for(00:05,sensor:safe) & 22:00..07:05 => lamp:off")
...och det senaste "Hjälp scen temp och tid" viewtopic.php?f=29&t=6880#p21960

Code: Select all

tempSensor = 326
mobile= 234
rule("@06:30 & tempSensor:value < 5 =>  post(#notify{temp=tempSensor:value })")
rule("#notify{temp='$val'} => api.post('/mobile/push', {mobileDevices={22}, message=log('Idag är %s grader kallt, vill du starta motorvärmaren?',val), title='Motorvärmare', category='YES_NO', data={sceneId=2}})")
En liten scen med en del typiska regler för hemmaautomatisering. Mer kommer i ett uppföljande inlägg.

Code: Select all

--[[
%% properties
99 value
77 value
89 value
108 value
103 value
104 value
109 sceneActivation 
%% events
%% events
100 CentralSceneEvent
%% globals
HomeStatus
%% autostart
--]]
-- Kom ihåg att deklarera alla triggers som finns på höger-sidan i era regler i scen-headern

if dofile and not _EMULATED then _EMBEDDED={name="EventRunner",id=20} dofile("HC2.lua") end -- För offline debugging

_version,_fix = "2.0","B5"  -- Mar 17, 2019  -- Version

--[[
-- EventRunner. Event based scheduler/device trigger handler
-- Copyright 2019 Jan Gabrielsson. All Rights Reserved.
-- Email: jan@gabrielsson.com
-- Email: jan@gabrielsson.com
--]]

_sceneName   = "Demo"      -- Sätt till namnet på scenen, bara för loggning
_homeTable   = "devicemap" --Namnet till er HomeTable om ni har någon (fibaro global)
_HueHubs     = {}          -- Hue bridges, Ex. {{name='Hue',user=_HueUserName,ip=_HueIP}} -- Optional 
_myNodeRed   = "http://192.168.1.50:1880/eventrunner" -- Ex. used for Event.postRemote(_myNodeRed,{type='test'}) -- Optional

if dofile then dofile("credentials.lua") end -- To not accidently commit credentials to Github, or post at forum :-)
-- E.g. Hue user names, icloud passwords etc. HC2 credentials is set from HC2.lua, but can use same file.

-- Kan sättas till true för att logga vissa delar av systemet
_debugFlags = { 
  post=true,invoke=false,triggers=true,dailys=false,timers=false,rule=false,ruleTrue=false,hue=false,msgTime=false
}
---------------- Här definierar ni era regler --------------------
function main()
  local rule,define = Rule.eval, Util.defvar 

-- Datastrukur (HomeTable) med era deviceID. Ta bort om ni har de lagrade i en fibaro:global. Och igen, glöm inte att deklarera trigger devices i scen headern!
  HT =[[
  {
  "dev":{"bedroom":{"lamp":88,"motion":99},
         "kitchen":{"lamp1":66,"lamp2":67,"motion":77},
         "children":{"lamp":88,"motion":89},
         "hall":{"lamp":109,"door":108},
         "back":{"lamp":101,"door":103},
         "front":{"lamp":102,"door":104},
         "keyfob":201,
         "phones":{"bob":121,"mary":122},
         },
  "other":"other"
 }
  ]]

  --Läs in HomeTable struktur från fibaro global (eller scen)
  --local HT = type(_homeTable)=='number' and api.get("/scenes/".._homeTable).lua or fibaro:getGlobalValue(_homeTable) 
  HT = json.decode(HT)
  Util.defvars(HT.dev)                 -- Gör HomeTable definitioner tillgängliga i regler (EventScript)
  Util.reverseMapDef(HT.dev)      -- Gör HomeTable namn tillgängliga för log utskrifter.
  
  -- Släck och tänd utebelysning vid soluppgång+30min och solnedgång-30min
  rule("@sunset-00:30 => {front.lamp, back.lamp}:on")
  rule("@sunrise+00:30 => {front.lamp, back.lamp}:off")
  
  -- Om rörelsesensor i barnens rum aktiveras på natten, tänd lampan dimmad till 30%
  rule("children.motion:breached & 24:00..sunrise-01:00 => children.lamp:value=30")
  -- Om rörelsesensorn inte känner av aktivitet på 5min, släck lampan.
  rule("for(00:05,children.motion:safe) & 24:00..sunrise-00:55 => children.lamp:off")
  
  -- Definera variabel 'sensors' som innehåller husets alla sensorer
  rule("sensors={bedroom.motion,kitchen.motion,children.motion,hall.motion,front.door,back.door}")
  -- Om ingen sensor aktiv på 30min på dagtid, veckodagar, anta att ingen hemma och HomeStatus sätts till 'away'
  rule("for(00:30,sensors:safe) & 08:00..15:00 & wday('mon-fri') => $HomeStatus='away'")
  -- Om någon sensor aktiveras, sätt HomeStatus till 'home'
  rule("sensors:breached => $HomeStatus='home'")
  
  rule("allLamps={bedroom.lamp,kitchen.lamp1,kitchen.lamp2,children.lamp}")
  -- Dubbel-klick på knapp i hallen släcker alla lampor utom de som är ute
  rule("hall.lamp:scene == S2.double => allLamps:off") -- Använder 'SceneActivation' property

  -- Om fibaro global 'HomeStatus' sätts till 'away' starta regel som tänder/släcker lampor slumpmässigt
  rule("$HomeStatus=='away' => post(#presenceSimulation{action='start'})") -- Postar event till presence regel linger ned
  -- Om fibaro global 'HomeStatus' sätts till 'home' starta regel som tänder/släcker lampor slumpmässigt
  rule("$HomeStatus=='home' => post(#presenceSimulation{action='stop'})")
  
  -- Key 3 på remote sätter HomeStatus till 'away' (som i sin tur startar presence simulering...)
  rule("keyfob:central.key==3 => $HomeStatus='away'") 
  -- Key 4 på remote sätter HomeStatus till 'home'
  rule("keyfob:central.key==4 => $HomeStatus='home'") 
  
  -- Lite mer komplicerad regel för presence simulering. 
  -- Spara undan värden på lamporna, Sätt flagga att simulering pågår, Starta regel
  rule([[#presenceSimulation{action='start'} & !simulation => 
        log('Starting presence simulation');
         savedLamps = simLamps:value;  
         simulation=true;          
         enable(presence)]])      
  -- Återställ värden på lamporna, Sätt flagga att simulering inte kör, Stoppa regel
  rule([[#presenceSimulation{action='stop'} & simulation=> 
       log('Stopping presence simulation');
       simLamps:value=savedLamps;  
       simulation=false;       
       disable(presence)]])  
 
   -- Definera lampor som ska vara med i simulering
  rule("simLamps = {bedroom.lamp, kitchen.lamp1, kitchen.lamp2, hall.lamp}")
  -- Kör regel varje 15min +/- 15min slumpmässigt. Välj ut slumpmässig lampa och toggla den.
  presence = rule("@@00:15+rnd(-00:05,00:05) => simLamps[rnd(size(simLamps))]:toggle").disable()
  
end -- main()
MastrUsr
Medlem
Posts: 85
Joined: 25 Apr 2017, 07:24

19 Mar 2019, 21:28

WOW!! Har precis med mätt mage läst båda inläggen. Ser verkligen fram emot att få testa detta!! Verkar grymt!

Skickat från min SM-N960F via Tapatalk

sonnyboy
Proffsmedlem
Posts: 617
Joined: 26 Sep 2013, 08:05
Location: Västerås

19 Mar 2019, 23:13

Har precis börjat lite lätt och det fungerar ruskigt bra :)
Kommer garanterat komma med en massa frågor framöver.
Redan nu känns ER lättare än GEA.
Stort Tack @jang som delade med dig av ditt fina jobb och tack till @jompa68 som lagt ut en massa bra exempel :)
Fibaro HomeCenter 2
Fw 4.532 Beta
BeyondMeasure 1.10
25 Enheter, 55 Scener tidigare, 8 nu med gea GEA
jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

20 Mar 2019, 06:46

sonnyboy wrote:
19 Mar 2019, 23:13
Har precis börjat lite lätt och det fungerar ruskigt bra :)
Kommer garanterat komma med en massa frågor framöver.
Redan nu känns ER lättare än GEA.
Stort Tack @jang som delade med dig av ditt fina jobb och tack till @jompa68 som lagt ut en massa bra exempel :)
Tack. GEA har haft en större community under en längre tid så jag tror att den möjligtvis kan vara lite mer "mogen". Jag har inte så många olika typer av enheter så jag har inte testat allt. Men grunden i ER känner jag mig trygg med så det är oftast lätt att lägga till support. Saker som jag t.ex inte jobbat med är alarm (arm/disarm), RGB, termostater, men jag tror att basen finns där. Med det sagt så stöter ni på ngt nytt ni vill ha i ER så försöker jag fixa det asap.

Å andra sidan finns det finesser i ER som inte finns i GEA ;)
Last edited by jang on 20 Mar 2019, 08:15, edited 2 times in total.
jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

20 Mar 2019, 08:15

Det här inlägget är ganska långt, men försöker förklara hur man kan koda och testa ER på en PC istället för på HC2:an. På så sätt kan man känna sig någorlunda övertygad att scenen är korrekt innan man installerar den på HC2:an - och man slipper skrämma familjen med en massa blinkande lampor och tjutande sirener när man experimenterar med sin scen...

Hela EventRunner.lua är en HC2 scen med många finesser men samtidigt är den nu uppe i ca 2000 rader kod. Den innehåller många komplexa bitar; en parser och kompilator for EventScrip-regler, som i princip är ett programmerings språk i sig självt. En interpretator för EventScript så man kan exekvera dessa snabbt. En massa funktioner etc etc. Allt detta hade varit omöjligt att utveckla bara på HC2:an...

Från start har EventRunner scenen designats för att kunna utvecklas off-line med Windows/Mac och moderna utvecklingsverktyg. På HC2:an är det omöjligt att steppa igenom kod, inspektera variabler, sätter villkorliga brytpunkter etc. Tekniker som är i princip nödvändiga för att kunna utveckla lite mer avancerade scener.

Det började med att jag simulerade fibaro:* funktionerna men har över tid resulterat i att jag utvcklat en "Scen emulator", HC2.lua, som gör att man har en liten HC2 emulator offline som man kan köra scener i. Den supportar ER scener men även vanliga scener eller en mix av dom (inte VDs ännu, men det är inte omöjligt att det kommer)

För att köra scener på sin Windows/Mac/Linux maskin så behöver man en Lua utvecklingsmiljö. Den enda jag har provat är ZeroBrane Studio som är ett riktigt trevligt gratis open source verktyg med editor, debugger och kompilator (jag har testat VisualStudio men den har inte en tillräckligt bra Lua implementation för Mac/Linux)
-Ladda ner och installera ZeroBrane studio. https://studio.zerobrane.com/
-Ladda ner HC2.lua https://raw.githubusercontent.com/janga ... er/HC2.lua och EventRunner.lua https://raw.githubusercontent.com/janga ... Runner.lua från min GitHub och lägg de i katalogen där du kodar...
-Öppna HC2.lua oc lägg in IP, användarnamn,och lösenord till din HC2:a (varibler i början av HC2)
-Öppna EventRunner.lua i ZeroBrane studio
-Kör (debug, >, F5) EventRunner.lua och se vad som händer (det går inte att köra utan debug, men vad är poängen?)

Anledning till att vi kan köra en EventRunner scen är raden i början av scenen

Code: Select all

if dofile and not _EMULATED then _EMBEDDED={name="EventRunner",id=20} dofile("HC2.lua") end
Vad den gör är att vid uppstart så anropar den HC2.lua som i sin tur tar över och laddar in scenen som anropade den och börjar köra den. När scenen körs av HC2.lua så är variabeln '_EMULATED' sann, vilket gör att vi inte anropar emulatorn en gång till etc etc.
Det kan också vara bra att ha kod som man bara vill köra i emulatorn inom

Code: Select all

if _EMULATED then
 --- kod som bara ska köras i emulatorn, typ trigga fake events, test cases etc.
end
Den koden körs då inte när vi lyfter över scenen till HC2:an.
När vi anropar HC2.lua så definerar vi också en variabel _EMBEDDED som åtminstonde måste vara 'true' för att tala om för HC2.lua att den blivit anropad från en annan scen. Man kan också skicka med namnet på scenen och vilken sceneID den ska ha i en tabell. Man kan inte köra flera scener med samma sceneID.

Raden

Code: Select all

if dofile and not _EMULATED then _EMBEDDED={name="EventRunner",id=20} dofile("HC2.lua") end
kan vi också lägga in i en"vanlig" scen för att köra emulatorn. 'dofile' är inte definerat på HC2:an så koden är harmlös när vi flyttar över till att köra scenen på riktigt.

Det finns ett annat sätt att emulera scener på också. Vi kan i början i HC2.lua (i dess main() funktion) registrera en eller flera scener som vi vill ladda in, och sedan köra HC2.lua. Eller en mix, vi kan starta från EventRunner.lua och sedan ha HC2.lua att ladda in ytterligare scener.

HC2.lua har en del variabler och funktioner som kan vara bra att känna till.

Code: Select all

_DEMO=false                  -- Om sann, laddar en testscen
_REMOTE=false                -- Hint till emulatorn om vi kan skicka kommadon till HC2:an. 
_EVENTSERVER = 6872          -- Porten som vi startar ett web GUI på 
_SPEEDTIME = 24*180          -- Om 'false' kör i normal hastighet, annars antal timmar som vi "speedar" igenom.
_BLOCK_PUT=true              -- Om vi tillåter att resurser ändras på HC2:an (globals, scenes etc)
_BLOCK_POST=true             -- Om vi tillåter att resurser skapas på HC2:an (globals, scenes etc)
_AUTOCREATEGLOBALS=true      -- Om vi vill att "lokala" globals ska skapas första gången vi refererar till dem
_AUTOCREATEDEVICES=true      -- Om vi vill att "lokala" devices ska skapas första gången vi refererar till dem
_VALIDATECHARS = true        -- Kollar om scenkoden innehåller ogiltiga ISO koder (ett problem några av oss har)
_COLOR = true                -- Om sann, loggar med färg. 
_HC2_FILE = "HC2.data"       -- Namnet på filen där vi lagrar configurationsdata från HC2:an

_HC2_IP=_HC2_IP or "192.198.1.xx"       -- IP adress till HC2:an
_HC2_USER=_HC2_USER or "xxx@yyy"        -- namn (email) till HC2 användare
_HC2_PWD=_HC2_PWD or "xxxxxx"           -- Lösenord.
local creds = loadfile("credentials.lua") -- Det kan vara en poäng att sätta lösenord i en lokal fil som läses in, så man slipper ha dem i koden, om man postar sin scen på forumet...
if creds then creds() end
I HC2.lua, i dess main() görs en del initieringar

Code: Select all

 HC2.setupConfiguration(true,true) 
Kopierar scener, globala, devices från HC2:an till HC2.data. Första gången man har kört den kan man sätta andra argumentet till 'false', och kopierar den inte data från HC2:an utan läser bara från den lokala HC2.data filen som skapats. Det kan vara bra då det kan ta 5s att kopiera data från HC2:an vilket är lite störande när man håller på att testa sin scen. Dessutom om man testar på ett ställe där man inte har tillgång till sin HC2:a, så slipper man att den hänger medan den försöker koppla sig mot den.

Code: Select all

 if not _REMOTE or _RUNLOCAL then -- If we are remote don't try to access resources on the HC2
    HC2.localDevices(true) -- set all devices to local
    HC2.localGlobals(true) -- set all globals to local
    HC2.localRooms(true)   -- set all rooms to local
    --HC2.localScenes(true)  -- set all scenes to local
  end

Om _REMOTE är falskt så sätter vi alla resourser till "lokala", utom scener.
Att en resours (device, global, scen) är taggad som lokal betyder att vi inte skickar kommandon till den riktiga HC2:an, utan vi sparar ett lokalt tillstånd för den. Det innebär att vi har en lokal device 55, kan vi göra fibaro:call(55,"turnOn") och sedan testa om fibaro:call(55,"value")>"0" och det är sant. Dessutom postas en sourceTrigger i emulatorn när 55 slås på så att scener kan trigga på det, på samma sätt som händer på HC2:an.
Resources som läses in från HC2:an och lagras i HC2.data är "icke-lokala" vid start.

Vi kan också selektivt sätta några resources till "remote" eller "icke-lokala"
HC2.remoteDevices({66,88}) -- Sätter device 66 och 88 till att skicka kommandon till HC2:an
På så sätt kan vi testa en scen med en fejkad sensor men styra en riktig lampa etc.

HC2.loadEmbedded() -- If we are called from another scene (dofile...)
Den här raden upptäcker att HC2.la är anropad från en scen, ni kom ihåg raden
if dofile and not _EMULATED then _EMBEDDED={name="EventRunner",id=20} dofile("HC2.lua") end
och isåfall registrerar den anropande scenen

Att registrear en scen i HC2.lua görs såhär

Code: Select all

HC2.registerScene("My scene",77,"MyScen.lua")
vilket ger scenen namnet "My scene" och sceneID 77.

Observera att det inte startar scenen. Det görs först då emulatorn startar. Den postar då ett "autostart" event och alla registrerade scener som har en "%% autostart" i scen headern kommar att startas.
Om man vill starta scenen manuellt (vilket är lite opraktiskt) så måsta man ge kommandot för det.
Ett sätt är att göra fibaro:startScene(sceneID), och det finns en funktion som tillåter oss att schedulera fibaro:* anrop.

Code: Select all

HC2.runTriggers{"+/00:00;startScene(77)"}
Om vi 5s senare vill slå på en sensor för att trigga scenen

Code: Select all

HC2.runTriggers{"+/00:00;startScene(77)","+/00:05;call(77,'turnOn')"}
Att starta "fejk" trigger är oftast lättare inifrån scenen som vi kommer att se i ett senare inlägg.

HC2.logFibaroCalls()
Sätter en flagga så att det går att logga alla fibaro:* kommandon när de anropas.

Tillbaks till _EVENTSERVER och _SPEEDTIME
När emulatorn startar upp så startas även en webserver på _EVENTSERVER porten, http://localhost:6872/emu/main
Surfa in till den så kan ni se devices och scener och ge några kommandon till dessa. Gränssnittet kommer att förbättras över tiden.
Om ni slår på en lampa/sensor via webgränssnittet och ni har en scen som deklarerat den som en trigger (%% properties) i scen headern så kommer scenen att startas upp.

_SPEEDTIME kan vara bra om man har en scen som ska tända släcka lampor på vissa tider och vissa dagar eller andra villkor. Sätt _SPEEDTIME till 24*30 och emulatorn speedar igen en månad på någon sekund. Men ni ser alla loggutskrifter med rätta tider så ni kan se att lampor tänds ock släkcs som ni tänkt. Notera bara att ni bör ha taggat lamporna som lokala resurser, annars kommer det att blinka rejält...

Ok det var del1 om att koda och testa scener off-line. Jag rekommenderar det VERKLIGEN. Man blir mycket mer produktiv, mindre frustrerad, mer omtyckt av familjen, och slipper en del onödiga HC2 krascher.
Nuförtiden skriver jag alla min scener off-line.
RH_Dreambox
Proffsmedlem
Posts: 934
Joined: 03 Jan 2015, 16:49
Location: Vegby
Contact:

20 Mar 2019, 10:51

Hej jang, jag använder idag scenen "LUASceduler" för min automatik men tyckte att det vore intressant att prova på ER.
Men när jag testar så får jag ett felmeddelande som jag misstänker hör ihop med HomeTable. Jag har skapat en Global fördefinierad variabel som heter "devicemap" och dess värde har jag döpt till HomeTable". Men fyller ER-scenen på variabeln, eller hur går det till?

Och när jag kör ER i ZeroBrane Studio så startar körningen upp, men sedan händer inget mer. Konsolfönstret får först statusen "Output (running)" som omedelbart ändras till "Output (suspended)".

Output från konsolfönstret.

Code: Select all

Program starting as '"D:\Hemautomation\Zero Brane Studio\bin\lua.exe" -e "io.stdout:setvbuf('no')" "C:\Users\RH\AppData\Local\Temp\.F763.tmp"'.
Program 'lua.exe' started in 'D:\Hemautomation\Zero Brane Studio\myprograms' (pid: 10176).
Debugging session started in 'D:\Hemautomation\Zero Brane Studio\myprograms\'.
Attachments
Event_Runner.JPG
2 st HC2 4.540
jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

20 Mar 2019, 13:42

RH_Dreambox wrote:
20 Mar 2019, 10:51
Hej jang, jag använder idag scenen "LUASceduler" för min automatik men tyckte att det vore intressant att prova på ER.
Men när jag testar så får jag ett felmeddelande som jag misstänker hör ihop med HomeTable. Jag har skapat en Global fördefinierad variabel som heter "devicemap" och dess värde har jag döpt till HomeTable". Men fyller ER-scenen på variabeln, eller hur går det till?

Code: Select all

 HT =[[
  {
  "dev":{"bedroom":{"lamp":88,"motion":99},
         "kitchen":{"lamp1":66,"lamp2":67,"motion":77},
         "children":{"lamp":88,"motion":89},
         "hall":{"lamp":109,"door":108},
         "back":{"lamp":101,"door":103},
         "front":{"lamp":102,"door":104},
         "keyfob":201,
         "phones":{"bob":121,"mary":122},
         },
  "other":"other"
 }
  ]]

  --Läs in HomeTable struktur från fibaro global (eller scen)
  --local HT = type(_homeTable)=='number' and api.get("/scenes/".._homeTable).lua or fibaro:getGlobalValue(_homeTable) 
  HT = json.decode(HT)
  Util.defvars(HT.dev)                 -- Gör HomeTable definitioner tillgängliga i regler (EventScript)
  Util.reverseMapDef(HT.dev)      -- Gör HomeTable namn tillgängliga för log utskrifter.
I exemplet ovan har jag en HomeTable (i json format, samma format som du lagrar i en fibaro global). Observera att Util.defvars och Util.reverseMapDef anropas på HT.dev grenen. Om du inte har ngn 'dev' gren så ge bara HT som argument. Varför jag har gjort såhär är att jag har andra "grenar" i HomeTable som inte innehåller devices, och jag vill inte definiera upp variabler för dessa.

Om du idag inte har en homeTable, kan du bara ändra den "inline" tabell som finns som exempel i koden så att den passar dig.

Om du har en json formaterad HomeTable lagrad i en fibaro global med namn "HomeTable" (och du inte har ngn 'dev' gren) ska det se ut såhär

Code: Select all

  _homeTable = "HomeTable"
   :
  function main()
    local HT = type(_homeTable)=='number' and api.get("/scenes/".._homeTable).lua or fibaro:getGlobalValue(_homeTable) 
    HT = json.decode(HT)
    Util.defvars(HT)                 -- Gör HomeTable definitioner tillgängliga i regler (EventScript)
    Util.reverseMapDef(HT)      -- Gör HomeTable namn tillgängliga för log utskrifter.
    :

RH_Dreambox wrote:
20 Mar 2019, 10:51
Och när jag kör ER i ZeroBrane Studio så startar körningen upp, men sedan händer inget mer. Konsolfönstret får först statusen "Output (running)" som omedelbart ändras till "Output (suspended)".
Har du tryckt en gång till på F5/> ? När den startar upp så 'suspendera' den på första raden i koden och det ser ut som det i din log. Ett tryck till på '>' och den fortsätter.
RH_Dreambox
Proffsmedlem
Posts: 934
Joined: 03 Jan 2015, 16:49
Location: Vegby
Contact:

20 Mar 2019, 19:29

Tack för snabbt svar.
Nu fick jag igång ER i ZeroBraine.
Felet var att jag hade lagt HC2.lua i samma mapp där jag lagt EventRunner.lua, och det funkade inte.
När jag flyttade ut HC2.lua och lade den i "roten" för alla mina LUA-mappar så hoppade det igång.

Men det stannade när HomeTable skulle läsas in.
Om jag förstod dig rätt så skapar inte Event Runner denna HomeTable utan den måste jag först skapa på något annat sätt?
Du beskriver hur det skall fungera, men för mig som inte är någon programmerare så är det inte så lätt att hänga med :-).

Men jag skall kolla på Fibaros forum, för jag har bestämt för mig att Sancotronik eller någon annan där förklarar hur man bygger en HomeTable, jag skall kolla på den igen.
2 st HC2 4.540
MastrUsr
Medlem
Posts: 85
Joined: 25 Apr 2017, 07:24

20 Mar 2019, 22:17

RH_Dreambox wrote:Tack för snabbt svar.
Nu fick jag igång ER i ZeroBraine.
Felet var att jag hade lagt HC2.lua i samma mapp där jag lagt EventRunner.lua, och det funkade inte.
När jag flyttade ut HC2.lua och lade den i "roten" för alla mina LUA-mappar så hoppade det igång.

Men det stannade när HomeTable skulle läsas in.
Om jag förstod dig rätt så skapar inte Event Runner denna HomeTable utan den måste jag först skapa på något annat sätt?
Du beskriver hur det skall fungera, men för mig som inte är någon programmerare så är det inte så lätt att hänga med :-).

Men jag skall kolla på Fibaros forum, för jag har bestämt för mig att Sancotronik eller någon annan där förklarar hur man bygger en HomeTable, jag skall kolla på den igen.
Om du hittat en bra förklaring får du gärna länka till den här (alternativt skriva en förklaring när du lärt dig ;})

Skickat från min SM-N960F via Tapatalk

jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

21 Mar 2019, 07:51

Well, HomeTable är egentligen inte så komplicerat.
Iden är att ha en Lua tabell/struktur som innehåller alla dina deviceID och deras namn, så att du kan använda namnen i koden istället för deviceID numret. Om en device byter ID så behöver man inte ändra i koden, bara i tabellen.
Ex.

Code: Select all

HT = {lampa = 77} -- min HomeTable
fibaro:call(HT.lampa,"turnOff")
Vad vi kan göra är att lagra tabellen i en fibaro global genom att koda den till en sträng (i json format)

Code: Select all

HT = {lampa = 77} -- min HomeTable
fibaro:setGlobal("HomeTable",json.encode(HT))
och senare i en annan scen som vill ha tabellen

Code: Select all

HT =json.decode(fibaro:getGlobalValue("HomeTable"))
fibaro:call(HT.lampa,"turnOff")
Problemet med en HomeTable är att man inte kan använda den i scen-headern för att deklarera triggers. Där måste man alltid användas numret på devicen.

Code: Select all

--[[
%% properties
77 value
--]]
Man brukar gärna vilja ha en struktur på sin HomeTable. Lua tabeller kan innehålla andra Lua tabeller etc.

Code: Select all

-- min HomeTable
HT = {kok = {lampa = 77, sensor=88} ,
         sovrum =  {lampa = 99, switch=101}
        }
        
fibaro:call(HT.kok.lampa,"turnOff")
fibaro:call(HT.sovrum.lampa,"turnOff")
Fördelen är att vi kan ha namnet 'lampa' både i köket och i sovrummet utan att det krockar genom att en har prefix 'HT.kok.' och den andra 'HT.sovrum.'
Vi fick skriva 'kok' istället för 'kök' då den syntaxen inte stödjer tecken från andra språk.
Om ni har hängt på Franska fibaro forumet så har ni sett att engelska inte är något för fransmän... det finns en annan syntax för tabell konstruktion och access.

Code: Select all

-- min HomeTable
HT = {["kök"] = {lampa = 77, sensor=88} ,
         sovrum =  {lampa = 99, switch=101}
        }
        
fibaro:call(HT["kök"].lampa,"turnOff")
fibaro:call(HT["sovrum"]["lampa"],"turnOff")
..och man kan blanda. Själv föredrar jag "engelska" termer på mina variabler och den kortare "." notationen, men det är en smaksak

Ok, det här är ganska enkelt. Vad som hände var att folk tyckte det var en bra ide att automatiskt generera tabellen. Iden var att man lägger till och tar bort devices och de får nya deviceID och det är svårt att hålla reda på om man har 100+ devices etc.
https://forum.fibaro.com/topic/23942-tu ... scene-ids/
Scener och kodsnuttar skapades för att gå igenom alla devices i HC2:an och skapa en tabell där de automatiskt lades in med sitt device namn under prefixet vilket rum de tilldelats, typ i exemplet ovan. Ibland även med sektionen som ett prefix före rummet.

Det är inte helt enkelt och oftast måste namnen masseras innan de kan användas, och man måste ofta titta på tabellen för att förstå var allt hamnade så man vet hur man kan adressera de i sin kod.

Jag använde själv den här metoden ett tag men nu har jag en "handkodad" tabell i en scen. Då kan jag formatera den som jag vill. Jag kan lägga devices där jag vill (inte alltid i det rum där de är) etc. Dessutom har jag mycket annan konfigurationsdata i tabellen. Lösenord till tjänster jag anropar etc.
Men smaken är olika. Om man måste bygga om sitt HC2 system varannan dag för att det kraschar och man får nya deviceID hela tiden då kan jag förstå att man vill automatisera skapandet av en.

Om ni inte har en HomeTable vore det ju tråkigt om ni fastnade på det innan ni kan testa ER. Jag skulle rekommendera att ni gör såhär i er ER scene

Code: Select all

function main()
  local rule,define = Rule.eval, Util.defvar 

-- Lua tabell (HomeTable) med era deviceID.
  HT =
  { 
 bedroom = { lamp = 88, motion = 99},
 kitchen = {lamp1 = 66, lamp2 = 67, motion = 77},
 children = {lamp = 88, motion = 89},
 hall = {lamp = 109, door = 108},
 back = {lamp = 101,  door = 103},
 front = {lamp = 102, door = 104},
 keyfob = 201,
 phones = {bob = 121, mary = 122},
 }

  --Spara undan HomeTable struktur i fibaro global om någon annan scen vill ha tabellen
  fibaro:setGlobal("HomeTable",json.encode(HT))  -- Glöm inte att skapa "HomeTable" i HC2 panels för variabler
  Util.defvars(HT)                 -- Gör HomeTable definitioner tillgängliga i regler (EventScript)
  Util.reverseMapDef(HT)      -- Gör HomeTable namn tillgängliga för log utskrifter.
Ändra tabellen så det passar ert hus och era devices. Använd ["namn"] syntaxen om ni föredrar svenska, men kom ihåg att använda samma syntax i koden när ni använder tabellen. Och glöm inte att ni fortfarande måste använda numren i scen headern för att deklarera triggers.

Om ni redan har en HomeTable lagrad i en fibaro global så gör ni

Code: Select all

function main()
  local rule,define = Rule.eval, Util.defvar 

  HT=json.decode(fibaro:getGlobalValue("HomeTable"))
  Util.defvars(HT)                 -- Gör HomeTable definitioner tillgängliga i regler (EventScript)
  Util.reverseMapDef(HT)      -- Gör HomeTable namn tillgängliga för log utskrifter.
I ER finns raden

Code: Select all

Util.defvars(HT)
Den gör strukturen i HT tillgänglig i regler (utan HT prefix)
Ex

Code: Select all

rule("@15:00 => bedroom.lamp:on")
Om ni har svenska tecken blir det lite krångligare då ER inte supportar ISO tecken i variabelnamn (tror att det borde vara hyfsat enkelt att lägga till, ska titta på det, åtminstone för svenska)
Vad man får göra nu är att använda HT tabellen direkt och ha ['..'] syntax för de svenska namnen,

Code: Select all

rule("@15:00 => HT['kök'].lampa:on")
Addendum:
Pushat en ny version av ER. Snabbt hack. Nu kan man använda åäöÅÄÖ i variabelnamn Funkar inte med andra UTF-8 tecken för tillfället.
Ex.

Code: Select all

HT = {["kök"] = {lampa = 77, sensor=88} ,
         sovrum =  {lampa = 99, switch=101}
        }
rule("@15:00 => kök.lampa:on")
MastrUsr
Medlem
Posts: 85
Joined: 25 Apr 2017, 07:24

21 Mar 2019, 19:55

Tänkte bara komma med en kort update från min sida.

Har fått igång det via ZeroBrane och det funkar, woho!
Än så länge har jag bara gjort såhär:

Code: Select all

function main()
  local rule,define = Rule.eval, Util.defvar

  HT =
  { 
 kitchen = {koksbelysning = 42, bankbelysning = 37, koksbord = 208},
 hall = {lamp = 47},
 phones = {e= 329, j= 252},
}

--Spara undan HomeTable struktur i fibaro global om någon annan scen vill ha tabellen
  fibaro:setGlobal("HomeTable",json.encode(HT))  -- Glöm inte att skapa "HomeTable" i HC2 panels för variabler
  Util.defvars(HT)                 -- Gör HomeTable definitioner tillgängliga i regler (EventScript)
  Util.reverseMapDef(HT)      -- Gör HomeTable namn tillgängliga för log utskrifter.
  
  rule("@@00:00:05 => f=!f; || f >> log('Ding!') || true >> log('Dong!')") -- example rule logging ding/dong every 10 second
  rule("@@00:00:10 => hall.lamp:on")

  --if dofile then dofile("example_rules.lua") end     -- some more example rules to try out...
end -- main()
...och hallen tänds var 10:e sekund; magiskt! Nu ska jag bara lära mig lite fina regler så ska vi snart vara på banan! :D


Edit: @Jang, förstod jag dig rätt när du förklarade att du deklarerar enheter på samma sätt som jag gjort i kodsnutten ovan (som du fint förklarade att jag skulle ;) )?
jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

21 Mar 2019, 20:07

Prova hall.lamp:toggle :)
MastrUsr
Medlem
Posts: 85
Joined: 25 Apr 2017, 07:24

21 Mar 2019, 21:13

jang wrote:Prova hall.lamp:toggle :)
Guld :D

Såg du min fråga ovan?

Jag har lagt till en HomeTable variable i HC2. Är det nu bara att ta all koden i EventRunner.lua och klistra in i en ny scen i HC2 och sätta max antal instancer till 10?

Skickat från min SM-N960F via Tapatalk

jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

21 Mar 2019, 21:40

MastrUsr wrote:
21 Mar 2019, 21:13
jang wrote:Prova hall.lamp:toggle :)
Guld :D

Såg du min fråga ovan?
Jag har lagt till en HomeTable variable i HC2. Är det nu bara att ta all koden i EventRunner.lua och klistra in i en ny scen i HC2 och sätta max antal instancer till 10?
Ja, har man satt upp det rätt ska det bara vara att kopiera allt från den fungerande scenen i ZBS och klistra in i en scen i HC2:an (och sätt max antal instanser till 10, Run scenes: till automatic, och %% autostart i headern,
MastrUsr
Medlem
Posts: 85
Joined: 25 Apr 2017, 07:24

21 Mar 2019, 21:41

jang wrote:
MastrUsr wrote:
21 Mar 2019, 21:13
jang wrote:Prova hall.lamp:toggle :)
Guld :D

Såg du min fråga ovan?
Jag har lagt till en HomeTable variable i HC2. Är det nu bara att ta all koden i EventRunner.lua och klistra in i en ny scen i HC2 och sätta max antal instancer till 10?
Ja, har man satt upp det rätt ska det bara vara att kopiera allt från den fungerande scenen i ZBS och klistra in i en scen i HC2:an (och sätt max antal instanser till 10, Run scenes: till automatic, och %% autostart i headern,
Tack, du är grym! Tänk om alla företag man tvingas kommunicera med kunde ta efter...

Skickat från min SM-N960F via Tapatalk

sonnyboy
Proffsmedlem
Posts: 617
Joined: 26 Sep 2013, 08:05
Location: Västerås

21 Mar 2019, 22:39

Blir ju bara bättre och bättre :)
I morgon på lunchen ska jag skapa upp min HT i lua som du skriver. Har inte använt mig av det tidigare. Super att även å ä ö kan användas nu!
Fibaro HomeCenter 2
Fw 4.532 Beta
BeyondMeasure 1.10
25 Enheter, 55 Scener tidigare, 8 nu med gea GEA
jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

22 Mar 2019, 14:16

Lite mer "avancerade" ER funktioner, och tips och tricks... och inspiration.

Det finns ingen 'if-then-else' men något liknande
'|| <test1> >> <actions1> || test2> >> <actions2> ...'
Ex.

Code: Select all

rule("55:isOn => || $HomeStatus=='home' >> 66:on; 88:on || $HomeStatus=='away' >> 67:on; 77:on")
När lampa 55 tänds så tänder vi olika lampor beroende på en fibaro globals värde.
Annat exempel

Code: Select all

rule([[sensor:breached =>
      || 07:00..09:00        >> lampa:value=40
      || 09:00..12:00        >> lampa:value=30
      || 12:00..sunset-01:00 >> lampa:value=20
      || sunset-01:00..21:00 >> lampa:value=50
      || 21:00..23:00        >> lampa:value=80
      || 23:00..07:00        >> lampa:value=20
      ]])
När en sensor triggas så dimmrar vi en lampa till olika värden beroende på tid på dygnet.
Tips. I Lua kan vi definera strängar med '[[ ... ]]', och fördelen är att de kan sträcka sig över flera rader. Det tillåter oss att formatera reglerna lite snyggare som ovan. Den andra fördelen är att man kan använda både ".." och '..' för strängar inuti [[..]]. Annars om man definerar en regel med rule("...") så kan man bara använda '..' inuti den.

Ett vanligt sätt att skriva en 'if-then' på höger-sidan är att använda 'och', som skrivs '&'

Code: Select all

rule("sensor:breached => 07:00..09:00 & wday('sun') & lampa:on")
Först testar den om vi är i rätt tidsintervall, sedan om det är rätt dag, och isåfall tänder lampan.

Vi kan hantera SceneActivation events, som typiskt kommer från dimmrar eller switchar som har support för det. Det gör att vi kan trigga på dubbel eller tripple klicks, och "hold" and "release". Funktionen vi triggar på i en regel är <deviceID>:scene.
Det finns fördefinerade värden för S1 och S2 (switchar/dimmrar brukar supporta 2 knappar)

Code: Select all

switch=23
rule("switch:scene==S2.double => log('Någon dubbelklickade på knappen')")

rule([[switch:scene => action = switch:scene;
       || action==S1.click   >> log('Enkel-klick S1')
       || action==S1.double  >> log('Dubbel-klick S1')
       || action==S1.tripple >> log('Tripple-klick S1')
       || action==S1.hold    >> log('Håller inne S1')
       || action==s1.release >> log('Släpper upp S1')
       || action==S2.click   >> log('Enkel-klick S2')
       || action==S2.double  >> log('Dubbel-klick S2')
       || action==S2.tripple >> log('Tripple-klick S2')
       || action==S2.hold    >> log('Håller inne S2')
       || action==s2.release >> log('Släpper upp S2')
       ]])
Sista regeln triggar på att vi får ett SceneActivation event (switch:scene), tilldelar variabeln 'action' värdet och testar sedan
värdet vilken typ av action vi fick.
'SceneActivation' måste deklareras i scen-headern under %% properties

Code: Select all

%% properties
23 SceneActivation
Två andra events är 'CentralSceneEvent' som typiskt kommer från knappsatser, samt 'AccessControlEvent' som kommer från olika typer av lås. Den förstnämda triggas med <deviceID>:central, och den sistnämnda med <deviceID>:access. Båda returnerar 'data' delen av eventet så vi kan testa mot dess olika värden

Code: Select all

lock = 99
keyfob = 100
rule("lock:access.status=='Lock' => log('Locked by user %s',lock:access.name)")  
rule("lock:access.status=='Unlock' => log('Unlocked by user %s',lock:access.name)") 

rule("keyfob:central.keyId=='2' => log('Turning on lights in house'); allLampsInHouse:on")
'CentralSceneEvent' och 'AccessControlEvent' måste deklareras i scen-headern under %% events

Code: Select all

%% events
100 CentralSceneEvent
99 AccessControlEvent
Ett annat vanligt problem är att vi inte vill automatiskt tända/släcka en lampa om någon just har tänt/släck manuellt.
<deviceID>:manual returnerar antal sekunder sedan en switch/lamps ändrats manuellt, eller -1 om det var en regel som gjort det.
Ex.

Code: Select all

rule("sensor:breached & lampa:manual > 00:05 => lampa:on")
rule("for(00:10,sensor:safe) & lampa:manual > 00:10 => lampa:off")
I det här fallet tänder vi bara lampan om det var minst 10min sedan någon tände/släckte lampan.
...och vi släcker om det var minst 10min sedan någon tände lampan.


Skicka meddelanden tilt mobiler görs med <mobileID>:msg=<string>
Ex.

Code: Select all

grind=44
phone=103
rule("grind:breached => phone:msg='Grinden har öppnats'")
Funktionen log(..) används för att logga en text i konsolen. Den tar samma formatteringsargument som Lua's string.format. Förutom att logga till konsolen så returnerar log strängen. Det gör att vi kan skriva

Code: Select all

rule("grind:breached => phone:msg=log('Grinden har öppnats %s',osdate('%c'))")
Vi både loggar till konsolen och skickar det till telefonen.

Vi har sett att vi kan testa om ett uttryck har varit sant en viss tid med 'for'. Ibland vill vi fortsätta och exekvera en aktion om det har varit sant 2x tiden, 3x tiden etc. 'repeat' hjälper oss med det. Dessutom returnerar 'repeat' hur många gånger vi har repeterat.

Code: Select all

rule("for(00:10,grind:breached) => phone:msg=log('Grinden har varit öppen i %s minuter',10*repeat())")
Vi kan också ge ett värde till 'repeat' hur många gånger max den ska repetera.

Code: Select all

rule("for(00:10,grind:breached) => phone:msg=log('Grinden har varit öppen i %s minuter',10*repeat(5))")
Den här gången får vi bara 5 påminnelser.

En liten mer avancerad ljuskontroll som tar hänsyn till lux. 2 luxsensorer och en lampa som ska tändas.

Code: Select all

luxs={room.lux1,room.lux2}
rule("sum(luxs:lux)/size(luxs) <= 100 => room.lampa:on")
Om meddelvärdet av de 2 ljus sensorerna är mindre eller lika med 100 tänd lampan.
luxs:lux kommer att returnera en tabell med luxvärden för sensorerna, ex {50,150}, sum({50,150}) blir 200, och size({50,150}) är 2 (antalet element i tabellen), så medelvärdet blir här 100.

Det finns mycket mer finesser i ER men det här var en start...
RH_Dreambox
Proffsmedlem
Posts: 934
Joined: 03 Jan 2015, 16:49
Location: Vegby
Contact:

22 Mar 2019, 14:53

Först ett stort tack för ditt jättearbete med ER. Det verkar betydligt enklare att komma igång med det jämfört med GEA.
Men jag har ett litet programmerings-problem nu när det börjar bli ljusare ute.

Hur skriver jag att en lampa skall tändas tex 07:00, men inte om solen redan gått upp?
Jag har kollat mängder av kod utan att hitta hur man gör. Förmodligen busenkelt, men...

Och så ett litet önskemål....
Det vore toppen om schemaläggningen kunde synkroniseras efter tex. omstart eller ett strömavbrott.
LUASceduler har den finessen, så om något är ur fas i schemat så behöver man bara spara om koden så synkas alla scener och enheter igen.
2 st HC2 4.540
jang
Medlem
Posts: 81
Joined: 05 Jan 2014, 00:44
Location: Stockholm

22 Mar 2019, 15:15

RH_Dreambox wrote:
22 Mar 2019, 14:53
Först ett stort tack för ditt jättearbete med ER. Det verkar betydligt enklare att komma igång med det jämfört med GEA.
Men jag har ett litet programmerings-problem nu när det börjar bli ljusare ute.

Hur skriver jag att en lampa skall tändas tex 07:00, men inte om solen redan gått upp?
Jag har kollat mängder av kod utan att hitta hur man gör. Förmodligen busenkelt, men...

Och så ett litet önskemål....
Det vore toppen om schemaläggningen kunde synkroniseras efter tex. omstart eller ett strömavbrott.
LUASceduler har den finessen, så om något är ur fas i schemat så behöver man bara spara om koden så synkas alla scener och enheter igen.
Tack. Problem med solen.

Code: Select all

rule("@07:00 & sunrise > 07:00 => lampa:on")
Dvs, varje dag kl 07:00 triggas regeln, men vi har ett extra villkor att sunrise måste vara efter 07:00

Catchup av regler är lite trixit i allmänhet.
För '@' daily regler finns villkoret 'catch'.

Code: Select all

rule("@{catch,10:00} =>  lampa:on") -- om det är efter 10:00 när vi startar upp kör regeln ändå, och schedulera igen for 10:00 nästa dag
Dessutom kan man villkora den med ett intervall så att den inte körs om det är långt efter 10:00

Code: Select all

rule("@{catch,10:00} & 10:00..12:00 =>  lampa:on") -- om det är efter 10:00 (men max 12:00) när vi startar upp kör regeln ändå, och schedulera igen for 10:00 nästa dag
Är det andra regler än typ '@' som du behöver catchup för?
Post Reply