Thermostat recommandation: buy or build

This Forum is about the Opentherm gateway (OTGW) from Schelte

Moderator: hvxl

Post Reply
Tiller
Starting Member
Starting Member
Posts: 3
Joined: Wed Jan 25, 2023 8:41 pm

Thermostat recommandation: buy or build

Post by Tiller »

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!
Tiller
Starting Member
Starting Member
Posts: 3
Joined: Wed Jan 25, 2023 8:41 pm

Re: Thermostat recommandation: buy or build

Post by Tiller »

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:
2023-01-27_11-49.png
2023-01-27_11-49.png (90.03 KiB) Viewed 2310 times
2023-01-27_11-50.png
2023-01-27_11-50.png (91.5 KiB) Viewed 2310 times
2023-01-27_11-50_1.png
2023-01-27_11-50_1.png (31.68 KiB) Viewed 2310 times
dobi64
Starting Member
Starting Member
Posts: 1
Joined: Sat Jan 28, 2023 5:03 pm

Re: Thermostat recommandation: buy or build

Post by dobi64 »

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.
renerene
Starting Member
Starting Member
Posts: 1
Joined: Sat Nov 05, 2022 9:33 am

Re: Thermostat recommandation: buy or build

Post by renerene »

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

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&param=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.
Post Reply

Return to “Opentherm Gateway Forum”