Hello,
I have an opentherm boiler (Atlantic Naia 2) and an opentherm thermostat (atlantic navilink h55) but the latter doesn't play nice with me and I can't manage to override the temperature on it via the gateway (see viewtopic.php?t=13870&sid=79747055dcca2 ... efc0089808 ).
So now, I have to take a decision : buy a new thermostat that supports override, build my own thermostat software or give up.
I'm a software engineer, so the "development part" does not scare me, but I fear I'll struggle on the "logic" side of things: how an efficient thermostat works. What CH setpoint, what modulation ratio when to turn on/off, etc.
I have _some_ resources such as https://stuff.stooit.com/d/1/63d3a97fce ... _11-37.png (sorry in French) but yeah, I'm a bit afraid I'll make an inefficient monster.
I tried to look around for open-source thermostat software, but I didn't find much.
Then there's what I'm trying to do at home: I have 3 rooms, with 4 radiators (1 room is big, so there are 2 here) and only 1 CH circuit. So what I want to do is to put TRV on my radiators so I can open/close them at will and then I'd like to be able to set a different temperature in each room.
So if I buy a thermostat, I'll have to override the temperature depending on the room that needs to be heated.
So basically:
1. Do you have any knowledge of homemade thermostats with good efficiency?
2. Would you recommend this, or do you think I should just buy a new thermostat?
3. Do you have a recommendation for a cheap thermostat that plays nice with OTGW?
Thanks!
Thermostat recommandation: buy or build
Moderator: hvxl
Re: Thermostat recommandation: buy or build
Oh and there's also the fact that my current thermostat seems to be quite dumb and not doing a good job at modulating my boiler:
Re: Thermostat recommandation: buy or build
Hello Tiller,
I don't have an answer for you, but I have the exact same boiler and thermostat. I just ordered a kit from nodo-shop.
I just learned about the OTGW project this morning, and I thought the OT Monitor software would be able to play this part.
Anyway, I'll let you know when I'll receive my kit if I succeed having the OTGW working with H55.
I don't have an answer for you, but I have the exact same boiler and thermostat. I just ordered a kit from nodo-shop.
I just learned about the OTGW project this morning, and I thought the OT Monitor software would be able to play this part.
Anyway, I'll let you know when I'll receive my kit if I succeed having the OTGW working with H55.
Re: Thermostat recommandation: buy or build
Here is my attempt for domoticz that helped my through the winter 2022/2023:
The core is a PI algorithm:
P: if the room temperature is lower than the setpoint, set the boiler temp high
I: The longer time the bolier is on, the lower the temp should be
The core is a PI algorithm:
P: if the room temperature is lower than the setpoint, set the boiler temp high
I: The longer time the bolier is on, the lower the temp should be
Code: Select all
-- dzThermostaatOtgw - version 6 april 2023
--https://www.domoticaforum.eu/viewtopic.php?p=101441#p101441
return {
active = true,
logging = {
--level = domoticz.LOG_DEBUG, -- comment to use the dzVents global logging setting
marker = 'dzThermostaatOtgw'
},
on = {
devices = {'triggerhulp','thermostaat','OTGW FlameOn'},
timer = {'every minute'}, --"The CS command must be repeated at least every minute as long as adjustment is needed. This is a vigilance check to prevent runaway heating in case the controlling program loses its connection, or crashes."
},
data = {
cvLangNietAangestuurd = {initial=0},
iWaardeTotaal = {initial=0},
totaleBrandtijd = {initial=0},
schakelmoment = {initial=0},
periodiekStoken= {initial=0},
},
execute = function(dz, item)
local notifyHead='dzOtgw'
local notifyLevel = 3 --messageType 2=log, 3=pushover, 5=speak, 7=siren, 11=whisper, 13=shout; multiply values for combinations i.e. 15=pushover and speak
local tempKetel = dz.devices('OTGW Boiler Water Temperature').temperature
local tempBinnen = dz.utils.round(dz.devices('tempBinnen').temperature,1)
local tempBuiten = dz.utils.round(dz.devices('tempBuiten').temperature,1)
local tempZolder = dz.utils.round(dz.devices('tempZolder').temperature,1)
local setpointZolder = dz.devices ('heatZolder').setPoint
local thermostaat = dz.devices('thermostaat').setPoint
local otgwCS = dz.devices('otgwCS').temperature
local iWaardeTotaal=dz.data.iWaardeTotaal
local totaleBrandtijd=dz.data.totaleBrandtijd
local schakelmoment=dz.data.schakelmoment
local inschakelTemp=-2 --tussen inschakelTemp en uitschakelTemp wordt lineair de warmwater CV temp bepaalt
local uitschakelTemp = -0.5 --tussen inschakelTemp en uitschakelTemp wordt lineair de warmwater CV temp bepaalt; als de CV de afgelopen tijd niet gebrand heeft dan wordt deze waarde verhoogd, afhankelijk van iFactor
if tempBuiten < -3 then -- als het koud is dan meer focus op gas(cv) ipv electro(airco)
uitschakelTemp = 0.2
elseif tempBuiten < 0 then
uitschakelTemp = 0
end
local laagsteCvTemp = 40
local hoogsteCvTemp = 65
local stooklijnTempLaag = -8 --onder deze buitentemperatuur wordt het water opgestook tot hoogsteCvTemp
local stooklijnTempHoog = 20 --boven deze buitentemperatuur wordt het water opgestook tot LaagsteCvTemp
local iFactor = 50 --percentage dat de brandhistorie invloed heeft op het nieuwe setpoint
local maxHistorie=90 --maximale tijd [min] om CV ketel brandtijd historie te loggen
-- Stooklijn: de buitentemperatuur bepaalt de hoogsteCvTemp
--voorbeeld
--stookverschil = 25
--tempverschil = 10
--hoogsteCvTemp = 35+10/25*25
stookBereik = stooklijnTempHoog - stooklijnTempLaag
tempBereik = hoogsteCvTemp - laagsteCvTemp
tempVerschil = stooklijnTempHoog - tempBuiten -- bij hoog tempVerschil moet hoogsteCvTemp hoog zijn
if tempVerschil < 0 then tempVerschil = 0 elseif tempVerschil > stookBereik then tempVerschil = stookBereik end
hoogsteCvTemp = dz.utils.round (laagsteCvTemp + tempVerschil/stookBereik * tempBereik, 0)
--iWaarde brandtijd historie bijhouden. Waarde 0=heeft hele uur gebrand / 100 = afgelopen uur niet aangegaan
--gemiddeldeCvTemp = (laagsteCvTemp + hoogsteCvTemp)/2
--if otgwCS==0 then brandtijd = brandtijd-gemiddeldeCvTemp else brandtijd=brandtijd+gemiddeldeCvTemp end
if otgwCS==0 and dz.devices('OTGW FlameOn').active and not dz.devices('tapwater').active then iWaardeTotaal = iWaardeTotaal-1/maxHistorie else iWaardeTotaal=iWaardeTotaal+1/maxHistorie end
if iWaardeTotaal < 0 then iWaardeTotaal = 0 elseif iWaardeTotaal>maxHistorie then iWaardeTotaal=maxHistorie end --brandtijd in minuten brandtijd
iWaarde = dz.utils.round(100-iWaardeTotaal / maxHistorie * 100,0) --waarde tussen 0 en 100
--pWaarde: 100=hoge nood om te branden ; 0= temperatuur in woonkamer is hoog genoeg
ondergrens = inschakelTemp
bovengrens = uitschakelTemp
bereik = (bovengrens - ondergrens)*(1+iWaarde*iFactor/100/100) --stel iFactor = 30 en iWaarde =50 dan wordt bereik met 1.15 vergroot
bovengrens = dz.utils.round(inschakelTemp + bereik,0)
offset= tempBinnen - thermostaat
if offset < ondergrens then nieuw=hoogsteCvTemp --het is koud, CV maximaal inschakelen
elseif offset > bovengrens then
nieuw=0
dz.log('[offset groter dan bovengrens,nieuw=0]', dz.LOG_DEBUG)
else
nieuw = dz.utils.round(laagsteCvTemp+(hoogsteCvTemp - laagsteCvTemp)*offset/(ondergrens-bovengrens),0)
dz.log('[offset kleiner dan bovengrens, ruwe nieuw='..nieuw..']', dz.LOG_DEBUG)
if nieuw > hoogsteCvTemp then nieuw = hoogsteCvTemp elseif nieuw < laagsteCvTemp then nieuw = laagsteCvTemp end
end
dz.log('nieuw - tussenstap 1: '..nieuw, dz.LOG_DEBUG)
if dz.devices('OTGW FlameOn').active and not dz.devices('tapwater').active
then -- vlam is aan
if schakelmoment <= 0 then --vlam stond uit?
schakelmoment = dz.time.dDate
brandtijd = 0
dooftijd = 0
else
brandtijd = (dz.time.dDate - schakelmoment)/60
dooftijd = 0
end
else -- vlam is uit
if schakelmoment >= 0 then --vlam stond aan?
now=dz.time.dDate
totaleBrandtijd = totaleBrandtijd + (now - schakelmoment)/60 --bijhouden omdat anders stop periodiekstoken niet als de vlam korter dan 3 minuten aan is, totaleBrandtijd wordt gereset in periodiekstoken routine
schakelmoment = 0 - dz.time.dDate -- nieuw schakelmoment = negatieve waarde die het moment van vlam uit bewaard
brandtijd = 0
dooftijd = 0
else
dooftijd = (schakelmoment+dz.time.dDate)/60
brandtijd = 0
end
end
if
(brandtijd > 15 and nieuw - tempKetel < 10) or -- niet langer dan 15 minuten stoken
((not dz.devices('OTGW FlameOn').active) and dooftijd < 10) --minimaal 10 minuten wachten voordat je weer inschakelt
then
nieuw = 0
dz.log('er is warmtevraag, maar wachten op 10 minuten dooftijd of uitzetten na 15 minuten onafgebroken branden.', dz.LOG_DEBUG)
end
dz.log('nieuw - tussenstap 2: '..nieuw, dz.LOG_DEBUG)
gewensteStooktijd = 2
--elke uur 3 minuten CV laten branden, om badkamer, zolder en keukenvloer een beetje warm te houden naast airco verwarming
periodiekStokenTempGrens=12 --boven deze temperatuur de CV niet periodiek inschakelen
if dz.time.matchesRule('at 22:00-23:59') or dz.time.matchesRule('at 0:00-5:00') then dooftijdGrens = 999 --in de nacht niet periodiek inschakelen
elseif dz.time.matchesRule('at 6:00-7:21 on mon,tue,wed,thu,fri') or dz.time.matchesRule('at 8:00-9:21 on sat,sun') then dooftijdGrens = 20 --in de ochtend extra inschakelen om badkamer en huis extra te verwarmen
--elseif dz.devices ('zolderOpwarmen').active and tempBuiten<12 then dooftijdGrens = 30
elseif setpointZolder>=18 and tempZolder<17 and tempBuiten<6 then dooftijdGrens = 15 gewensteStooktijd=4
elseif setpointZolder>=17 and tempZolder<setpointZolder+2 and tempBuiten<12 then dooftijdGrens = 30
elseif tempBuiten<5 then dooftijdGrens = 45
elseif tempBuiten<1 then dooftijdGrens = 30
elseif tempBuiten<periodiekStokenTempGrens then dooftijdGrens = 90
else dooftijdGrens = 999
end
if dz.data.periodiekStoken == 1 then
if brandtijd + totaleBrandtijd >= gewensteStooktijd or tempBuiten > periodiekStokenTempGrens then
dz.data.periodiekStoken = 0
totaleBrandtijd = 0
--nieuw = 0 setten niet nodig, want je neemt de berekende waarde van hierboven over, die waarschijnlijk al nul is.
else
nieuw = laagsteCvTemp
end
elseif
tempBuiten < periodiekStokenTempGrens and
tempBinnen < 22 and
--tempBinnen - uitschakelTemp > thermostaat and
dooftijd > dooftijdGrens
then
dz.data.periodiekStoken = 1
nieuw = laagsteCvTemp
end
dz.log('nieuw - tussenstap 3: '..nieuw, dz.LOG_DEBUG)
--de nieuwe setwaarde naar de ketel sturen:
--if nieuw ~= otgwCS then
dz.openURL('http://192.168.0.107:8080/json.htm?type=command¶m=sendopenthermcommand&idx=33&cmnd=CS='..nieuw)
--end
dz.devices('cvKetelGraph').updateTemperature(thermostaat+nieuw/10) --dashticz waarde voor grafiek op keukentablet
if nieuw==0 and otgwCS==0 then
dz.log('OTGW CV is 0, ketel blijft uit.', dz.LOG_DEBUG)
else
dz.devices('otgwCS').updateTemperature(nieuw) --waardes continue doorsturen, voor het geval er eentje niet aankomt, behalve bij 0 ivm lastupdate
dz.log('OTGW CV ingesteld op: '..nieuw, dz.LOG_DEBUG)
end
if
dz.devices('otgwCS').lastUpdate.daysAgo>5
then
dz.data.cvLangNietAangestuurd=1
elseif
dz.devices('otgwCS').temperature~=0 and dz.data.cvLangNietAangestuurd==1
then
dz.helpers.managedNotify(dz, notifyHead,'Winter is coming. CV is na meer dan vijf dagen weer aangezet', 0, notifyLevel, 1)
dz.data.cvLangNietAangestuurd=0
end
dz.data.iWaardeTotaal = iWaardeTotaal
dz.data.totaleBrandtijd = totaleBrandtijd
dz.data.schakelmoment=schakelmoment
if dz.devices('OTGW FlameOn').active then dz.log('vlam is aan') else dz.log('vlam is uit') end
dz.log('hoogsteCvTemp: '..hoogsteCvTemp, dz.LOG_DEBUG)
dz.log('iWaardeTotaal: '..iWaardeTotaal, dz.LOG_DEBUG)
dz.log('iWaarde: '..iWaarde, dz.LOG_DEBUG)
dz.log('thermostaat: '..thermostaat, dz.LOG_DEBUG)
dz.log('tempKetel: '..tempKetel, dz.LOG_DEBUG)
dz.log('temp binnen: '..tempBinnen, dz.LOG_DEBUG)
dz.log('temp buiten: '..tempBuiten, dz.LOG_DEBUG)
dz.log('bereik: '..bereik, dz.LOG_DEBUG)
dz.log('inschakelTemp: '..inschakelTemp, dz.LOG_DEBUG)
dz.log('uitschakelTemp: '..uitschakelTemp, dz.LOG_DEBUG)
dz.log('bovengrens: '..bovengrens, dz.LOG_DEBUG)
dz.log('ondergrens: '..ondergrens, dz.LOG_DEBUG)
dz.log('offset (ingesteld <--> werkelijk): '..offset, dz.LOG_DEBUG)
dz.log('schakelmoment: '..schakelmoment, dz.LOG_DEBUG)
dz.log('brandtijd: '..brandtijd, dz.LOG_DEBUG)
dz.log('totale brandtijd: '..totaleBrandtijd, dz.LOG_DEBUG)
dz.log('dooftijd: '..dooftijd, dz.LOG_DEBUG)
dz.log('dz.data.periodiekStoken: '..dz.data.periodiekStoken, dz.LOG_DEBUG)
end
}
Last edited by renerene on Thu Apr 06, 2023 8:01 am, edited 1 time in total.