Ogrzewanie zwykłe i podłogowe - Urządzenie zastępujące sterowanie z Fibaro

  • 2 Odpowiedzi
  • 9114 Wyświetleń

0 użytkowników i 1 Gość przegląda ten wątek.

*

Offline Grzegorz

  • * 10
  • 2
Od jakiegoś czasu (grubo ponad miesiąc) w moim domu zastąpiłem dość prymitywny algorytm sterowania ogrzewaniem Fibaro przez własne urządzenie wirtualne napisane w LUA, którego kod znajdziecie poniżej. Jest to dobry punkt wyjścia dla tych z Was, którzy chcą pobawić się ogrzewaniem na własną rękę.

Cechy urządzenia to:
- wykorzystuje standardowy panel ogrzewania Fibaro do definiowania temperatury o określonych porach dnia w podziale na strefy,
- obsługuje tryb wakacyjny ustawiany w panelu ogrzewania,
- obsługuje ręczne ustawienie temperatury w panelu ogrzewania (lub termostatach na urządzeniach mobilnych) na zadany czas,
- obsługuje dodatkowe czujniki temperatury (opcjonalne) do kontroli temperatury podłogi,
- wspiera ograniczenie maksymalnej temperatury podłogi,
- rozróżnia urządzenia wykonawcze do ogrzewania podłogowego od innych (nie odcina ogrzewania kaloryfera gdy podłoga gorąca a powietrze zimne),
- ma bardzo prostą (choć lepszą od tej z Fibaro) logikę grzania,
- ma podstawową obsługę błędów i wyjątków dodaną na bazie doświadczeń.

Wymagania i ograniczenia skryptu to:
- Wersja oprogramowania HC2 to min. 4.0 (chodzi o sposób dobierania się do parametrów ogrzewania przez json),
- Przetestowany wyłącznie na kombinacji UBS'y z DS'ami + Relay Switch'e z Fibaro, choć powinno działać z dowolnym czujnikiem temperatury i urządzeniami wykonawczymi.
- Ze względu na błąd w oprogramowaniu HC2, skryptu nie należy uruchamiać w głównej pętli urządzenia wirtualnego. Ta "umiera" po 2-3 dniach i można bardzo się zdziwić. Zamiast tego należy utworzyć przycisk w urządzeniu wirtualnym i odpalać go, np. co minutę, przy pomocy sceny. Sposób jak na starego Poloneza, ale działa stabilnie.

Uwaga! Należy pamiętać o dostosowaniu tabeli na początku skryptu do własnych ustawień i ID urządzeń.

-- Heating zones parameters definition
-- (heat zone numbers must match the ones from Fibaro!!!)
local heatZones={}
-- Basement
heatZones[2] = {airSensorID = 130, maxFloorTemp = 25, floorSensorID = 131, regHeatersID = {}, floorHeatersID = {17}} -- Boiler room
heatZones[8] = {airSensorID = 140, maxFloorTemp = 25, floorSensorID = 142, regHeatersID = {}, floorHeatersID = {15}} -- Studio
-- Ground floor
heatZones[3] = {airSensorID = 122, maxFloorTemp = 27, floorSensorID = 124, regHeatersID = {143}, floorHeatersID = {20}} -- Entry hall / toilet
heatZones[4] = {airSensorID = 75, maxFloorTemp = 25, floorSensorID = 77, regHeatersID = {}, floorHeatersID = {18}} -- Main room
-- 1st floor
heatZones[5] = {airSensorID = 129, maxFloorTemp = 24, floorSensorID = 132, regHeatersID = {12}, floorHeatersID = {9}} -- Bathroom
heatZones[6] = {airSensorID = 139, maxFloorTemp = 25, floorSensorID = 141, regHeatersID = {}, floorHeatersID = {11}} -- Bedroom
-- 2nd floor
heatZones[7] = {airSensorID = 76, maxFloorTemp = nil, floorSensorID = nil, regHeatersID = {6}, floorHeatersID = {}} -- Attic

local zone -- used for main loop
local heater -- used for heating element loops
local desiredTemp -- used for currently desired temperature
local nextTemp -- used for temperature in the next time period
local nextTempChange -- used for time in minutes until the next temperature change
local isFloorHeatingOn -- used for information whether floor heating is on
local lastFloorHeatingAction -- used for timestamp of last change of floor heating state
local minSinceLastFloorHeatingAction -- used for information how many minutes passed since last change of floor heating state
local isRegHeatingOn -- used for information whether floor heating is on
local lastRegHeatingAction -- used for timestamp of last change of regular heating state
local minSinceLastRegHeatingAction -- used for information how many minutes passed since last change of regular heating state
local floorHeatingAction -- used to determine upcoming action after decision process
local regHeatingAction -- used to determine upcoming action after decision process

local dayOfWeek = string.gsub(os.date("%A"), "^%a", string.lower) -- weekday in string for reading HC2 heating panel table
local currentTime = (os.date("%H") * 60) + os.date("%M") -- time in minutes since midnight

local heatingConnection = Net.FHttp("127.0.0.1",11111)
if heatingConnection == nil then
fibaro:debug("Problem opening network connection (nil value returned)")
fibaro:abort()
end

for zone in pairs (heatZones) do

    -- read heating schedule for selected zone
    repeat
        response, status, errorCode = heatingConnection:GET("/api/panels/heating/"..zone)
        fibaro:sleep(0.5 * 1000)
    until (tonumber(errorCode) == 0) and (tonumber(status) == 200) and (response ~= nil)
jsonTable = json.decode(response)
--fibaro:debug(response)
response = nil

fibaro:debug("----- Zone: "..jsonTable.name.." (ID: "..zone..") -----")

-- determine what is current desired temperature depending on the heating mode and time of the day
if jsonTable.properties.handTemperature > 0 then
-- Heating is in manual mode
desiredTemp = jsonTable.properties.handTemperature
nextTempChange = (jsonTable.properties.handTimestamp - os.time()) / 60
if (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].night.temperature
elseif (jsonTable.properties[dayOfWeek].day.hour * 60) + jsonTable.properties[dayOfWeek].day.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].morning.temperature
elseif (jsonTable.properties[dayOfWeek].evening.hour * 60) + jsonTable.properties[dayOfWeek].evening.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].day.temperature
elseif (jsonTable.properties[dayOfWeek].night.hour * 60) + jsonTable.properties[dayOfWeek].night.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].evening.temperature
else
nextTemp = jsonTable.properties[dayOfWeek].night.temperature
end
elseif jsonTable.properties.vacationTemperature > 0 then
-- Heating is in vacation mode
desiredTemp = jsonTable.properties.vacationTemperature
nextTempChange = 90 -- in minutes! in this case it doesn't really matter as vacation mode is set manually
nextTemp = jsonTable.properties.vacationTemperature
elseif (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute > currentTime then
-- It's night (after midnight)
desiredTemp = jsonTable.properties[dayOfWeek].night.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].morning.temperature
elseif (jsonTable.properties[dayOfWeek].day.hour * 60) + jsonTable.properties[dayOfWeek].day.minute > currentTime then
-- It's morning
desiredTemp = jsonTable.properties[dayOfWeek].morning.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].day.hour * 60) + jsonTable.properties[dayOfWeek].day.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].day.temperature
elseif (jsonTable.properties[dayOfWeek].evening.hour * 60) + jsonTable.properties[dayOfWeek].evening.minute > currentTime then
-- It's day
desiredTemp = jsonTable.properties[dayOfWeek].day.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].evening.hour * 60) + jsonTable.properties[dayOfWeek].evening.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].evening.temperature
elseif (jsonTable.properties[dayOfWeek].night.hour * 60) + jsonTable.properties[dayOfWeek].night.minute > currentTime then
-- It's evening
desiredTemp = jsonTable.properties[dayOfWeek].evening.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].night.hour * 60) + jsonTable.properties[dayOfWeek].night.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].night.temperature
else
-- It's night (before midnight)
desiredTemp = jsonTable.properties[dayOfWeek].night.temperature
nextTempChange = ((24 * 60) - currentTime) + (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].morning.temperature
end
 
  fibaro:debug("Desired temperature: "..desiredTemp..", Next temperature: "..nextTemp.." (will be set in "..nextTempChange.." min.)")

-- read current air temperature
airTemp = tonumber(fibaro:getValue(heatZones[zone].airSensorID, "value"))
if airTemp == nil then
fibaro:debug("Problem reading air temperature in zone "..zone.." (nil value returned)")
fibaro:abort()
end

fibaro:debug("Air sensor: "..heatZones[zone].airSensorID..", Current air temp.: "..airTemp)

---------- FLOOR HEATING CONTROL SECTION ----------
isFloorHeatingOn = 0
lastFloorHeatingAction = 0
minSinceLastFloorHeatingAction = 15 -- set this way to enable regular heating if floor is not present in current zone

if table.getn(heatZones[zone].floorHeatersID) > 0 then

-- read floor temperature
floorTemp = tonumber(fibaro:getValue(heatZones[zone].floorSensorID, "value"))
if floorTemp == nil then
fibaro:debug("Problem reading floor temperature in zone "..zone.." (nil value returned)")
fibaro:abort()
end

fibaro:debug("Floor sensor: "..heatZones[zone].floorSensorID..", Current floor temp.: "..floorTemp.." (max. "..heatZones[zone].maxFloorTemp..")")

-- read floor heating status
for heater in ipairs(heatZones[zone].floorHeatersID) do
isElementOn = fibaro:getValue(heatZones[zone].floorHeatersID[heater], "value")
if isElementOn == nil then
fibaro:debug("Problem getting state of the floor heater (ID: "..heater..", zone: "..zone..") (nil value returned)")
fibaro:abort()
end
isElementOn = tonumber(isElementOn)
if isElementOn > isFloorHeatingOn then isFloorHeatingOn = isElementOn end
lastElementAction = fibaro:getModificationTime(heatZones[zone].floorHeatersID[heater],"value")
if lastElementAction > lastFloorHeatingAction then lastFloorHeatingAction = lastElementAction end
--fibaro:debug("Floor heater ID: "..heatZones[zone].floorHeatersID[heater]..", State: "..isElementOn..", Last change: "..os.date("%H:%M",lastElementAction))
end
minSinceLastFloorHeatingAction = (os.time()-lastFloorHeatingAction) / 60

fibaro:debug("Floor heating state: "..isFloorHeatingOn..", Last change: "..os.date("%H:%M",lastFloorHeatingAction).." ("..minSinceLastFloorHeatingAction.." min. ago)")

-- decide whether to turn floor heating on or off
floorHeatingAction = "none"
if (isFloorHeatingOn > 0) and (nextTempChange <= 15) and (nextTemp < airTemp) then
-- We will start to cool-off the room in 15 min. so there is no point in heating -> turn off floor heaters
floorHeatingAction = "turnOff"
elseif (isFloorHeatingOn == 0) and (nextTempChange <= 15) and (nextTemp > airTemp) and (minSinceLastFloorHeatingAction >= 15) then
-- It's been a while since heaters were on and in less than 15 min. we need to go up with temp. -> turn on floor heaters
floorHeatingAction = "turnOn"
elseif ((airTemp >= desiredTemp) or (floorTemp >= heatZones[zone].maxFloorTemp - 0.75)) and (isFloorHeatingOn > 0) then
-- It's too hot in the room or floor is overheating -> turn off floor heaters
floorHeatingAction = "turnOff"
elseif (airTemp < desiredTemp) and (floorTemp < heatZones[zone].maxFloorTemp) and (minSinceLastFloorHeatingAction >= 15) and (isFloorHeatingOn == 0) and (((nextTempChange <= 15) and (nextTemp > airTemp)) or (nextTempChange > 15)) then
-- It's too cold in the room and floor heaters were turned off a while ago -> turn on floor heaters
floorHeatingAction = "turnOn"
end

-- execute heating decision
if floorHeatingAction == "turnOff" then
fibaro:debug("Turning off floor heating")
for heater in ipairs(heatZones[zone].floorHeatersID) do
fibaro:call(heatZones[zone].floorHeatersID[heater],"turnOff")
end
elseif floorHeatingAction == "turnOn" then
fibaro:debug("Turning on floor heating")
for heater in ipairs(heatZones[zone].floorHeatersID) do
fibaro:call(heatZones[zone].floorHeatersID[heater],"turnOn")
end
end
end

---------- REGULAR HEATING CONTROL SECTION ----------
isRegHeatingOn = 0
lastRegHeatingAction = 0
minSinceLastRegHeatingAction = 15

if table.getn(heatZones[zone].regHeatersID) > 0 then

-- read floor heating status
for heater in ipairs(heatZones[zone].regHeatersID) do
isElementOn = fibaro:getValue(heatZones[zone].regHeatersID[heater], "value")
if isElementOn == nil then
fibaro:debug("Problem getting state of the regular heater (ID: "..heater..", zone: "..zone..") (nil value returned)")
fibaro:abort()
end
isElementOn = tonumber(isElementOn)
if isElementOn > isRegHeatingOn then isRegHeatingOn = isElementOn end
lastElementAction = fibaro:getModificationTime(heatZones[zone].regHeatersID[heater],"value")
if lastElementAction > lastRegHeatingAction then lastRegHeatingAction = lastElementAction end
--fibaro:debug("Regular heater ID: "..heatZones[zone].regHeatersID[heater]..", State: "..isElementOn..", Last change: "..os.date("%H:%M",lastElementAction))
end
minSinceLastRegHeatingAction = (os.time()-lastRegHeatingAction) / 60

fibaro:debug("Regular heating state: "..isRegHeatingOn..", Last change: "..os.date("%H:%M",lastRegHeatingAction).." ("..minSinceLastRegHeatingAction.." min. ago)")

-- decide whether to turn floor heating on or off
regHeatingAction = "none"
if (isRegHeatingOn > 0) and (nextTempChange <= 15) and (nextTemp < airTemp) then
-- We will start to cool-off the room in 15 min. so there is no point in heating -> turn off regular heaters
floorHeatingAction = "turnOff"
elseif (isRegHeatingOn == 0) and (nextTempChange <= 15) and (nextTemp > airTemp) and (minSinceLastRegHeatingAction >= 15) then
-- It's been a while since heaters were on and in less than 15 min. we need to go up with temp. -> turn on floor heaters
floorHeatingAction = "turnOn"
elseif (airTemp >= desiredTemp) and (isRegHeatingOn > 0) then
-- It's too hot in the room -> turn off regular heaters
regHeatingAction = "turnOff"
elseif (airTemp < desiredTemp) and (minSinceLastRegHeatingAction >= 15) and (isRegHeatingOn == 0) and (((nextTempChange <= 15) and (nextTemp > airTemp)) or (nextTempChange > 15)) then
-- It's too cold in the room and all regular heaters were turned off a while ago -> turn on regular heaters
regHeatingAction = "turnOn"
end

-- execute heating decision
if regHeatingAction == "turnOff" then
fibaro:debug("Turning off regular heating")
for heater in ipairs(heatZones[zone].regHeatersID) do
fibaro:call(heatZones[zone].regHeatersID[heater],"turnOff")
end
elseif regHeatingAction == "turnOn" then
fibaro:debug("Turning on regular heating")
for heater in ipairs(heatZones[zone].regHeatersID) do
fibaro:call(heatZones[zone].regHeatersID[heater],"turnOn")
end
end
end

-- cleanup
floorHeatingAction = nil
regHeatingAction = nil
jsonTable = nil
end

heatZones = nil
heatingConnection = nil
*

Offline Grzegorz

  • * 10
  • 2
Odp: Ogrzewanie zwykłe i podłogowe - Urządzenie zastępujące sterowanie z Fibaro
« Odpowiedź #1 dnia: Grudzień 03, 2015, 07:23:32 am »
Ze względu na pytania o zakres koniecznych modyfikacji, które dostaję raz na jakiś czas, postanowiłem odpisać na forum i przy okazji podzielić się najnowszą wersją skryptu, która zawiera drobne poprawki błędów i dobrze służy mi już drugi sezon grzewczy.

Aby dopasować kod poniżej do własnego domu, wystarczy utworzyć strefy w Panelu Ogrzewania i zmodyfikować tabelę heatZones na samym początku skryptu. Reszta to samograj.

Parametry w tabeli to:
- airSensorID - ID czujnika temperatury powietrza
- maxFloorTemp - maksymalna temperatura podłogi (nil jeśli nie mierzymy)
- floorSensorID - ID czujnika temperatury podłogi (nil jeśli nie ma)
- regHeatersID - tabela z ID elementów wykonawczych na elektrozaworach zwykłych grzejników dla danego pomieszczenia (pusta jeśli nie ma)
- floorHeatersID - tabela z ID elementów wykonawczych na elektrozaworach ogrzewania podłogowego dla danego pomieszczenia (pusta jeśli nie ma)

Uwaga! Identyfikatory w tabeli muszą zgadzać się z numerami stref w Panelu Ogrzewania w HC2 (np. pierwsza pozycja poniżej ma numer 2, ponieważ to pomieszczenie w Panelu Ogrzewania jest w strefie nr 2).

-- Heating zones parameters definition
-- (heat zone numbers must match the ones from Fibaro!!!)
local heatZones={}
-- Basement
heatZones[2] = {airSensorID = 130, maxFloorTemp = 25, floorSensorID = 131, regHeatersID = {}, floorHeatersID = {17}} -- Boiler room
heatZones[8] = {airSensorID = 140, maxFloorTemp = 25, floorSensorID = 142, regHeatersID = {}, floorHeatersID = {15}} -- Studio
-- Ground floor
heatZones[3] = {airSensorID = 122, maxFloorTemp = 27, floorSensorID = 124, regHeatersID = {143}, floorHeatersID = {20}} -- Entry hall / toilet
heatZones[4] = {airSensorID = 75, maxFloorTemp = 25, floorSensorID = 77, regHeatersID = {}, floorHeatersID = {18}} -- Main room
-- 1st floor
heatZones[5] = {airSensorID = 129, maxFloorTemp = 24, floorSensorID = 132, regHeatersID = {12}, floorHeatersID = {9}} -- Bathroom
heatZones[6] = {airSensorID = 139, maxFloorTemp = 25, floorSensorID = 141, regHeatersID = {}, floorHeatersID = {11}} -- Bedroom
-- 2nd floor
heatZones[7] = {airSensorID = 76, maxFloorTemp = nil, floorSensorID = nil, regHeatersID = {6}, floorHeatersID = {}} -- Attic

local zone -- used for main loop
local heater -- used for heating element loops
local desiredTemp -- used for currently desired temperature
local nextTemp -- used for temperature in the next time period
local nextTempChange -- used for time in minutes until the next temperature change
local isFloorHeatingOn -- used for information whether floor heating is on
local lastFloorHeatingAction -- used for timestamp of last change of floor heating state
local minSinceLastFloorHeatingAction -- used for information how many minutes passed since last change of floor heating state
local isRegHeatingOn -- used for information whether floor heating is on
local lastRegHeatingAction -- used for timestamp of last change of regular heating state
local minSinceLastRegHeatingAction -- used for information how many minutes passed since last change of regular heating state
local floorHeatingAction -- used to determine upcoming action after decision process
local regHeatingAction -- used to determine upcoming action after decision process

local dayOfWeek = string.gsub(os.date("%A"), "^%a", string.lower) -- weekday in string for reading HC2 heating panel table
local currentTime = (os.date("%H") * 60) + os.date("%M") -- time in minutes since midnight

local heatingConnection = Net.FHttp("127.0.0.1",11111)
if heatingConnection == nil then
fibaro:debug("Problem opening network connection (nil value returned)")
fibaro:abort()
end

for zone in pairs (heatZones) do

    -- read heating schedule for selected zone
    repeat
        response, status, errorCode = heatingConnection:GET("/api/panels/heating/"..zone)
        fibaro:sleep(0.5 * 1000)
    until (tonumber(errorCode) == 0) and (tonumber(status) == 200) and (response ~= nil)
jsonTable = json.decode(response)
-- fibaro:debug(response)
response = nil

fibaro:debug("----- Zone: "..jsonTable.name.." (ID: "..zone..") -----")

-- determine what is current desired temperature depending on the heating mode and time of the day
if (jsonTable.properties.handTemperature > 0) and (jsonTable.properties.handTimestamp >= os.time()) then
-- Heating is in manual mode
desiredTemp = jsonTable.properties.handTemperature
nextTempChange = (jsonTable.properties.handTimestamp - os.time()) / 60
if (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].night.temperature
elseif (jsonTable.properties[dayOfWeek].day.hour * 60) + jsonTable.properties[dayOfWeek].day.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].morning.temperature
elseif (jsonTable.properties[dayOfWeek].evening.hour * 60) + jsonTable.properties[dayOfWeek].evening.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].day.temperature
elseif (jsonTable.properties[dayOfWeek].night.hour * 60) + jsonTable.properties[dayOfWeek].night.minute > currentTime + nextTempChange then
nextTemp = jsonTable.properties[dayOfWeek].evening.temperature
else
nextTemp = jsonTable.properties[dayOfWeek].night.temperature
end
elseif jsonTable.properties.vacationTemperature > 0 then
-- Heating is in vacation mode
desiredTemp = jsonTable.properties.vacationTemperature
nextTempChange = 90 -- in minutes! in this case it doesn't really matter as vacation mode is set manually
nextTemp = jsonTable.properties.vacationTemperature
elseif (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute > currentTime then
-- It's night (after midnight)
desiredTemp = jsonTable.properties[dayOfWeek].night.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].morning.temperature
elseif (jsonTable.properties[dayOfWeek].day.hour * 60) + jsonTable.properties[dayOfWeek].day.minute > currentTime then
-- It's morning
desiredTemp = jsonTable.properties[dayOfWeek].morning.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].day.hour * 60) + jsonTable.properties[dayOfWeek].day.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].day.temperature
elseif (jsonTable.properties[dayOfWeek].evening.hour * 60) + jsonTable.properties[dayOfWeek].evening.minute > currentTime then
-- It's day
desiredTemp = jsonTable.properties[dayOfWeek].day.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].evening.hour * 60) + jsonTable.properties[dayOfWeek].evening.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].evening.temperature
elseif (jsonTable.properties[dayOfWeek].night.hour * 60) + jsonTable.properties[dayOfWeek].night.minute > currentTime then
-- It's evening
desiredTemp = jsonTable.properties[dayOfWeek].evening.temperature
nextTempChange = (jsonTable.properties[dayOfWeek].night.hour * 60) + jsonTable.properties[dayOfWeek].night.minute - currentTime -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].night.temperature
else
-- It's night (before midnight)
desiredTemp = jsonTable.properties[dayOfWeek].night.temperature
nextTempChange = ((24 * 60) - currentTime) + (jsonTable.properties[dayOfWeek].morning.hour * 60) + jsonTable.properties[dayOfWeek].morning.minute -- in minutes!
nextTemp = jsonTable.properties[dayOfWeek].morning.temperature
end
 
  fibaro:debug("Desired temperature: "..desiredTemp..", Next temperature: "..nextTemp.." (will be set in "..nextTempChange.." min.)")

-- read current air temperature
airTemp = tonumber(fibaro:getValue(heatZones[zone].airSensorID, "value"))
if airTemp == nil then
fibaro:debug("Problem reading air temperature in zone "..zone.." (nil value returned)")
fibaro:abort()
end

fibaro:debug("Air sensor: "..heatZones[zone].airSensorID..", Current air temp.: "..airTemp)

---------- FLOOR HEATING CONTROL SECTION ----------
isFloorHeatingOn = 0
lastFloorHeatingAction = 0
minSinceLastFloorHeatingAction = 15 -- set this way to enable regular heating if floor is not present in current zone

if table.getn(heatZones[zone].floorHeatersID) > 0 then

-- read floor temperature
floorTemp = tonumber(fibaro:getValue(heatZones[zone].floorSensorID, "value"))
if floorTemp == nil then
fibaro:debug("Problem reading floor temperature in zone "..zone.." (nil value returned)")
fibaro:abort()
end

fibaro:debug("Floor sensor: "..heatZones[zone].floorSensorID..", Current floor temp.: "..floorTemp.." (max. "..heatZones[zone].maxFloorTemp..")")

-- read floor heating status
for heater in ipairs(heatZones[zone].floorHeatersID) do
isElementOn = fibaro:getValue(heatZones[zone].floorHeatersID[heater], "value")
if isElementOn == nil then
fibaro:debug("Problem getting state of the floor heater (ID: "..heater..", zone: "..zone..") (nil value returned)")
fibaro:abort()
end
isElementOn = tonumber(isElementOn)
if isElementOn > isFloorHeatingOn then isFloorHeatingOn = isElementOn end
lastElementAction = fibaro:getModificationTime(heatZones[zone].floorHeatersID[heater],"value")
if lastElementAction > lastFloorHeatingAction then lastFloorHeatingAction = lastElementAction end
--fibaro:debug("Floor heater ID: "..heatZones[zone].floorHeatersID[heater]..", State: "..isElementOn..", Last change: "..os.date("%H:%M",lastElementAction))
end
minSinceLastFloorHeatingAction = (os.time()-lastFloorHeatingAction) / 60

fibaro:debug("Floor heating state: "..isFloorHeatingOn..", Last change: "..os.date("%H:%M",lastFloorHeatingAction).." ("..minSinceLastFloorHeatingAction.." min. ago)")

-- decide whether to turn floor heating on or off
floorHeatingAction = "none"
if (isFloorHeatingOn > 0) and (nextTempChange <= 15) and (nextTemp < airTemp) then
-- We will start to cool-off the room in 15 min. so there is no point in heating -> turn off floor heaters
floorHeatingAction = "turnOff"
elseif (isFloorHeatingOn == 0) and (nextTempChange <= 15) and (nextTemp > airTemp) and (minSinceLastFloorHeatingAction >= 15) then
-- It's been a while since heaters were on and in less than 15 min. we need to go up with temp. -> turn on floor heaters
floorHeatingAction = "turnOn"
elseif ((airTemp >= desiredTemp) or (floorTemp >= heatZones[zone].maxFloorTemp - 0.75)) and (isFloorHeatingOn > 0) then
-- It's too hot in the room or floor is overheating -> turn off floor heaters
floorHeatingAction = "turnOff"
elseif (airTemp < desiredTemp) and (floorTemp < heatZones[zone].maxFloorTemp) and (minSinceLastFloorHeatingAction >= 15) and (isFloorHeatingOn == 0) and (((nextTempChange <= 15) and (nextTemp > airTemp)) or (nextTempChange > 15)) then
-- It's too cold in the room and floor heaters were turned off a while ago -> turn on floor heaters
floorHeatingAction = "turnOn"
end

-- execute heating decision
if floorHeatingAction == "turnOff" then
fibaro:debug("Turning off floor heating")
for heater in ipairs(heatZones[zone].floorHeatersID) do
fibaro:call(heatZones[zone].floorHeatersID[heater],"turnOff")
end
elseif floorHeatingAction == "turnOn" then
fibaro:debug("Turning on floor heating")
for heater in ipairs(heatZones[zone].floorHeatersID) do
fibaro:call(heatZones[zone].floorHeatersID[heater],"turnOn")
end
end
end

---------- REGULAR HEATING CONTROL SECTION ----------
isRegHeatingOn = 0
lastRegHeatingAction = 0
minSinceLastRegHeatingAction = 15

if table.getn(heatZones[zone].regHeatersID) > 0 then

-- read floor heating status
for heater in ipairs(heatZones[zone].regHeatersID) do
isElementOn = fibaro:getValue(heatZones[zone].regHeatersID[heater], "value")
if isElementOn == nil then
fibaro:debug("Problem getting state of the regular heater (ID: "..heater..", zone: "..zone..") (nil value returned)")
fibaro:abort()
end
isElementOn = tonumber(isElementOn)
if isElementOn > isRegHeatingOn then isRegHeatingOn = isElementOn end
lastElementAction = fibaro:getModificationTime(heatZones[zone].regHeatersID[heater],"value")
if lastElementAction > lastRegHeatingAction then lastRegHeatingAction = lastElementAction end
--fibaro:debug("Regular heater ID: "..heatZones[zone].regHeatersID[heater]..", State: "..isElementOn..", Last change: "..os.date("%H:%M",lastElementAction))
end
minSinceLastRegHeatingAction = (os.time()-lastRegHeatingAction) / 60

fibaro:debug("Regular heating state: "..isRegHeatingOn..", Last change: "..os.date("%H:%M",lastRegHeatingAction).." ("..minSinceLastRegHeatingAction.." min. ago)")

-- decide whether to turn floor heating on or off
regHeatingAction = "none"
if (isRegHeatingOn > 0) and (nextTempChange <= 15) and (nextTemp < airTemp) then
-- We will start to cool-off the room in 15 min. so there is no point in heating -> turn off regular heaters
floorHeatingAction = "turnOff"
elseif (isRegHeatingOn == 0) and (nextTempChange <= 15) and (nextTemp > airTemp) and (minSinceLastRegHeatingAction >= 15) then
-- It's been a while since heaters were on and in less than 15 min. we need to go up with temp. -> turn on floor heaters
floorHeatingAction = "turnOn"
elseif (airTemp >= desiredTemp) and (isRegHeatingOn > 0) then
-- It's too hot in the room -> turn off regular heaters
regHeatingAction = "turnOff"
elseif (airTemp < desiredTemp) and (minSinceLastRegHeatingAction >= 15) and (isRegHeatingOn == 0) and (((nextTempChange <= 15) and (nextTemp > airTemp)) or (nextTempChange > 15)) then
-- It's too cold in the room and all regular heaters were turned off a while ago -> turn on regular heaters
regHeatingAction = "turnOn"
end

-- execute heating decision
if regHeatingAction == "turnOff" then
fibaro:debug("Turning off regular heating")
for heater in ipairs(heatZones[zone].regHeatersID) do
fibaro:call(heatZones[zone].regHeatersID[heater],"turnOff")
end
elseif regHeatingAction == "turnOn" then
fibaro:debug("Turning on regular heating")
for heater in ipairs(heatZones[zone].regHeatersID) do
fibaro:call(heatZones[zone].regHeatersID[heater],"turnOn")
end
end
end

-- cleanup
floorHeatingAction = nil
regHeatingAction = nil
jsonTable = nil
end

heatZones = nil
heatingConnection = nil
*

Offline Jacławiciel

  • * 4
  • 0
  • Nazwa i wersja ID: HC2
Odp: Ogrzewanie zwykłe i podłogowe - Urządzenie zastępujące sterowanie z Fibaro
« Odpowiedź #2 dnia: Grudzień 04, 2015, 12:43:57 pm »
Możesz nam przybliżyć trochę jaką przewagę nad domyślnym Panelem ma Twój skrypt? Jaka logika się za nim kryje?

W pierwszej wersji pomimo wpisania wartości nil w polu czujników temperatury podłogi skrypt nie działał. Jak nie mam czujników temperatury podłogi to wpisać strefy podłogówki do "regular heaters" czy w nowszej wersji wystarczy wpisać nil do "maxFloorTemp" i "floorSensorID"?

[ERROR] 15:53:45: line :getValue (arg 2), expected 'unsigned int' got 'nil'

Błąd wyskakuje w tym miejscu?
floorTemp = tonumber(fibaro:getValue(heatZones[zone].floorSensorID, "value"))
if floorTemp == nil then
fibaro:debug("Problem reading floor temperature in zone "..zone.." (nil value returned)")
fibaro:abort()
end

I jeszcze jedno pytanko... Czy nastawa ręczna ma wyższy priorytet od nastawy wakacyjnej?

Dzięki jeszcze raz za pomoc. ;)
« Ostatnia zmiana: Grudzień 04, 2015, 04:04:12 pm wysłana przez Jacławiciel »