Radiator LUA code

Hierbij de code die ik voor elk van de verwarmingen apart heb aangegeven. Per kamer heb je zo een scene nodig om de radiatoren van die kamer juist aan te sturen.

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

local heaterid=133 --id of the thermostatic valve
local heaterfloor="gelijkvloers" -- for logging
local heaterroom="living" -- for logginh

local extopen1=56  --id of the external door/window sensor
local extopen2=189  --id of the external door/window sensor
local extopen3=0  --id of the external door/window sensor
local exttemp=196  --id of the external temperature sensor
local extmotion=149  --id of the external motion detector
local extmanplus=37 --id of the external heat switch +1 degrees

local buitenwarmtemp=19 --temperatuur outside with heating off
local errortemp=18

local iemandthuis=tonumber(fibaro:getGlobalValue("G_IemandThuis"))
local tempbuiten=tonumber(fibaro:getGlobalValue("G_TempBuiten"))

--per "soort" een scrn : vanuut,vanminuut,totuur,totminuut,setvalue
-- voor een normale weekdag
local thuisweekdag={
  {0,0,6,0,18},
  {6,1,20,0,20},
  {20,1,22,0,21},
  {22,1,23,0,20},
  {23,1,23,59,18}
  }

local thuisweekenddag={
  {0,0,6,0,18},
  {6,1,23,0,20},
  {23,1,23,59,18}
  }

local nietthuis={
  {0,0,17,0,18},
  {17,1,18,0,19},
  {18,1,19,00,20},
  {19,01,23,59,18}
  }

local buitenwarm={
  {0,0,23,59,16}
  }

local parsetemp=nietthuis
local schemaName="nietthuis"

if (tempbuiten>=buitenwarmtemp) then
  parsetemp=buitenwarm
  schemaName="buitenwarm"
elseif (iemandthuis==0) then
  parsetemp=nietthuis
  schemaName="nietthuis"
elseif ((tonumber(os.date("%w"))~=0) and (tonumber(os.date("%w"))~=6)) then
  parsetemp=thuisweekdag
  schemaName="thuisweekdag"
else
  parsetemp=thuisweekenddag
  schemaName="thuisweekenddag"
end

if (extopen1~=0) then
  if (tonumber(fibaro:getValue(extopen1,"value"))==1) then
    parsetemp=buitenwarm
    schemaName="verluchtingopen"
  end
end
if (extopen2~=0) then
  if (tonumber(fibaro:getValue(extopen2,"value"))==1) then
    parsetemp=buitenwarm
    schemaName="verluchtingopen"
  end
end

fibaro:debug("T ext.:"..tempbuiten.."; Selected Schema: "..schemaName)

local time=tonumber(os.date("%H"))*60+tonumber(os.date("%M"))
local setlevel=errortemp
local levelttl=0
local logtotime="--:--"

for i=1,#parsetemp do
  local mintime=parsetemp[i][1]*60+parsetemp[i][2]
  local maxtime=parsetemp[i][3]*60+parsetemp[i][4]
  if ((time>=mintime) and (timetonumber(fibaro:getValue(exttemp,"ui.curtemp.value"))) then
    fibaro:setGlobal("G_KetelWarmte",1)
    fibaro:debug("Demanding Boiler Heat: "..setlevel.." requested "..fibaro:getValue(exttemp,"ui.curtemp.value").." measured")
  end
end

fibaro:debug("Selected Temp: "..setlevel.." for: "..levelttl.." minutes until "..logtotime)

local currentlevel=tonumber(fibaro:getValue(heaterid,"value"))
if (currentlevel~=setlevel) then
  fibaro:call(heaterid,"setTargetLevel",setlevel)
  fibaro:debug("SETTING - Current setLevel: "..currentlevel.." new level: "..setlevel)
  fibaro:call(heaterid,"setTime",tonumber(os.time(t))+levelttl*60)
end

Verwarming concept in stapjes

Hieronder een zo compleet mogelijke uitleg van hoe ik de structuur heb opgebouwd rond de sturing van mijn verwarming. Ik begin met de meest eenvoudige stapjes en voeg dan stilletjes zaken toe om te komen tot de uiteindelijke programmatie.

img093

Een basis kamer met een radiator en een schema.

Stel, je hebt een kamer met 1 radiator. Nu wil je een tijdsafhankelijke sturing, zodat je bijvoorbeeld het volgende kan instellen:

  • tussen 8u en 10u: 21°C
  • tussen 10u en 15u: 19°C
  • tussen 15u en 22u: 20°C
  • tussen 22u en 8u: 18°C

Om dit volgens een LUA sturing handig op te splitsen moet je een stapje ervoor toevoegen en het laatste stapje opsplitsen:

  • 00:00 tot 08:00 : 18°C
  • 08:01 tot 10:00 : 21°C
  • 10:01 tot 15:00 : 19°C
  • 15:01 tot 22:00 : 20°C
  • 22:01 tot 23:59 : 18°C

Dit schema vertaalt zich in de finale LUA in een structuur:

local schema_x={
  {00,00,08,00,18},
  {08,01,10,00,21},
  {10,01,15,00,19},
  {15,01,22,00,20},
  {22,01,23,59,18}
  }

En dan heb je nog de code die de temperatuur hieruit haalt die nodig is op dat moment:

local parsetemp=schema_x

local time=tonumber(os.date("%H"))*60+tonumber(os.date("%M"))  --huidige tijd
local setlevel=errortemp -- errortemp wanneer er iets misgaat (18°C)
local levelttl=0 -- hoe lang de temperatuur geldig is
local logtotime="--:--" -- voor de log

for i=1,#parsetemp do
  local mintime=parsetemp[i][1]*60+parsetemp[i][2]
  local maxtime=parsetemp[i][3]*60+parsetemp[i][4]
  if ((time>=mintime) and (time<maxtime)) then
    setlevel=parsetemp[i][5]
    levelttl=(maxtime-time-1)
    logtotime=parsetemp[i][3]..":"..parsetemp[i][4]
  end
end

Een kamer met meerdere schema’s.

In sommige kamers wil je misschien meerdere schema’s gebruiken. Eentje voor als het een weekdag is, en een ander voor wanneer het een dag in het weekend is. Naar analogie met hierboven krijg je dan verschillende local’s (hieronder ingekort weergegeven)

local thuisweekdag ={
    {00,00,08,00,18},
    {08,01,22,00,20},
    {22,01,23,59,18}
    }

local thuisweekenddag = {
    {00,00,09,00,18},
    {09,01,23,00,21},
    {23,01,23,59,18}
    }

En de code om het juiste schema te selecteren:

local parsetemp=nil
local schemaName=""

if ((tonumber(os.date("%w"))~=0) and (tonumber(os.date("%w"))~=6)) then
  parsetemp=thuisweekdag
  schemaName="thuisweekdag"
else
  parsetemp=thuisweekenddag
  schemaName="thuisweekenddag"
end

Toevoeging: niemand-thuis schema

Wanneer er niemand thuis is, kan je de verwarming best een graadje lager schakelen. Dit bestaat dus uit twee zaken, enerzijds een soort van “schakelaar” of alarmsysteem-codepaneel waarmee je aan de HC2 kan laten weten of er iemand thuis is of niet, anderzijds een schema specifiek voor de radiator dat geselecteerd moet worden wanneer er niemand thuis is.

Bij mij is dit bepaald door de globale variabele “G_IemandThuis”.

local nietthuis={
  {0,0,23,59,18}
  }

En de selectiecode:

local iemandthuis=tonumber(fibaro:getGlobalValue("G_IemandThuis"))
local parsetemp=nietthuis
local schemaName="nietthuis"

if (iemandthuis==0) then
  parsetemp=nietthuis
  schemaName="nietthuis"
elseif ((tonumber(os.date("%w"))~=0) and (tonumber(os.date("%w"))~=6)) then
  parsetemp=thuisweekdag
  schemaName="thuisweekdag"
else
  parsetemp=thuisweekenddag
  schemaName="thuisweekenddag"
end

Toevoeging: schema afhankelijk van de buitentemperatuur

Wanneer het buiten meer dan 18 graden is, hoef je eigenlijk binnen geen verwarming meer op te zetten vind ik. Vandaar dat ik een schema hiervoor heb toegevoegd.

local buitenwarm={
  {0,0,23,59,16}
  }

En de selectie hier is weer gebaseerd op een globale variabele, die ingevuld wordt vanuit een buitenweerstation of bijvoorbeeld vanuit Yahoo Weather.

local buitenwarmtemp=16 --temperatuur buiten zonder verwarming

local tempbuiten=tonumber(fibaro:getGlobalValue("G_TempBuiten"))

if (tempbuiten>=buitenwarmtemp) then
  parsetemp=buitenwarm
  schemaName="buitenwarm"
elseif (iemandthuis==0) then
  parsetemp=nietthuis
  schemaName="nietthuis"
elseif ((tonumber(os.date("%w"))~=0) and (tonumber(os.date("%w"))~=6)) then
  parsetemp=thuisweekdag
  schemaName="thuisweekdag"
else
  parsetemp=thuisweekenddag
  schemaName="thuisweekenddag"
end




Een kamer met een radiator en een temperatuur sensor (en dus ook aansturing van de warmtevraag naar de ketel)

Wanneer je een sensor hebt hangen in de kamer, die de actuele temperatuur meet, kan je uit het verschil met de ingestelde waarde in de thermostaatkop bepalen of de ketel warmte moet produceren of niet. In mijn opstelling zet ik op voorhand een globale variabele op 0, ga ik alle radiator-LUA-settings schema’s af en als nadien die globale variabele op 1 staat, betekent dit dat er ergens een kamer warmte nodig heeft.

Enerzijds betekent dit een toevoeging in de scene om de radiatorkop in te stellen

local exttemp=74  --id van de externe temperatuursensor

if (exttemp~=0) then
  if (setlevel>tonumber(fibaro:getValue(exttemp,"value"))) then
    fibaro:setGlobal("G_KetelWarmte",1)
    fibaro:debug("Demanding Boiler Heat: "..setlevel.." requested "..fibaro:getValue(exttemp,"value").." measured")
    fibaro:sleep(100)
  end
end

Anderzijds dus ook een aparte scene die alle 5 minuten loopt en alle scenes van de radiatoren afloopt en daarna de ketel al dan niet om warmte vraagt.

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

local heatsetids={30,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48}
-- de id's van alle set-scenes van de Danfoss Radiatorkoppen
local nestDevice=196
local ketelHeating=0

while true do
  fibaro:debug("Running scene at: "..os.date())
  local setp=tonumber(fibaro:getValue(nestDevice,"ui.settemp.value"))
  local curlivtmp=tonumber(fibaro:getValue(nestDevice,"ui.curtemp.value"))  
  fibaro:debug("SetPoint: "..setp.."  -  Current: "..curlivtmp)
  if (setp>curlivtmp) then
    ketelHeating=1
  else
    ketelHeating=0
  end
  fibaro:setGlobal("G_KetelWarmte",0)
  for i=1,#heatsetids do
    fibaro:startScene(heatsetids[i])
  end
  fibaro:sleep(10*1000)
  if (tonumber(fibaro:getGlobalValue("G_KetelWarmte"))==1) then
    fibaro:debug("Outcome: G_Ketelwarmte=1")
    if (ketelHeating==1) then
      if (setp>curlivtmp) then
        fibaro:debug("Boiler Heat requested - boiler still active")
      else
        fibaro:debug("Boiler Heat requested - boiler still active - updating temp")
	    fibaro:call(nestDevice,"setProperty", "ui.setpoint.value", curlivtmp+1)
      end  
    else
      fibaro:call(nestDevice,"setProperty", "ui.setpoint.value", curlivtmp+1)
      fibaro:debug("Boiler Heat requested - Activating boiler setting temp to: "..curlivtmp+1)
      fibaro:sleep(100)
    end
  else
    fibaro:debug("Outcome: G_Ketelwarmte=0")
    if (ketelHeating==0) then
      if (setp<curlivtmp) then
        fibaro:debug("Not Requesting Boiler Heat - boiler still inactive")
      else
	    fibaro:call(nestDevice,"setProperty", "ui.setpoint.value", curlivtmp-1)
        fibaro:debug("Not Requesting Boiler Heat - boiler still inactive - updating temp")
        fibaro:sleep(1000)
      end
      --check for temp and adjust not heating temp
    else
      fibaro:call(nestDevice,"setProperty", "ui.setpoint.value", curlivtmp-1)
      fibaro:sleep(1000)
      fibaro:debug("Not Requesting Boiler Heat - Deactivating boiler setting temp to: "..curlivtmp-1)
    end
  end
  fibaro:sleep(4*60*1000) -- slaap 4 minuten
end

In de scene hierboven zit ineens de integratie van mijn eigen gecreëerde NEST Thermostaat aansturing in. Zie daarvoor de specifieke pagina verderdoor.

Toevoeging: open/toe sensor(en)

Wanneer je een kamer aan het verluchten bent, is het niet nodig van de verwarming te laten opstaan. Als je een “open-toe sensor” op de raam installeert, kan je dit schema ook ineens mee verwerken in de scene voor de instelling van de radiatorkop. Ik heb ervoor gekozen om dan het “buitenwarm” schema toe te passen

local extopen=72  --id van de externe open deur/raam sensor

if (extopen~=0) then
  if (tonumber(fibaro:getValue(extopen,"value"))==1) then
    parsetemp=buitenwarm
    schemaName="verluchtingopen"
  end
end

Toevoeging: bewegingssensor

Indien er een kamer is waar een bewegingsdetector hangt, kan je bijvoorbeeld de temperatuur automatisch een graadje hoger zetten, wanneer er het afgelopen half uur nog beweging gedetecteerd is. Perfect om bijvoorbeeld de living op 20°C te zetten normaal gezien, en als er iemand aanwezig is net dat extra beetje gezellige warmte te creëren.

local extmotion=0  --id van de externe bewegingsdetector

if (extmotion~=0) then
  if ((os.time()-fibaro:getValue(extmotion, "lastBreached"))<1800) then
    setlevel=setlevel+1
  end
end

Toevoeging: extra warmte – knop

Wil je toch nog iets extra doen voor de mensen waarmee je samenwoont die het gemakkelijk kou hebben, kan je in een kamer een extra drukknop toevoegen zodat je manueel de temperatuur een graadje hoger kan schakelen.

local extmanplus=37 --id van een externe heat schakelaar +1 graden

if (extmanplus~=0) then
  if (tonumber(fibaro:getValue(extmanplus,"value"))==1) then
    setlevel=setlevel+1
  end
end

Finale LUA script voor de scene die de radiator instelt

Het finale LUA script ziet er dan zo uit:

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

local heaterid=133 --id van de thermostaatkop
local heaterfloor="gelijkvloers"
local heaterroom="living"

local extopen1=56  --id van de externe open deur/raam sensor
local extopen2=189  --id van de externe open deur/raam sensor
local extopen3=0  --id van de externe open deur/raam sensor
local exttemp=196  --id van de externe temperatuursensor
local extmotion=149  --id van de externe bewegingsdetector
local extmanplus=37 --id van een externe heat schakelaar +1 graden

local buitenwarmtemp=19 --temperatuur buiten zonder verwarming
local errortemp=18

local iemandthuis=tonumber(fibaro:getGlobalValue("G_IemandThuis"))
local tempbuiten=tonumber(fibaro:getGlobalValue("G_TempBuiten"))

--per "soort" een scrn : vanuut,vanminuut,totuur,totminuut,setvalue
-- voor een normale weekdag
local thuisweekdag={
  {0,0,6,0,18},
  {6,1,20,0,20},
  {20,1,22,0,21},
  {22,1,23,0,20},
  {23,1,23,59,18}
  }

local thuisweekenddag={
  {0,0,6,0,18},
  {6,1,23,0,20},
  {23,1,23,59,18}
  }

local nietthuis={
  {0,0,17,0,18},
  {17,1,18,0,19},
  {18,1,19,00,20},
  {19,01,23,59,18}
  }

local buitenwarm={
  {0,0,23,59,16}
  }

local parsetemp=nietthuis
local schemaName="nietthuis"

if (tempbuiten>=buitenwarmtemp) then
  parsetemp=buitenwarm
  schemaName="buitenwarm"
elseif (iemandthuis==0) then
  parsetemp=nietthuis
  schemaName="nietthuis"
elseif ((tonumber(os.date("%w"))~=0) and (tonumber(os.date("%w"))~=6)) then
  parsetemp=thuisweekdag
  schemaName="thuisweekdag"
else
  parsetemp=thuisweekenddag
  schemaName="thuisweekenddag"
end

if (extopen1~=0) then
  if (tonumber(fibaro:getValue(extopen1,"value"))==1) then
    parsetemp=buitenwarm
    schemaName="verluchtingopen"
  end
end
if (extopen2~=0) then
  if (tonumber(fibaro:getValue(extopen2,"value"))==1) then
    parsetemp=buitenwarm
    schemaName="verluchtingopen"
  end
end

fibaro:debug("T ext.:"..tempbuiten.."; Selected Schema: "..schemaName)

local time=tonumber(os.date("%H"))*60+tonumber(os.date("%M"))
local setlevel=errortemp
local levelttl=0
local logtotime="--:--"

for i=1,#parsetemp do
  local mintime=parsetemp[i][1]*60+parsetemp[i][2]
  local maxtime=parsetemp[i][3]*60+parsetemp[i][4]
  if ((time>=mintime) and (time<maxtime)) then
    setlevel=parsetemp[i][5]
    levelttl=(maxtime-time-1)
    logtotime=parsetemp[i][3]..":"..parsetemp[i][4]
  end
end

if (extmotion~=0) then
  if ((os.time()-fibaro:getValue(extmotion, "lastBreached"))<1800) then setlevel=setlevel+1 end end if (extmanplus~=0) then if (tonumber(fibaro:getValue(extmanplus,"value"))==1) then setlevel=setlevel+1 end end if (exttemp~=0) then if (setlevel>tonumber(fibaro:getValue(exttemp,"ui.curtemp.value"))) then
    fibaro:setGlobal("G_KetelWarmte",1)
    fibaro:debug("Demanding Boiler Heat: "..setlevel.." requested "..fibaro:getValue(exttemp,"ui.curtemp.value").." measured")
  end
end

fibaro:debug("Selected Temp: "..setlevel.." for: "..levelttl.." minutes until "..logtotime)

local currentlevel=tonumber(fibaro:getValue(heaterid,"value"))
if (currentlevel~=setlevel) then
  fibaro:call(heaterid,"setTargetLevel",setlevel)
  fibaro:debug("SETTING - Current setLevel: "..currentlevel.." new level: "..setlevel)
  fibaro:call(heaterid,"setTime",tonumber(os.time(t))+levelttl*60)
end

Aansturing van de ketel

Er zijn een paar mogelijkheden om je centrale verwarmingsketel aan te sturen, afhankelijk van het soort ketel dat je hebt. Wanneer er gewerkt wordt met een eenvoudige “Aan-Uit” thermostaat kan je hiervoor een Fibaro Relais gebruiken. Wat ook mogelijk is, is een intelligente thermostaat, voordeel hiervan is dat je indien je een OpenTherm compatibele thermostaat hebt, zoals ik, deze de ketelsturing ook nog intelligent moduleert. Ik heb hiervoor een NEST thermostaat gekozen. De aansturing daarvan is wel wat moeilijker, maar hiervoor heb ik een oplossing gemaakt.

img094

Voor de finale gedocumenteerde LUA zie de specifieke pagina

Een simpele drukknop gebruiken voor een dimmer

Stel, je hebt een drukknop die niet elektrisch gekoppeld is aan een dimmende lamp. Nu wil je die drukknop gebruiken om die lamp toch te laten aan gaan, vervolgens in 4 stappen door de dimmer te gaan en weer uit te gaan. Onderstaand vind je de LUA code hiervoor.
Vul de waarde voor id1 met het ID van de drukknop en id2 met het ID van de schakelaar en vervang {{id1}} door het ID van de drukknop.

--[[
%% properties
{{id1}} value
%% events
%% globals
--]]
local id1=xx
local id2=xx
fibaro:debug('Change detected in '..fibaro:getName(id1)..' with id '..id1..'. New Value: '..fibaro:getValue(id1,'value'))
local currentstate = tonumber(fibaro:getValue(id2, 'value'))
fibaro:debug('Current state of dimmer'..fibaro:getName(id2)..' : '..currentstate)
if (currentstate <= 90) then
currentstate=currentstate+25
fibaro:call(id2, "setValue",currentstate)
fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to level "..currentstate.." %")
else currentstate=0
fibaro:call(id2, "turnOff")
fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to OFF")
end

Een drukknop gebruiken om een contact aan en uit te doen

Stel, je hebt een drukknop die niet elektrisch gekoppeld is aan een lamp. Nu wil je die drukknop gebruiken om die lamp toch te laten aan en weer uit gaan. Onderstaand vind je de LUA code hiervoor.
Vul de waarde voor id1 met het ID van de drukknop en id2 met het ID van de schakelaar en vervang {{id1}} door het ID van de drukknop.

--[[
%% properties
{{id1}} value
%% events
%% globals
--]]
local id1=xx
local id2=xx
fibaro:debug('Change detected in '..fibaro:getName(id1)..' with id '..id1..'. New Value: '..fibaro:getValue(id1,'value'))
local currentstate = fibaro:getValue(id2, 'value')
fibaro:debug('Current state of switch '..fibaro:getName(id2)..' : '..currentstate)
if ((currentstate == "0") and (fibaro:getValue(id1,'value')=="1")) then
fibaro:call(id2, "turnOn")
fibaro:debug("Turning ON switch "..fibaro:getName(id2))
else
fibaro:call(id2, "turnOff")
fibaro:debug("Turning OFF switch "..fibaro:getName(id2))
end

Een simpele drukknop met 2 functies (2 x schakelen)

Om een simpele drukknop te gebruiken om 2 toestellen aan te sturen moet je een onderscheid kunnen maken tussen een “Single Click” = éénmaal drukken en een “Double Click” = tweemaal kort achtereen drukken.

Indien de simpele drukknop geen twee of meer aparte profielen ondersteunt (zoals bvb de NodOn Soft Remote wel doet) kan je met wat programmeren in LUA toch wel zo iets benaderen.

Hiertoe moet je 3 globale variabelen declareren (in het “Variables Panel”) per schakelaar en 2 LUA scenes maken.

1. Globale Variabelen

Maak er 3 aan; voor de naamgeving heb ik hier een conventie gebruikt om ze later gemakkelijk te identificeren. Vervang {{id1}} door het ID van de schakelaar/drukknop, {{id2}} door het ID van de eerste module die je wil schakelen met een enkele druk en {{id3}} door het ID van de derde module die je met dubbel drukken wil schakelen.

  • Push{{id1}}_1
  • Push{{id1}}_2
  • Push{{id1}}_3

2. LUA script voor het druk-event

AdvDrukknop{{id1}}_DRUK

--[[
%% properties
{{id1}} value
%% events
%% globals
--]]
local id1={{id1}} --schakelaar
local id2={{id2}} --advanced drukknop scene
fibaro:debug("Button Push Time: "..tonumber(os.time()))
fibaro:setGlobal("Push"..id1.."_3",fibaro:getGlobalValue("Push"..id1.."_2"))
fibaro:setGlobal("Push"..id1.."_2",fibaro:getGlobalValue("Push"..id1.."_1"))
fibaro:setGlobal("Push"..id1.."_1",tonumber(os.time()))
fibaro:sleep(200)
fibaro:startScene(id2)

3. LUA script voor de schakeling

--[[
%% properties
%% events
%% globals
--]]
local id1=37 -- de schakelaar
local id2=34 -- module 1 - enkele klik
local id3=48 -- module 2 - dubbele klik
local p3=fibaro:getGlobalValue("Push"..id1.."_3")
local p2=fibaro:getGlobalValue("Push"..id1.."_2")
local p1=fibaro:getGlobalValue("Push"..id1.."_1")
fibaro:debug('Change detected in '..fibaro:getName(id1)..' with id '..id1)
local db=10
local d1=p1-p2
local d2=p2-p3
fibaro:debug('Delta 1: '..d1..' Delta 2: '..d2)
if ((d10)) then
fibaro:debug("Double click on "..fibaro:getName(id1).." detected ")
fibaro:setGlobal("Push"..id1.."_1",0)
fibaro:setGlobal("Push"..id1.."_2",0)
fibaro:setGlobal("Push"..id1.."_3",0)
--basis drukknop routine bij double click (enkel toggle, geen overeenkomst met indicator)
local currentstate = fibaro:getValue(id3, 'value')
fibaro:debug('Current state of switch '..fibaro:getName(id3)..' : '..currentstate)
if (currentstate == "0") then
fibaro:call(id3, "turnOn")
fibaro:debug("Turning ON switch "..fibaro:getName(id3))
else
fibaro:call(id3, "turnOff")
fibaro:debug("Turning OFF switch "..fibaro:getName(id3))
end
elseif ((d1>=db) and (d2==0)) then
fibaro:debug("Single click on "..fibaro:getName(id1).." detected ")
fibaro:setGlobal("Push"..id1.."_1",0)
fibaro:setGlobal("Push"..id1.."_2",0)
fibaro:setGlobal("Push"..id1.."_3",0)
--basis drukknop routine bij single click
local currentstate = fibaro:getValue(id2, 'value')
fibaro:debug('Current state of switch '..fibaro:getName(id2)..' : '..currentstate)
if ((currentstate == "0") and (fibaro:getValue(id1,'value')=="1")) then
fibaro:call(id2, "turnOn")
fibaro:debug("Turning ON switch "..fibaro:getName(id2))
else
fibaro:call(id2, "turnOff")
fibaro:debug("Turning OFF switch "..fibaro:getName(id2))
end
else
fibaro:setGlobal("Push"..id1.."_1",0)
fibaro:setGlobal("Push"..id1.."_2",0)
fibaro:setGlobal("Push"..id1.."_3",0)
end

Verwarming Routines Start

Start hier

Aangezien de verwarming en de scripting er rond ondertussen uitgebreide vormen aan het aannemen is, ga ik hier in de toekomst een apart deel van de site aan besteden. Op deze pagina wil ik alle artikels die ik erover schrijf oplijsten, zodat hier een duidelijk overzicht is.

Algemeen concept

Ik wil een zo volledig mogelijke sturing maken, die rekening houdt met zo veel mogelijk parameters en zo aanpasbaar mogelijk is. Daarenboven moet die ook mijn ketel kunnen aansturen en zo energiebesparend mogelijk zijn, terwijl de juiste plaatsen in het huis toch nog een zo aangenaam mogelijke comforttemperatuur behouden.

Om dit te kunnen realiseren kan je natuurlijk geen gebruik maken van de standaard programmering (“Heating Panel”) in de HC2 en moet je het allemaal zelf doen in LUA.

Qua hardware heb ik ervoor gekozen om met de Danfoss LC-13 thermostatische kranen te werken en centraal een NEST Thermostaat (die OpenTherm ondersteunt) te plaatsen. Verder gebruik ik de verschillende sensoren die ter beschikking staan in de kamers (raam- en deursensoren, bewegingsdetectoren, temperatuursensoren, een buitenweerstation, …)

Een simpele drukknop met 2 functies (dimmen en schakelen)

Om een simpele drukknop te gebruiken om 2 toestellen aan te sturen moet je een onderscheid kunnen maken tussen een “Single Click” = éénmaal drukken en een “Double Click” = tweemaal kort achtereen drukken.

Indien de simpele drukknop geen twee of meer aparte profielen ondersteunt (zoals bvb de NodOn Soft Remote wel doet) kan je met wat programmeren in LUA toch wel zo iets benaderen.

Deze iets ingewikkeldere opstelling laat toe om met enkele druk op de knop het dimniveau te wisselen tussen 0=OFF ; 25% ; 50% ; 75% ; 100%. Wanneer je dubbel drukt op de knop wordt het andere toestel aan- of uitgeschakeld.

Hiertoe moet je 4 globale variabelen declareren (in het “Variables Panel”) per schakelaar en 2 LUA scenes maken.

1. Globale Variabelen

Maak er 4 aan; voor de naamgeving heb ik hier een conventie gebruikt om ze later gemakkelijk te identificeren. Vervang {{id1}} door het ID van de schakelaar/drukknop, {{id2}} door het ID van de eerste module die je wil schakelen met een enkele druk en {{id3}} door het ID van de derde module die je met dubbel drukken wil schakelen.

  • Push{{id1}}_1
  • Push{{id1}}_2
  • Push{{id1}}_3
  • Correct{{id1}}

2. LUA script voor het druk-event
AdvDrukknop{{id1}}_DRUK

--[[
%% properties
{{id1}} value
%% events
%% globals
--]]
local id1={{id1}} --schakelaar
local id2={{id2}} --advanced drukknop scene
local correct=fibaro:getGlobalValue("Correct"..id1)
if (correct=="0") then
fibaro:debug("Button Push Time: "..tonumber(os.time()))
fibaro:setGlobal("Push"..id1.."_3",fibaro:getGlobalValue("Push"..id1.."_2"))
fibaro:setGlobal("Push"..id1.."_2",fibaro:getGlobalValue("Push"..id1.."_1"))
fibaro:setGlobal("Push"..id1.."_1",tonumber(os.time()))
fibaro:sleep(200)
fibaro:startScene(13)
else
fibaro:setGlobal("Correct"..id1,"0")
end

3. LUA script voor de schakeling

--[[
%% properties
%% events
%% globals
--]]
local id1={{id1}} -- de schakelaar
local id2={{id2}} -- module 1 - dimmodule
local id3={{id3}} -- module 2 - schakelmodule
local correctStateOnDim=1 --correctie van de indicator op de schakelaar nodig ?
local p3=fibaro:getGlobalValue("Push"..id1.."_3")
local p2=fibaro:getGlobalValue("Push"..id1.."_2")
local p1=fibaro:getGlobalValue("Push"..id1.."_1")
fibaro:debug('Change detected in '..fibaro:getName(id1)..' with id '..id1)
local db=10
local d1=p1-p2
local d2=p2-p3
fibaro:debug('Delta 1: '..d1..' Delta 2: '..d2)
if ((d1<db) and (d2>0)) then
fibaro:debug("Double click on "..fibaro:getName(id1).." detected ")
fibaro:setGlobal("Push"..id1.."_1",0)
fibaro:setGlobal("Push"..id1.."_2",0)
fibaro:setGlobal("Push"..id1.."_3",0)
--basis drukknop routine bij double click (enkel toggle, geen overeenkomst met indicator)
local currentstate = fibaro:getValue(id3, 'value')
fibaro:debug('Current state of switch '..fibaro:getName(id3)..' : '..currentstate)
if (currentstate == "0") then
fibaro:call(id3, "turnOn")
fibaro:debug("Turning ON switch "..fibaro:getName(id3))
else
fibaro:call(id3, "turnOff")
fibaro:debug("Turning OFF switch "..fibaro:getName(id3))
end
elseif ((d1>=db) and (d2==0)) then
fibaro:debug("Single click on "..fibaro:getName(id1).." detected ")
fibaro:setGlobal("Push"..id1.."_1",0)
fibaro:setGlobal("Push"..id1.."_2",0)
fibaro:setGlobal("Push"..id1.."_3",0)
--simpele dimmer drukknop routine bij single click
local currentstate = tonumber(fibaro:getValue(id2, 'value'))
fibaro:debug('Current state of dimmer'..fibaro:getName(id2)..' : '..currentstate)
if (currentstate <= 90) then
currentstate=currentstate+25
fibaro:call(id2, "setValue",currentstate)
fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to level "..currentstate.." %")
else currentstate=0
fibaro:call(id2, "turnOff")
fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to OFF")
end
if (correctStateOnDim==1) then
if ((currentstate==0) and (fibaro:getValue(id1,"value")=="1")) then
fibaro:setGlobal("Correct"..id1,"1")
fibaro:call(id1,"turnOff")
elseif ((currentstate~=0) and (fibaro:getValue(id1,"value")=="0")) then
fibaro:setGlobal("Correct"..id1,"1")
fibaro:call(id1,"turnOn")
end
end
else
fibaro:setGlobal("Push"..id1.."_1",0)
fibaro:setGlobal("Push"..id1.."_2",0)
fibaro:setGlobal("Push"..id1.."_3",0)
end

Een simpele drukknop voor dimmer met betere spreiding

Stel, je hebt een drukknop die niet elektrisch gekoppeld is aan een dimmende lamp. Nu wil je die drukknop gebruiken om die lamp toch te laten aan gaan, vervolgens in een paar stappen door de dimmer te gaan en weer uit te gaan.In de vorige post hierover vond je een wiskundige spreiding voor de dimwaarden (per 25%). Nu is dit met de meeste lampen niet logisch omdat die naarmate je meer bij de 100% komt niet veel harder branden. Vandaar heb ik hier geprobeerd om wat waarden te pakken die beter uitkomen.

Onderstaand vind je de LUA code hiervoor.
Vul de waarde voor id1 met het ID van de drukknop en id2 met het ID van de schakelaar en vervang {{id1}} door het ID van de drukknop.

--[[

%% properties

{{id1}} value

%% events

%% globals

--]]

local id1=xx

local id2=xx

fibaro:debug('Change detected in '..fibaro:getName(id1)..' with id '..id1..'. New Value: '..fibaro:getValue(id1,'value'))

local currentstate = tonumber(fibaro:getValue(id2, 'value'))

fibaro:debug('Current state of dimmer'..fibaro:getName(id2)..' : '..currentstate)

  local oldpush=fibaro:getGlobal("Push"..id1.."_1")

  local newpush=tonumber(os.time())

  fibaro:setGlobal("Push"..id1.."_1",newpush)

  fibaro:debug('first push: '..oldpush..' second push: '..newpush..' delta: '..newpush-oldpush) 

if (currentstate == 0) then

currentstate=35

elseif (currentstate == 35) then

currentstate=55

elseif (currentstate == 55) then

currentstate=70

elseif (currentstate == 70) then

currentstate=100

elseif (currentstate >90) then

currentstate=0

fibaro:call(id2, "turnOff")

fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to OFF")

end

  if ((newpush-oldpush>30) and (currentstate~=10)) then

    currentstate=0

    fibaro:call(id2, "turnOff")

    fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to OFF")

    if (fibaro:getValue(id1,"value")=="1") then

      fibaro:setGlobal("Correct"..id1,"1")

      fibaro:call(id1,"turnOff")

    end

  end

if (currentstate~=0) then

fibaro:call(id2, "setValue",currentstate)

fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to level "..currentstate.." %")

end

Versie 2 MET correctie van de indicator van de schakelaar.

Indien u een schakelaar die een indicator heeft gebruikt, zal de indicatie bij de standaard procedure niet meer kloppen. Om dit te corrigeren onderstaande. Hiervoor moet u in het “Variables Panel” een globale variabele aanmaken.

Globale variabele

    • Correct{{id1}}

LUA Scene

--[[

%% properties

{{id1}} value

%% events

%% globals

--]]

local id1=xx

local id2=xx

fibaro:debug('Change detected in '..fibaro:getName(id1)..' with id '..id1..'. New Value: '..fibaro:getValue(id1,'value'))

local currentstate = tonumber(fibaro:getValue(id2, 'value'))

if (fibaro:getGlobalValue("Correct"..id1)=="0") then

fibaro:debug('Current state of dimmer'..fibaro:getName(id2)..' : '..currentstate)

  local oldpush=fibaro:getGlobal("Push"..id1.."_1")

  local newpush=tonumber(os.time())

  fibaro:setGlobal("Push"..id1.."_1",newpush)

  fibaro:debug('first push: '..oldpush..' second push: '..newpush..' delta: '..newpush-oldpush) 

if (currentstate == 0) then

currentstate=35

elseif (currentstate == 35) then

currentstate=55

elseif (currentstate == 55) then

currentstate=70

elseif (currentstate == 70) then

currentstate=100

elseif (currentstate >90) then

currentstate=0

fibaro:call(id2, "turnOff")

fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to OFF")

if (fibaro:getValue(id1,"value")=="1") then

fibaro:setGlobal("Correct"..id1,"1")

fibaro:call(id1,"turnOff")

end

end

  if ((newpush-oldpush>30) and (currentstate~=10)) then

    currentstate=0

    fibaro:call(id2, "turnOff")

    fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to OFF")

    if (fibaro:getValue(id1,"value")=="1") then

      fibaro:setGlobal("Correct"..id1,"1")

      fibaro:call(id1,"turnOff")

    end

  end

if (currentstate~=0) then

fibaro:call(id2, "setValue",currentstate)

fibaro:debug("Setting dimmer "..fibaro:getName(id2).." to level "..currentstate.." %")

if (fibaro:getValue(id1,"value")=="0") then

fibaro:setGlobal("Correct"..id1,"1")

fibaro:call(id1,"turnOn")

end

end

else

fibaro:setGlobal("Correct"..id1,"0")

end

Universele Tijd Sturing

Onderstaande LUA scene kan je gebruiken als tijdssturing. Vermits ik voor zonsopgang en zonsondergang met globale variabelen wil werken, moeten deze op voorhand wel gedefinieerd zijn:

  • G_ZonStatus

Hierbij de code. Je kan in de “timeEventMatrix” gewoon je tijdsgetriggerde scenes toevoegen als array (de eerste moet je laten staan):

“op welke dagen”,”startuur”,”startminuut”,”op te roepen sceneID”,”tekst voor debug”,”0″

--[[

%% autostart

%% properties

%% events

%% globals

--]]



-- "day", "hour", "minute"

-- day "zondag"=0 ; "maandag"=1 ; ... ; "zaterdag"=6 ; "all"=7

local timeEventMatrix={

  {"7","0","1","special","Sun Change","0"}, --default event to update sunrise and sunset time

  {"1","10","44","24","TimeScene","0"}

  }



local timeEvents=#timeEventMatrix



local sr_Hour=0

local sr_Minute=0

local ss_Hour=0

local ss_Minute=0



function FN_Event(day,hour,minute)

  fibaro:debug("Running Event at day "..day.." hour "..hour..":"..minute)

  if ((tonumber(hour)==0) and (tonumber(minute)==1)) then

    local ss=fibaro:getValue(1, "sunsetHour")

    ss_Hour=tonumber(string.sub(ss, 1 , 2))

    ss_Minute=tonumber(string.sub(ss,4) )

--    fibaro:debug("sunset hour: "..ss_Hour.." minute: "..ss_Minute)

    local sr=fibaro:getValue(1, "sunriseHour")

    sr_Hour=tonumber(string.sub(sr, 1 , 2))

    sr_Minute=tonumber(string.sub(sr,4) )

--    fibaro:debug("sunset hour: "..sr_Hour.." minute: "..sr_Minute)

	for i = 2,timeEvents do

--    fibaro:debug("reset event runstats")

      timeEventMatrix[i][6]="0"

    end

  end

  if ((tonumber(hour)==sr_Hour) and (tonumber(minute)==sr_Minute)) then

    fibaro:debug("Sunrise Event - setting G_Zonstatus")

    FN_SunriseEvent()

  elseif ((tonumber(hour)==ss_Hour) and (tonumber(minute)==ss_Minute)) then

    fibaro:debug("Sunset Event - setting G_Zonstatus")

    FN_SunsetEvent()

  end  

  for i = 2,timeEvents do

	if ((day==timeEventMatrix[i][1]) and (hour==timeEventMatrix[i][2]) and (minute==timeEventMatrix[i][3]) and (timeEventMatrix[i][6]~="1")) then

      fibaro:debug("Event "..i.." executing scene: "..timeEventMatrix[i][5])

      fibaro:startScene(timeEventMatrix[i][4])

      timeEventMatrix[i][6]="1"

    end

  end

end



function FN_SunriseEvent()

  fibaro:setGlobal("G_ZonStatus","1")

end



function FN_minToSunrise(time_hour,time_minute)

  if (time_hour*60+time_minute)<=(sr_Hour*60+sr_Minute) then

    return ((sr_Hour*60+sr_Minute)-(time_hour*60+time_minute))

  else

    return ((sr_Hour*60+sr_Minute)+(24*60)-(time_hour*60+time_minute))

  end  

end



function FN_SunsetEvent()

  fibaro:setGlobal("G_ZonStatus","0")

end



function FN_minToSunset(time_hour,time_minute)

  if (time_hour*60+time_minute)<=(ss_Hour*60+ss_Minute) then

    return ((ss_Hour*60+ss_Minute)-(time_hour*60+time_minute))

  else

    return ((24*60)-(time_hour*60+time_minute)+(ss_Hour*60+ss_Minute))

  end  

end



function FN_timeDiff(fromDay,fromHour,fromMinute,toDay,toHour,toMinute)

--  fibaro:debug("timediff between "..fromDay.." - "..fromHour..":"..fromMinute.." to "..toDay.." - "..toHour..":"..toMinute)

  if (toDay==7) then

    if (fromHour*60+fromMinute)<=(toHour*60+toMinute) then

      return ((toHour*60+toMinute)-(fromHour*60+fromMinute))

    else

      return ((24*60)-(fromHour*60+fromMinute)+(toHour*60+toMinute))

    end

  end

  if (fromDay==toDay) then

    if (fromHour*60+fromMinute)<=(toHour*60+toMinute) then

      return ((toHour*60+toMinute)-(fromHour*60+fromMinute))

    else

      return ((24*60*7)+(24*60)-(fromHour*60+fromMinute)+(toHour*60+toMinute))

    end

  elseif ((fromDay<toDay) and (toDay~=7)) then return ((24*60)-(fromHour*60+fromMinute)+(toDay-fromDay-1)*(24*60)+(toHour*60+toMinute)) elseif (fromDay>toDay) then

    return ((24*60)-(fromHour*60+fromMinute)+(24*60*(6-fromDay+toDay))+(toHour*60+toMinute))

  end

end  



function calcSleep(time_day,time_hour,time_minute)

  local sleepToSunset=FN_minToSunset(tonumber(time_hour),tonumber(time_minute))

--  fibaro:debug("Time to Sunset: "..sleepToSunset.." min")

  local idevent="SunSet"

  local sleepToSunrise=FN_minToSunrise(tonumber(time_hour),tonumber(time_minute))

--  fibaro:debug("Time to Sunrise: "..sleepToSunrise.." min")

  local minsleep=sleepToSunset

  if (sleepToSunrise<minsleep) then 

    minsleep=sleepToSunrise 

    idevent="SunRise"

  end

  for i = 1,timeEvents do

    local es=FN_timeDiff(tonumber(time_day),tonumber(time_hour),tonumber(time_minute),tonumber(timeEventMatrix[i][1]),tonumber(timeEventMatrix[i][2]),tonumber(timeEventMatrix[i][3]))

--    fibaro:debug("Sleep to event "..i.." : "..es.." min")

    if (es<minsleep) then minsleep=es idevent=timeEventMatrix[i][2]..":"..timeEventMatrix[i][3] end end fibaro:debug("Selected Event at "..idevent.." sleeptime: "..minsleep.." min") return minsleep end FN_Event("7","0","1") while true do local sleepNow=calcSleep(os.date("%w"),os.date("%H"),os.date("%M"))*60*1000 -- fibaro:debug("Sleeptime to nearest Event: "..sleepNow) if (sleepNow>=60000) then

    sleepNow=sleepNow-30000

  	fibaro:debug("Sleeping for: "..sleepNow.." milliseconds")

    fibaro:sleep(sleepNow)

  else

    FN_Event(os.date("%w"),os.date("%H"),os.date("%M"))

    fibaro:debug("Sleeping for: 60000 milliseconds")

    fibaro:sleep(60000)

  end  

end

 

AEOTEC Z-Wave Energy Meter

Een energie – verbruiksmeter die je in je zekeringkast kan installeren op de kringen zonder de draden te moeten doorsnijden. Verkrijgbaar in verschillende versies (1 kring, 2 kringen of 3 kringen meten).

Ik heb uiteindelijk gekozen voor de versie waarbij je 3 kringen kan meten. Deze is eigenlijk bedoeld voor een installatie met drie fasen, maar met een heel kleine aanpassing kan je deze ook laten werken om 3 kringen te meten in een monofase installatie.

Om dit te doen moet je de drie stroomdraden gewoon bij mekaar steken. Let er wel op dat je de blauwe bij de blauwe doet en de bruine bij de bruine.

Ik heb naast mijn zekeringkast een extra stopcontactje geplaatst, dan kan ik de energie meter proper met een stekker voorzien van stroom en moet ik niet knoeien in de kast zelf.

In de kast ziet het er mooi proper uit, en heel handig om te installeren met die genummerde klemmetjes die je gewoon over de stroomdraden kan steken waarvan je het verbruik wil weten.

Hier zie je de eerste klem die ik geplaatst heb over de draad die toekomt in de kast. Zo kan ik het totaalverbruik meten van alle elektrische toestellen in huis.

Verder heb ik ook nog een klem geplaatst na de 30mA verliesstroom schakelaar, dan heb ik het verbruik in alle natte ruimtes apart.

En als derde meetpunt heb ik de aansluiting genomen van de verbruikers in de tuin. Zo kan ik netjes opmeten hoeveel elektriciteit daar op gaat.

En zo zijn alle drie punten om verbruik van elektriciteit te meten bepaald. De installatie was echt heel eenvoudig en snel gebeurd.

Het koppelen van de energie meter op de Fibaro Home Center 2 had ik op voorhand al gedaan in mijn simpele test-opstelling. (het is nogal onhandig om dit achteraf te doen, aangezien de knop achter op de meter zit, en het toevoegen niet altijd van de eerste keer lukt. Ook hier weer heb ik een keer of zes, zeven moeten proberen om de meter in de software te krijgen.)

Verschiet niet, als de energie meter eenmaal in je z-wave netwerk geraakt krijg je in de HC2 interface een hele hoop devices bij ! Een deel ervan kan je al meteen op “This device is hidden in the system” zetten, aangezien ze toch geen nuttige informatie teruggeven. Zo zijn er devices die het symbool krijgen van een lichtmeter (?) en een of andere spanningswaarde meten (in mijn geval 58V, maar ik weet absoluut niet waar dat over gaat. De nuttige devices worden wel juist herkend, je vindt 3 Stroom-meters terug die in Ampere waardes meten en 3 verbruiksmeters die het Wattage in het oog houden. Eigenlijk hou je 6 devices van de 13 over die nuttig zijn.

Let wel op : de Fibaro Home Center 2 berekent het totaal verbruik op de som van alle meters. Dit kan je niet veranderen, dus zoals bijvoorbeeld in mijn geval zullen de totalen niet correct zijn (aangezien ik niet alle details meet en 1 meetpunt heb voor het totaal). Met wat filteren en prutsen kan je toch nog een mooi overzicht krijgen in het Energy Panel van de HC2.

Translate »