attempt to concatenate a boolean value

Här kan du som nybörjare ställa dina frågor utan att skämmas
Post Reply
Adde80
Medlem
Posts: 71
Joined: 18 Nov 2016, 01:06
7

I farten igen..

Har en kod som ibland ger debug fel "Line 77: attempt to concatenate a boolean value".. Det skumma är att det inte är varje gång.

Detta är en snutt från koden

Code: Select all

if
  (fibaro:getGlobalValue("TimeOfDay") == "Day")
    then
       if
           (os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60)) and ((w1+w2+w3+w4+w5+w6+w7+w8) < usage)
           then --borta
             if
               (fibaro:getGlobalValue("PresentState") == "Home")
               then
        --fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60)))) 
       	 fibaro:debug("Borta")
         fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60))) .." min")
             fibaro:setGlobal("PresentState", "Away");
              else
               fibaro:debug("Borta")
               end
Rad 77 som felet verkar komma från är
fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60))) .." min")

Lokala variablen delayShort är nu satt till 30..

Varför uppstår felet, och varför random? Vad betyder eg boolean value? :)
User avatar
RH_Dreambox
Z-Wave Kung
Posts: 1192
Joined: 03 Jan 2015, 16:49
9
Location: Vegby
Contact:

Boolean value eller boolskt värde är Sant / Falskt. Din kod försöker bearbeta ett falskt värde.
Min gamla ombyggda HC2 har fått ett nytt liv och min HC3 är nu nedkopplad.
HC2 med Home Assistant har blivit en riktig Game Changer och nu har jag hemautomatik på riktigt.
https://www.zwaveforum.se/viewtopic.php?t=7087
Adde80
Medlem
Posts: 71
Joined: 18 Nov 2016, 01:06
7

Tack!
Då blir nästa fråga vilket format det är på värdena som bearbetas.

Lokala variablerna som bearbetas i exemplet ovan (eg a1, a2 osv) kommer från:
local a1 = fibaro:getModificationTime(7,'value') --Sovrum tak
och
local w1 = fibaro:getValue(80, "power") --Ebba tak

Så där jag tror det går snett ibland är (os.time() -(math.max(a1,a2,a3, osv..)) >= (delayShort * 60))
Nu som ni kanske listat ut inte jag som skrivit ursprungskoden, så har vissa frågetecken..:) Labbar mest för att försöka få lite grepp på LUA.
Men som jag tolkar det så tas den faktiska tiden minus det högsta värdet från a1-a16 från första delen (math.max) och jämförs med om det är större eller lika med 30 (delayShort) * 60.

Frågan är formatet på resultatet i os.time - math.max..?

Jag la in en debug tidigare i koden för att läsa ut följande:

Code: Select all

fibaro:debug("Sovrumsbelysning ändrade värde: "..os.date("%H:%M",a1))
och får ut följande.

[DEBUG] 12:21:12: Sovrumsbelysning ändrade värde: 08:58

Skulle ju kunna labba lite med delayShort variabeln för att undvika detta fel, men vill ju fatta vad som görs. :D

Hela LUA scenen btw är tänkt att funka som en "är vi hemma eller borta" scene.
FredrikKarlsson
Medlem
Posts: 65
Joined: 08 Aug 2016, 20:21
7

Kolla om ett tonumber() kring alla uttag av ModificationTime. Har för mig att de kommer som strängar.


Helt orelaterade problemet så tänker jag att approachen du valt kan bli rörig att förstå i efterhand. Fundera på om du inte istället skulle göra detta i antingen två scener eller en scen med två lägen. Som jag förstår problemet du vill lösa så vill du veta sist någon av en samling enheter ändrade sin status. En lättare lösning kan vara att sätta upp de enheter och värden du är intresserade av att studera under property i scenens header. Så när dessa förändras kommer scenen att köras. Du tar ut ID för enheten som triggade scenen via getSourceTrigger() och sparar den tidsangivelsen i en global variabel (variable panel). På så sätt har du hela tiden lagrat tidpunkten då senaste eventet hände, som du kan checka i alla scener om du vill. Det förnekar uttrycken du behöver, gör det inte nödvändigt att kolla alla enheter varje gång och ger en kod som är lättare att bygga ut och underhålla tror jag.
Så skulle i alla fall jag fundera på att göra, men det kan förstås också finnas anledning att inte göra så..
Adde80
Medlem
Posts: 71
Joined: 18 Nov 2016, 01:06
7

Ah tack!
Dock vette fan om jag blev nå klokare. :D
tonumber() från ett uttag från ModificationTime gav 1484922836, vilket motsvarar 15:33 på den enheten.
Det skumma var att boolean felet verkade en smula random. Givetvis är det inte random, men jag fattar inte iaf. :)

Hur som helst så har du en poäng. Detta är troligtvis inte smidigaste sättet.
Det jag vill uppnå är ju att använda dels effekt användning samt senast någon antingen syntes av nån PIR eller tryckte på nån lampknapp för att på så sätt veta om vi är hemma eller inte.
Målet är väl att få lite belysning automatiskt när man kliver in i huset när Global Variabel är satt till Away..
Det jag har att leka med nu är ett antal PIR, en jäkla massa dimmers och ett gäng switchar.
Mobilen skulle man ju kunna använda, men verkar vara ganska lurigt, samt ev behöva byta router för att få det lira fullt.
Sen har man såklart Fibaros GPS tracker..
vonStayes
Ny medlem
Posts: 12
Joined: 03 Dec 2013, 22:23
10
Location: Lerum

Hej,

Anledningen till att du får felet "attempt to concatenate a boolean value" på raden:
fibaro:debug(((os.time() -(math.max(a1,a2,osv)) >= (delayShort * 60))) .." min")
... är att du har ">=" (större än eller lika med) där.

Det resulterar i en boolean. En variabel som bara kan ha två värden, true eller false. Det försöker du sedan konkatenera (slå ihop) med textsträngen "min". Det går inte att slå ihop en boolean med en textsträng.

Du kan ju testa att byta ut ">=" med "-" (ett minustecken) istället så får du vettigare utskrifter.
Alternativt ta bort ">= (delayShort * 60)" från raden.

Anledningen till att du bara får felet ibland är att det ligger inne i if-satserna. Du får bara felmeddelandet då rad 77 körs och det gör den bara om TimeOfDay == "Day" och det stora uttrycket (os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60)) and ((w1+w2+w3+w4+w5+w6+w7+w8) < usage) är sant och PresentState == "Home".

Ett tips är att bryta ner de stora uttrycken i mindre delar genom att använda lokala variabler. Du kan då göra debug-utskrifter på de lokala variablerna och enklare se vad som händer. Du får då även kod som är lättare att förstå och och göra ändringar i.
Adde80
Medlem
Posts: 71
Joined: 18 Nov 2016, 01:06
7

Ok ok, då är jag med..
Det var alltså när mina egna försök att debugga triggades av if-satserna som problemet uppstod. :)
Tanken var ju att försöka få ut debug utskrifter så jag vet exakt när Home blir Away.

(os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60)) and ((w1+w2+w3+w4+w5+w6+w7+w8) < usage)

Om ovan båda påståenden blir true så ändras global variabel till Away.. Det jag inte riktigt förstår är tanken bakom delayShort * 60.
Låt säga att os.time är 12:00 och vi drar hemifrån.. a15 (PIR entrédörren) kommer då få senaste ModificationTime 12:00..
Om vi drar till med 1 timma senare så borde os.time - senaste tiden för modifikation vara 60 min..
w1-8 kommer vara avstängda och således vara mindre än usage lokala variabeln.
Mitt frågetecken är då delayShort (som i nuvarnde fall är 50) * 60.. Det ger 3000. Gissar att det inte är millisekunder..

När jag skriver ut lite info ser det ut så här:
fibaro:debug("TEST sov nere: "..tonumber(a1))
[DEBUG] 22:35:14: TEST sov nere: 1485033763

local a1 = fibaro:getModificationTime(7,'value') --Sovrum tak
[DEBUG] 22:35:14: Sovrumsbelysning ändrade värde: 22:22

Alltså är 22:22 = 1485033763.. Tänkte att ok, oavsett hur den räknar eller vilket format det är så borde nuvarande tid - senast ändrade tid >= 3000 resultera i true/false..
Vilket det säkert gör, men skulle ju vilja veta exakt hur lång tid kommer det ta innan variabeln ändras till Away..

För att ytterligare snurra till det så har jag några fler tonumber exempel..
Tid vid körning av raden 22:24
1485033845 = 22:24
1485033763 = 22:18
1485039422 21:10
1485030360 21:26

Det konstiga är att 21:10 är större än 22:24..

Sen kanske detta är en återvändsgränd jag är och snurrar i :D men vill inte ge upp.. Måste ju greppa detta nångång. :P

Btw, här är hela koden.. Underlättar kanske. :)

Code: Select all

--[[
%% autostart
%% properties
%% events
%% globals
--]]

while true do
  
local delayShort = 50
local delayLong = 340
local usage = 30 --watt

local a1 = fibaro:getModificationTime(7,'value') --Sovrum tak
local a2 = fibaro:getModificationTime(15,'value') --Klk nere tak
local a3 = fibaro:getModificationTime(23,'value') --Toa nere tak
local a4 = fibaro:getModificationTime(31,'value') --Tvättstuga tak
local a5 = fibaro:getModificationTime(39,'value') --Groventré
local a6 = fibaro:getModificationTime(27,'value') --Entre tak
local a7 = fibaro:getModificationTime(35,'value') --kök
local a8 = fibaro:getModificationTime(43,'value') --Vard.rum vägg
local a9 = fibaro:getModificationTime(162,'value') --Matbord
local a10 = fibaro:getModificationTime(80,'value') --Ebba tak
local a11 = fibaro:getModificationTime(92,'value') --Leah tak
local a12 = fibaro:getModificationTime(100,'value') --Toa uppe tak
local a13 = fibaro:getModificationTime(114,'value') --Halltak uppe gång
local a14 = fibaro:getModificationTime(63,'value') --Kontor tak
local a15 = fibaro:getModificationTime(194,'value') --rörelse entré
local a16 = fibaro:getModificationTime(188,'value') --rörelse öv







local w1 = fibaro:getValue(80, "power") --Ebba tak
local w2 = fibaro:getValue(92, "power") --Leah tak
local w3 = fibaro:getValue(162, "power") --Matbord
local w4 = fibaro:getValue(7, "power") --Sovrum tak
local w5 = fibaro:getValue(27, "power") --Entré tak
local w6 = fibaro:getValue(35, "power") --kök
local w7 = fibaro:getValue(43, "power") --Vard.rum vägg
local w8 = fibaro:getValue(114, "power") --Halltak uppe gång

fibaro:debug("TEST sov nere: "..tonumber(a1))
fibaro:debug("TEST klk nere: "..tonumber(a2))
fibaro:debug("TEST toa: "..tonumber(a3))
fibaro:debug("TEST tvätt: "..tonumber(a4))
fibaro:debug("TEST PIR ö.v: "..tonumber(a16))
  
  
fibaro:debug("Sovrumsbelysning ändrade värde: "..os.date("%H:%M",a1))
fibaro:debug("Klädkammare nere ändrade värde: "..os.date("%H:%M",a2))
fibaro:debug("Toalett nere ändrade värde: "..os.date("%H:%M",a3))
fibaro:debug("Tvättstuga ändrade värde: "..os.date("%H:%M",a4))
fibaro:debug("Groventré tak ändrade värde: "..os.date("%H:%M",a5))
fibaro:debug("Entré ändrade värde: "..os.date("%H:%M",a6))
fibaro:debug("Köksbelysning ändrade värde: "..os.date("%H:%M",a7))
fibaro:debug("Vardagsrum vägg ändrade värde: "..os.date("%H:%M",a8))
fibaro:debug("Matbord ändrade värde: "..os.date("%H:%M",a9))
fibaro:debug("Ebbas rum ändrade värde: "..os.date("%H:%M",a10))
fibaro:debug("Leahs rum ändrade värde: "..os.date("%H:%M",a11))
fibaro:debug("Toalett uppe ändrade värde: "..os.date("%H:%M",a12))
fibaro:debug("Halltak uppe gång ändrade värde: "..os.date("%H:%M",a13))
fibaro:debug("Kontor ändrade värde: "..os.date("%H:%M",a14))
fibaro:debug("Rörelsedetektor entré noterade rörelse: "..os.date("%H:%M",a15))
fibaro:debug("Rörelsedetektor ö.v noterade rörelse: "..os.date("%H:%M",a16))
fibaro:debug("Watt: "..(w1+w2+w3+w4+w5+w6+w7+w8))

  
if
  (fibaro:getGlobalValue("TimeOfDay") == "Day")
    then
       if
           (os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60)) and ((w1+w2+w3+w4+w5+w6+w7+w8) < usage)
           then --borta
             if
               (fibaro:getGlobalValue("PresentState") == "Home")
               then
       --fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayShort * 60)))) 
       	 fibaro:debug("Borta")
         fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) .." min")))
             fibaro:setGlobal("PresentState", "Away");
              else
               fibaro:debug("Borta")
               end
           else --fortfarande hemma
             if
               (fibaro:getGlobalValue("PresentState") == "Away")
               then
              fibaro:debug("Hemma")
               fibaro:setGlobal("PresentState", "Home");
               else
             fibaro:debug("Hemma")
             fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)))/ 30) .." mins")
              end
         end
   else
         if
           (os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)) >= (delayLong * 30)) --and ((w1+w2+w3+w4+w5+w6+w7+w8) < usage)
           then --borta
             if
               (fibaro:getGlobalValue("PresentState") == "Home")
               then
              fibaro:debug("Borta")
             fibaro:setGlobal("PresentState", "Away");
              else
               fibaro:debug("Borta")
               fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)))/ 30) .." min")
               end
           else --fortfarande hemma
             if
               (fibaro:getGlobalValue("PresentState") == "Away")
               then
              fibaro:debug("Hemma")
               fibaro:setGlobal("PresentState", "Home");
               else
             fibaro:debug("Hemma")
             fibaro:debug(((os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16)))/ 30) .." min")
                end
      end
end
fibaro:sleep(15000);
  
end
Förresten det går inte ändra så att senaste raden kommer överst i debug loggen? Drygt att skrolla till botten hela tiden. :)
Iof har ju sina fördelar oxå..
FredrikKarlsson
Medlem
Posts: 65
Joined: 08 Aug 2016, 20:21
7

Nej, ge inte upp. Jag tror du skulle bli hjälp av att se till att alla uttryck som du använder, t.ex.

Code: Select all

os.time() -(math.max(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16))
och

Code: Select all

(w1+w2+w3+w4+w5+w6+w7+w8)
istället lagrades i en vanliga variabel. Det ökar läsbarheten i koden rätt mycket, och kan minska risken för ett par problem som kan uppstå när man kopierar kod.
Adde80 wrote:.
Tid vid körning av raden 22:24
1485033845 = 22:24
1485033763 = 22:18
1485039422 21:10
1485030360 21:26

Det konstiga är att 21:10 är större än 22:24..

Ja, det är konstigt. Jag använder denna tjänst http://www.epochconverter.com och får då

Code: Select all

1485033845 = Your time zone: 2017-01-21 22:24:05 GMT+1:00
1485033763 = Your time zone: 2017-01-21 22:22:43 GMT+1:00
1485039422 = Your time zone: 2017-01-21 23:57:02 GMT+1:00
1485030360 = Your time zone: 2017-01-21 21:26:00 GMT+1:00
så det är något skumt med din "21:10". Kan du kolla den kanske?

Är det sista tidpunkten som rörelse upptäcktes och nuvarande konsumtion som du vill ha koll på ?
* om rörelse sågs för mer än delayShort minuter sedan, så är ni borta
* om er konsumption är mindre än 30 W på de valda enheterna så är ni borta

Vill bara vara säker på att jag i hastigheten har missförstått logiken så att jag råder dig fel..[/color]
FredrikKarlsson
Medlem
Posts: 65
Joined: 08 Aug 2016, 20:21
7

Adde80 wrote:Ah tack!
Dock vette fan om jag blev nå klokare. :D


:-) Vi får se om jag kan göra dig lite klokare gällande hur jag menade genom ett exempel. Jag lagrar rörelse separat i våningar, men koden nedan kanske kan ge dig lite ledning hur man kan utnyttja HC2s eventsystem lite mer effektivt (i alla fall enklare kod)

Du måste ha en global variable (Variable pane, övre delen) som heter 'lastMovementDown'. För dig kan den heta 'lastMovement' istället.

Code: Select all

--[[
%% properties
355 lastBreached
379 lastBreached
183 lastBreached
390 lastBreached
476 lastBreached
%% events
%% globals
--]]

local toDebugBefore = fibaro:getGlobal("lastMoveDown")
fibaro:debug("Senast lagrade rörelsen nere var ".. toDebugBefore .. " (" .. os.date("%Y-%m-%d %X",toDebugBefore) .. ")")

local trigger = fibaro:getSourceTrigger()
local triggeringID = tonumber(trigger['deviceID'])
local movement = tonumber(fibaro:getValue(triggeringID, "lastBreached"))

fibaro:setGlobal("lastMoveDown",movement);

local toDebugAfter = fibaro:getGlobal("lastMoveDown")
fibaro:debug("Senast lagrade rörelsen nere är nu ".. toDebugAfter .. " (" .. os.date("%Y-%m-%d %X",toDebugAfter) .. ")")
Som du ser så drar jag nytta av att man kan sätta upp triggers (många) och sedan helt enkelt ta reda på vilken enhet som körde scenen denna gång. Rörelsesensorer och dörrsensorer har en "lastBreached" (studera gärna enheterna i Lua-editorn i HC2) och det är det jag lagrar. Om det är en annan typ av enhet (typ om någon tänder på toaletten så är man mest troligt hemma) så får man kolla "value" istället.
Koden ser till att senaste rörelsen hela tiden finns i den globala variabeln.

När du har detta kan du sätta upp en scen som bevakar dina rörelsevariabler för att göra något. Jag sätter en variabel borta/hemma. Den kan i sin tur trigga scener.

Code: Select all

--[[
%% properties
%% events
%% globals
lastMoveUp
lastMoveDown
--]]


local movementUpstairs = tonumber(fibaro:getGlobal("lastMoveUp"))
local movementDownstairs = tonumber(fibaro:getGlobal("lastMoveDown"))
local lastMovement = math.max(movementUpstairs,movementDownstairs)
fibaro:debug("Senast lagrade rörelsen var ".. lastMovement .. " (" .. os.date("%Y-%m-%d %X",lastMovement) .. ")")

local currentTime = os.time()
local awayDelay = 2 * 60 * 60; -- Ingen rörelse på 2 timmar

-- Om tidsdifferensen mellan nuvarande tid och senaste rörensen är mindre än 2 timmar så är vi hemma.
if ((currentTime - lastMovement) < awayDelay ) then
    fibaro:setGlobal("PresentState","Home")
    fibaro:debug("Status satt till hemmma (Home)")
else
    fibaro:setGlobal("PresentState","Away")
    fibaro:debug("Status satt till borta (Away)")
end

För kraftberäkningarna kan du göra något liknande, fast då kan det vara lika bra att inte dela upp processen i flera scener, för du måste ju då hur som helst dra ut konsumtionen för varje enhet varje gång för att beräkna medelvärdet. Det är ju inte en enhets senaste status som gäller då, utan totalen.. Nå, om den är > ett värde, sätt till Home.

Fördelen med denna approach kan vara att koden blir enklare att uppdatera, du kan lättare lägga till t.ex. en rörelsesensor utan att uppdatera alla delar av koden. Och, jag tror att lösningen är enklare att följa, då du har delat upp problemet i små problem som du löser.[/color]
Adde80
Medlem
Posts: 71
Joined: 18 Nov 2016, 01:06
7

@FredrikKarlsson
Nej, ge inte upp.
Hell no! Har ju bara börjat.. :lol:
Är det sista tidpunkten som rörelse upptäcktes och nuvarande konsumtion som du vill ha koll på ?
* om rörelse sågs för mer än delayShort minuter sedan, så är ni borta
* om er konsumption är mindre än 30 W på de valda enheterna så är ni borta

Vill bara vara säker på att jag i hastigheten har missförstått logiken så att jag råder dig fel..
Jo men det var tanken när jag hittade denna LUA nånstans.
Om rörelse eller ändrat värde på någon dimmer (local variabler a1-16) så är vi rimligtvis hemma och en globalvariabel håller då Home. Men för att inte behöva ha typ 2 timmars fördröjning på att ändra till "away" så kommer ju local variabler w1-8 in i bilden. Säg att vi sitter och käkar en sjukt lång middag :D eller kanske kollar på en film. Då är kan ju tiden springa iväg utan att a1-16 "rörs" eller att vi rör oss inom nån PIRs område. Tanken var då att är vi fortfarande hemma så är någon av enheterna som följs i w1-8 på och därför är Home fortfarande sant.

Så helt enkelt en LUA som ändras till Away när vi inte är hemma. Har lite scener redan som styr alla spottar i fönstersmygarna efter lux.. Blir det "lagom" mörkt så tänds de och släcks när det blir ljust, förutsatt att en annan variabel är Day.
Tanken var att kunna köra denna så att om vi vart borta och kommer hem och min Lux variabel är "Dark" så tänds div lampor upp när PIR vid entren triggas.. Förusatt att Global variable "PresentState" = Away, vilken är den jag försöker få till.

http://www.epochconverter.com !! Super, tack!!
Du har nog rätt.. Jag måste ha fått nån siffra fel när jag skrev av.

Ska skapa lite nya Scener baserat på dina tips! Tack igen! :)
FredrikKarlsson
Medlem
Posts: 65
Joined: 08 Aug 2016, 20:21
7

Ok, jag förstår. Vad sägs då om att göra en enkel scen som triggas varje gång Power-värdet ändras på någon enhet som du är intresserad av. Den scenen tar ut summan av förbrukningen och puttar in den i en global variabel (och går sedan i vila 5min eller så skulle jag föreslå, och du ser till att bara en instans av scenen körs åt gången).

Det värde du lagrat i din power-variabel kan du sedan konsultera i scenen som sätter Hemma/Borta.

Det handlar så klart mycket om tycke och smak när det gäller implementationer av en lösning på ett problem, men kanske kan denna uppdelade approach till problemet hjälpa dig komma fram till en bra lösning totalt sett, som kanske också inte är så klurig att underhålla sedan.
Post Reply