L'hiver vient !
Après avoir passer toute la saison dernière à essayer de stabiliser le script de Vil1driver, j'en suis venu à la conclusion que je n'aurais jamais de coefficients PID fixes.
Avec un poêle à bois, les apports extérieurs aux chauffages électriques sont impossibles à anticiper et corriger.
J'ai donc cherché un autre algorithme et je suis tombé sur celui d'Argonaute du forum HACF.
Il s'agit d'une approche TPI (Time Propostional & Integration).
Il explique à merveille son fonctionnement et j'ai donc décidé de l'adapter à Domoticz en m'inspirant du très bon travail de Vil1driver.
Pré-requis :
- Une sonde de température intérieure de la pièce à chauffer
- Une sonde de température extérieure (optionnelle) pour prendre en compte les pertes
- Un interrupteur virtuel de mise en route du chauffage
- Un thermostat virtuel pour régler la consigne.
Il faudra quand même régler 3 variables :
local coeffC = 0.60 -- coeff qui dépend de la puissance du chauffage et de la surface. A augmenter si la consigne n'est pas atteite.
local coeffT = 0.01 -- dépend lui de l’isolation de la pièce et des pertes thermiques. A augmenter si la consigne est difficile à atteindre par grand froid.
local bandeProportionnelle = 1.5 -- différence de température entre la lecture et la consigne où la chauffe est permanente. Peut être réduite si la consigne n'est pas dépassée après la montée en température. Permet une chauffe plus rapide.
Pour une installation standard aux normes, on a coeffC = 0,6 et coeffT = 0,01.
Vous pouvez également modifier la durée de cycle et la durée minimum entre 2 ordres.
TPIZone.lua
Code : Tout sélectionner
--[[
Prerequisits
==================================
Domoticz v2020.2 or later (dzVents version 3.1 or later)
Chauffage TPI
Le principe vient d'Agonaute du forum HACF.
https://forum.hacf.fr/t/gestion-de-bout-en-bout-du-chauffage/4897
-- Authors ----------------------------------------------------------------
V1.0 - Argonaute - Version Home Assistant
V2.0 - Neutrino - Adaptaption pour Domoticz en DzVents
]]--
-- Variables to customize --------------------------------------------------
local zone = "Chambre"
local sonde = {'Temp Chambre'} -- Nom de la ou des sondes de température
local sonde_ext = {'Temp_ext','Temp Extérieure'} -- Nom de la ou des sondes de température ext si présente (option)
local OnOff = 'Chauffage' -- Nom de l'interrupteur virtuel de mise en route (été/hiver)
local thermostat = 'Thermostat Chambre' -- nom du thermostat virtuel
-- actionneur
local radiateur = 'Chauffage Chambre' -- Nom de l'interrupteur de chauffage
--Pour une installation standard aux normes, on a coeffC = 0,6 et coeffT = 0,01
local coeffC = 0.60 -- coeff qui dépend de la puissance du chauffage et de la surface.
local coeffT = 0.01 -- dépend lui de l’isolation de la pièce et des pertes thermiques.
local bandeProportionnelle = 1.5 -- différence de température entre la lecture et la consigne où la chauffe est permanente.
local cycle = 10 -- temps en minutes d'un cycle TPI
local secu = 30 -- temps minimum en secondes entre 2 ordres opposés
------------------------------------------------------------------------------
local scriptName = 'TPI'..zone
local scriptVersion = '2.0'
-- contraindre
local function constrain(x, a, b)
if (x < a) then
return a
elseif (x > b) then
return b
else
return x
end
end
local function averageTemp(domoticz,t)
local sum = 0
local taille = 0
for _,v in pairs(t) do -- Get the sum of all numbers in t
if domoticz.devices(v).lastUpdate.minutesAgo < 60
and tonumber(domoticz.devices(v).temperature) ~= nil then
sum = sum + domoticz.devices(v).temperature
taille = taille + 1
else
domoticz.log(domoticz.devices(v).name .." "..domoticz.devices(v).temperature.." "..domoticz.devices(v).lastUpdate.minutesAgo,domoticz.LOG_INFO)
end
end
return sum / taille
end
return {
active = true,
logging = {
level = domoticz.LOG_DEBUG, -- Uncomment to override the dzVents global logging setting
--level = domoticz.LOG_ERROR, -- Uncomment to override the dzVents global logging setting
--level = domoticz.LOG_INFO, -- Uncomment to override the dzVents global logging setting
marker = scriptName..' '..scriptVersion
},
on = {
timer = {
'every 1 minutes',
},
devices ={thermostat,
},
},
execute = function(domoticz, item)
local heatTime
-- récupération température
local temp = domoticz.utils.round(averageTemp(domoticz,sonde),2)
-- récupération température ext
local temp_ext = nil
if sonde_ext ~= '' and sonde_ext ~= nil then
temp_ext = domoticz.utils.round(averageTemp(domoticz,sonde_ext),2)
else
temp_ext = domoticz.devices(thermostat).setPoint
end
-- à chaque cycle ou quand la consigne est modifiée
if ( domoticz.time.minutes%cycle == 0 )or item.isDevice then
-- si l'on veut chauffer
if ( domoticz.devices(OnOff).active ) then
-- récupération de la consigne
local consigne = domoticz.devices(thermostat).setPoint
-- calcul de la commande en %
local commande
if consigne - temp >= bandeProportionnelle then
commande = 100
else
commande = ((coeffC * (consigne - temp)) + (coeffT * (consigne - temp_ext)))*100
end
domoticz.log("Puissance de chauffe "..commande.."%", domoticz.LOG_DEBUG)
-- calcul du temps de fonctionnement
if commande >= 100 then
-- débordement de 20s pour ne pas couper avant recalcule
heatTime = (cycle*60)+20
elseif commande > 0 and commande < 100 then
-- secu mini maxi
heatTime = domoticz.utils.round(constrain(commande*cycle*0.6,secu,(cycle*60)-secu))
elseif commande <= 0 then
-- coupure retardée
heatTime = constrain(secu-domoticz.devices(radiateur).lastUpdate.secondsAgo,0,secu)
end
-- action sur l'élément chauffant
if heatTime > 0 then
domoticz.devices(radiateur).switchOn()
domoticz.devices(radiateur).switchOff().afterSec(heatTime)
else
domoticz.devices(radiateur).switchOff()
end
-- journalisation
domoticz.log('TPI zone: '..string.upper(zone),domoticz.LOG_DEBUG)
if temp_ext ~= nil then
domoticz.log('temperature ext: '..temp_ext..'°C',domoticz.LOG_DEBUG)
end
domoticz.log('température int : '..temp..'°C pour '..consigne..'°C souhaité',domoticz.LOG_DEBUG)
domoticz.log('Temps de chauffe : '..heatTime.."s",domoticz.LOG_DEBUG)
domoticz.log('CoeffC : '..coeffC,domoticz.LOG_DEBUG)
domoticz.log('CoeffT : '..coeffT,domoticz.LOG_DEBUG)
domoticz.log('Cycle : '..cycle..'min (sécu: '..secu..'s)',domoticz.LOG_DEBUG)
-- avertissement si secu dépasse 1/4 du cycle
if ((100*secu)/(60*cycle)>25) then
domoticz.log('sécu trop importante, ralonger durée de cycle..',domoticz.LOG_ERROR)
end
end
end
-- toutes les 5 minutes, si on ne veut pas chauffer
if ( domoticz.time.minutes%5 == 0 and domoticz.devices(OnOff).state == 'Off' ) then
-- arrêt chauffage (renvoi commande systematique par sécurité)
domoticz.devices(radiateur).switchOff().afterSec(constrain(secu-domoticz.devices(radiateur).lastUpdate.secondsAgo,3,secu))
end
end
}
Mais ça a le mérite de fonctionner chez moi
