Efter att flera frågat om rätt liknande utmaningar, så inser jag att en litet försök till att bistå i vad en variabel är och hur man kan skapa/nyttja dom är nog en rätt bra sak. I samband med detta kommer jag också som hastigast täcka in Listor - och med Listor syftar jag på vad man ibland refererar till vektorer (fast i LUA påminner det mera om indexerade matriser - men mer om det senare).
I förra tråden, LUA för nybörjare - Del 1, så gick jag som enklast igenom en enklare scen och hur de kan skapas. Jag förutsätter således att du läst igenom den tråden, och kanske börjar känna dig nyfiken på lite mera avancerade tankar och idéer.
Variabler finns det, i LUA och Fibaro HomeCenter 2, två varianter av:
- Lokala enbart i EN enda scen / VD (Virtual Device)
- Globala som nås från alla scener / VD
Sedan finns en variant av variabel som vi kan kalla listor, eller vektorer - men det är lite svårare så jag tar det senare.
Om vi börjar med Lokala variabler, så definierar vi dom enklast såhär:
Code: Select all
local RadioKanal
Code: Select all
RadioKanal = tostring(math.random(23,26))
Vad sker ovan, jo variabel RadioKanal, som är local, existerar enbart i denna scen (för detta är från en scen), och innehåller en slumpvis vald RadioKanal mellan "23" och "26" - slumptalsfunktionen "math.random(23,26)" returnerar ett heltal mellan 23 och 26, men vi behöver det i textformat (sträng som det kallas), varför vi även använder "tostring()" - det som står innanför parentes kommer konverteras från numeriskt värde till text.
Man kan såklart undra varför man skall göra just detta, en RadioKanal mellan 23 och 26 - jo i mitt exempel, som är taget från min "Radio @Home" scen, så startas alltså radion i bakgrundsläge och det sker genom att man senare ropar på en VD där man trycker knapp 23 till knapp 26 (kommer till det någon gång), varpå min hemmabio startar upp och börjar spela den valda internet radio kanalen när man är hemma (och således stänger av allt när man går hemifrån, mycket trevlig feature) .
I vilket fall, detta är alltså en enkel Lokal variabel. Och den fungerar alltså bara i den scen eller VD man skriver koden i.
En Global variabel har sitt värde generellt hela tiden i HC2, och den måste hanteras lite annorlunda. Först så skapar man variabeln, och det sker under en av panelerna i HC2 (klicka på Variabelpanel - det rödmarkerade området):
När man kommer in i denna panel, så kommer man få i praktiken TVÅ val - det beror lite på hur man avser att den globala variabeln skall fungera. Man får välja mellan en vanlig variabel som kan innehålla vilket värde som helst, eller en variabel med fördefinierade värden (se de två rödmarkerade områdena):
Som ni ser har jag (för detta är en skärmdump från min egna HC2) bara EN vanlig global variabel, och ELVA fördefinierade globala variabler. Vi skall nu prova att skapa en variabel av varje typ, så vi får prova på hur det är och upplevs. Vi börjar med en vanlig global variabel, klicka på den övre rödmarkerade knappen "Lägg till":
Vi skapar variabeln "Test" och spara den genom att trycka på knappen "Spara":
Och som synes så har vi nu skapat en ny variabel:
Det var enkelt. Och så är det även med en fördefinierad variabel, alltså en variabel som bara kan innehålla fasta i förväg bestämda värden. Vi börjar precis som ovan med att trycka "Lägg till" men nu den NEDRE knappen, och valet blir lite annorlunda:
Vi kallar således variabel för "Test2", och som fasta värden väljer vi:
Och trycker precis som förra gången "Spara"
Varpå det ser ut såhär:
Om man tittar lite mera noga så ser man, markerat med blått, två ytterligare symboler på samma rad som variabeln "Test":
Den första symbolen, ser ut som en penna, är mycket riktigt den man klickar på för att ÄNDRA möjliga värden på varibeln. Den med kryss är samma sak som att RADERA variabeln. Samma sak gäller ovan för den första variabeln vi skapade, där finns dock bara ett kryss för RADERING, men å andra sidan har vi ett fritextfält där man kan mata in valfritt värde för variabel.
OBS OBS OBS OBS OBS
Om man manuellt ändrar värdet på en variabel under denna panel, så kommer scener som har dessa variabler som triggervärden INTE att köras (se LUA för nybörjare - Del 1) - att ändra en variabel här inne i variabelpanelen startar således INTE några scener - det sker bara när man ändrar en variabel i en scen eller VD. Och detta är mycket viktigt att komma ihåg!!!
OBS OBS OBS OBS OBS
Således nu när vi skapat våra globala variabler så kan vi börja nyttja dom. Och globala variabler, oberoende av vilken av dessa två varianter som vi har, behöver anropas på ett speciellt sätt för att refereras till. Dvs man kan inte bara skriva:
Code: Select all
Test = 1
Som synes har jag markerat "getGlobalValue()" och klickar jag på denna så kommer full syntax upp på vald variabel i scenens LUA fönster:
OBServera att det kommit lite mera kod, och utan att gå för djupt så fungerar det lite såhär: Vi behöver hämta en global variabel, det krävs en funktion för att göra det, och den tillhandahåller fibaro åt oss (det är dom som implementerat denna variant av LUA): fibaro:getGlobalValue("Test") - alltså tillhandahållare:funktion(något att göra) - ja lite grovt förenklat alltså... Nej det är inte 100% korrekt, utan förenklat...
Men sådär lär det inte fungera speciellt bra Utan vi får nu hitta på något, som att t.ex. skapa en lokal variabel och flytta över värdet, och så skriver vi ut det med fibaro:debug funktionen (om ni undrar vad de två små punkterna gör på slutet av den koden så är det en "concatination" - dvs man slår ihop två det första med det andra och presenterar det som en enda massa):
Kul - så nu har vi fått tag i värdet, men hur manipulerar vi värdena då? Ja lokala variabler räcker det med ett likamed tecken "=", det har vi sett tidigare, men om man skall TESTA ett värde så krävs DUBBLA likamed tecken "==", och om vi samtidigt passar på att skriva lite mera LUA kod så kan det se ut såhär:
Alltså, först skapar vi den lokala variabeln "lokal_test", sedan hämtar vi värdet från den globala variabeln "Test", vi skriver ut båda värdena, och sedan tilldelar vi "lokal_test" värdet 2 (istf värdet noll som vi skapade den globala variabeln "Test" med som ursprungsvärde, dvs "default value" som det så vackert kallas), skriver ut detta för att verifiera att vi ändrat värdet, sedan testar vi om värdet av den lokala variabeln "lokal_test" verkligen är just två, och om det är det - och mycket skall till för att det inte skall vara det i denna hårdkodade variant av scen - så flyttar vi in värdet från den lokala variabeln "lokal_test" till den globala variabeln "Test". Och för att slutligen verifiera att vi verkligen ändrat värdet, så skriver vi ut värdet igen. Men vi kan också, såklart, verifera värdet genom att gå till variabelpanelen där vi skapade den globala variabeln:
Som synes har den globala variabeln "Test" ändrat värdet.
Jag vill också göra er observanta på att funktionen för att tilldela en global variabel ett värde alltså syntaxmässigt skiljer sig åt från att hämta:
Code: Select all
fibaro:getGlobalValue("Test")
Code: Select all
fibaro:setGlobal("Test", lokal_test)
Här kommer således hela koden för denna experiment scen:
Code: Select all
--[[
%% properties
%% globals
--]]
--start here
local lokal_test
lokal_test = fibaro:getGlobalValue("Test")
fibaro:debug("Variabeln Test har värdet: "..fibaro:getGlobalValue("Test"))
fibaro:debug("Variabeln lokal_test har värdet: "..lokal_test)
lokal_test = 2
fibaro:debug("Variabeln lokal-test, efter manipulering, har värdet: "..lokal_test)
if ( lokal_test == 2 ) then
fibaro:setGlobal("Test", lokal_test)
end
fibaro:debug("Variabeln Test har värdet: "..fibaro:getGlobalValue("Test"))
Ja precis som planerat. Samma gäller för globala variabler med fasta värden, men i dessa fall kan man alltså bara tilldela den globala variabel dessa fasta värden. Och vi skapade en sådan global variabel "Test2" - vad kan man nyttja den till då? Jo i följande exempel så låter vi denna globala variabel visa på om det är ljust (Soligt) eller mörkt (natt eller moln ivägen för solen) och kan på så sätt få reda på via en global variabel hur status är (och ett av skälen till att välja denna lösning är att om man vill ändra känsligheten på brytgränsen för soligt/mörkt så är det bara EN plats att ändra på - men variabeln kan nyttjas på många platse, kodar man varibeln fast med ett fast värde att testa mot så måste man ändra på flera platser eller skapa en variabel som innehåller brytgränsen osv):[DEBUG] 19:42:22: Variabeln Test har värdet: 0
[DEBUG] 19:42:22: Variabeln lokal_test har värdet: 0
[DEBUG] 19:42:22: Variabeln lokal-test, efter manipulering, har värdet: 2
[DEBUG] 19:42:22: Variabeln Test har värdet: 2
Code: Select all
--[[
%% autostart
%% properties
54 value
104 value
%% globals
--]]
-- Ta bort scener med samma ID som denna, så att bara EN av denna scene körs.
if (fibaro:countScenes() > 1) then fibaro:abort() end
-- Ta reda på om scenen startats genom trigger eller genom värdeändring på
-- någon av de IDn som angivits ovan under %% properties. Detta får man reda
-- på genom att läsa av funktionen fibaro:getSourceTrigger
local startSource = fibaro:getSourceTrigger()
if (
-- Om scenen startats genom ändrat värde, kolla om värdet för ljussensorerna
-- är högre än 280 för BÅDA sensorerna för att skapa viss tröghet i scenen.
( tonumber(fibaro:getValue(54, "value")) > 280 and
tonumber(fibaro:getValue(104, "value")) > 280 and
-- Och förutsätt att det tidigare värdet för den globala variabeln "Test2"
-- var "Mörkt" så att vi inte skapar onödig körning av koden
fibaro:getGlobalValue("Test2") == "Mörkt" )
-- Någon har startat denna scen genom att köra manuellt
or startSource["type"] == "other"
)
then
-- Tilldela den globala variabeln "Test2" värdet "Soligt" eftersom det är
-- tillräckligt ljust ute för att kalla det soligt (obs en ljus mulen dag
-- kommer att trigga också, då det indirekta ljuset som faller på ljussensorn
-- är mer än tillräckligt för att trigga värdeförändring)
fibaro:setGlobal("Test2", "Soligt")
end
if (
-- Om scenen startats genom ändrat värde, kolla om värdet för ljussensorerna
-- är lägre än 230 för NÅGON av sensorerna.
( ( tonumber(fibaro:getValue(54, "value")) < 230 or
tonumber(fibaro:getValue(104, "value")) < 230 ) and
-- Och förutsätt att det tidigare värdet för den globala variabeln "Test2"
-- var "Soligt" så att vi inte skapar onödig körning av koden
fibaro:getGlobalValue("Test2") == "Soligt" )
)
then
-- Tilldela den globala variabeln "Test2" värdet "Soligt" eftersom det är
-- tillräckligt ljust ute för att kalla det soligt (obs en ljus mulen dag
-- kommer att trigga också, då det indirekta ljuset som faller på ljussensorn
-- är mer än tillräckligt för att trigga värdeförändring)
fibaro:setGlobal("Test2", "Mörkt")
end
-- Debug area - här skriver vi till slut ut värdena så vi vet vad som hände:
fibaro:debug("Ljussensor 54 har värdet: "..fibaro:getValue(54, "value"))
fibaro:debug("Ljussensor 104 har värdet: "..fibaro:getValue(104, "value"))
fibaro:debug("Den globala variabel Test2 har värdet: "..fibaro:getGlobalValue("Test2"))
Som ni ser ovan så har vi alltså:
%% autstart
%% propertis
%% globals
Autostart innebär att scenen körs så fort vi sparar den, eller HC2 startas om - autostart alltså. Mycket praktiskt, men man måste såklart vara försiktig, om man inte är det, så kan man råka starta andra scener som t.ex. triggas av värden på gloabal variabler som används som triggers.
Properties innebär att scenen körs så fort som värdet för den eller de enheter som listas upp. I exemplet ovan är det alltså två av mina ljussensorer som kan trigga scenen, deviceID = 54 eller deviceID = 104.
Globals innebär att scenen körs så fort som värdet på den globala variabeln förändras - och det är här man alltså från en scen som sätter värdet på en global variabel kan starta en kedjereaktion så att andra scener startas såfort som värdet ändrats. Mycket praktiskt, men som sagt, kedjereaktioner kan ibland - speciellt om man gör komplexa LUA scener - skapa problem som man kanske inte alltid tänkt på. Rätt använt är det grymt häftigt, fel gjort kan man nog få en och annan utmaning...
Om vi tittar igen på samma bild igen:
Så ser vi att jag även inkluderade en liten rad som dödar samma scen om den redan körs, så att man bara har EN variant av scenen som är aktiv och körs - extra viktigt om man har loopar som är oändliga eller liknande, eller "sleep" funktioner som hänger sig och dyligt...
Vidare så ser vi en annan sak som ibland skymtas:
Code: Select all
-- Ta reda på om scenen startats genom trigger eller genom värdeändring på
-- någon av de IDn som angivits ovan under %% properties. Detta får man reda
-- på genom att läsa av funktionen fibaro:getSourceTrigger
local startSource = fibaro:getSourceTrigger()
I vilket fall, såhär blir utskriften av debug raderna på slutet om allt fungerar som det skall:
Och tittar vi på variabelpanelen så har mycket riktigt värdet ändrats (vi skapade variabeln "Test2" med värdet "Soligt" från början):[DEBUG] 20:21:51: Ljussensor 54 har värdet: 2
[DEBUG] 20:21:51: Ljussensor 104 har värdet: 22
[DEBUG] 20:21:51: Den globala variabel Test2 har värdet: Mörkt
[DEBUG] 20:29:44: Ljussensor 54 har värdet: 10
[DEBUG] 20:29:44: Ljussensor 104 har värdet: 22
[DEBUG] 20:29:44: Den globala variabel Test2 har värdet: Mörkt
Så vad kan man göra med den globala variabeln? Jo om man tittar på vad jag skrev ovan så kan vi starta en scen med hjälp av just värdeförändring på en global variabel, t.ex. något i stil med detta som tänder resp släcker våra fönsterlampor när solen går ned/i moln eller kommer fram/stiger upp på morgonen:
Code: Select all
--[[
%% autostart
%% properties
%% globals
Test2
--]]
--kill any extra instances of the same scene
if (fibaro:countScenes() > 1) then fibaro:abort() end
-- Mörkt, tänd ljusen i fönstren
if ( fibaro:getGlobalValue("Test2") == "Mörkt" )
then
-- Julbelysning
fibaro:call(146, "turnOn")
-- Skapa en fördröjning mellan 3.5 sekunder till 4.5 sekunder
fibaro:sleep(math.random(3500,4500))
-- Vanliga fönsterbelysningen
fibaro:call(48, "turnOn")
end
-- Ljust, släck ljusen i fönstren
if ( fibaro:getGlobalValue("Test2") == "Soligt" )
then
-- Vanliga fönsterbelysningen
fibaro:call(48, "turnOff")
-- Skapa en fördröjning mellan 3.5 sekunder till 4.5 sekunder
fibaro:sleep(math.random(3500,4500))
-- Julbelysning
fibaro:call(146, "turnOff")
end
Jag hade ursprungligen tänkt ta detta med variabel listor (vektorer) men jag spårade ur lite ovan så jag tar det i del 2.2 ?