Merci pour votre aide !
Pour modifier la consigne en fonction de la plage horaire, j'ai créé le script suivant qui fonctionne :
Code : Tout sélectionner
-- ce script permet de modifier la consigne de température des radiateurs appelés dans le script module.lua
----------------------------------------------
------ Configuration ------
----------------------------------------------
local piece
local virtuel = 'Consigne'
local url = '192.168.x.xx:xxxx'
local thermostat_confort = 'Thermostat SdB enfants'
local thermostat_eco = 'Eco'
local thermostat_horsgel = 'Hors gel'
local programmateur = 'Programmateur chauffage' -- interrupteur de programmation des plages horaires de chauffage
local chauffage = 'Chauffage' -- interrupteur de mode chauffage (été/hiver)
local tempDeviceIdx=83
commandArray = {}
if otherdevices[chauffage]=='On' and otherdevices[programmateur]=='On' then
--commandArray['OpenURL']=url..'/json.htm?type=command¶m=udevice&idx=83&nvalue=0&svalue='.. thermostat_confort
commandArray['UpdateDevice'] =tempDeviceIdx..'|0|'..tonumber(otherdevices_svalues[thermostat_confort])
end
if otherdevices[chauffage]=='On' and otherdevices[programmateur]=='Off' then
--commandArray['OpenURL']=url..'/json.htm?type=command¶m=udevice&idx=83&nvalue=0&svalue='.. otherdevices_svalues[thermostat_eco]
commandArray['UpdateDevice'] =tempDeviceIdx..'|0|'..tonumber(otherdevices_svalues[thermostat_eco])
end
if otherdevices[chauffage]=='Off' then
--commandArray['OpenURL']=url..'/json.htm?type=command¶m=udevice&idx=83&nvalue=0&svalue='.. thermostat_horsgel
commandArray['UpdateDevice'] =tempDeviceIdx..'|0|'..tonumber(otherdevices_svalues[thermostat_horsgel])
end
return commandArray
Finalement, j'étais pas emballé par cette solution que je trouvais un peu lourde. Du coup, je suis revenu sur mon idée de départ, à savoir modifier légèrement la fonction PID dans le script "modules.lua" pour y intégrer le changement de consigne en fonction de mon programmateur et du mode été / hiver.
ça consiste simplement à remplacer
Code : Tout sélectionner
-- si l'on veut chauffer
if ( otherdevices[pid['OnOff']] == 'On' ) then
-- récupération de la consigne
local consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat']
par
Code : Tout sélectionner
-- si l'on veut chauffer
if ( otherdevices[pid['OnOff']] == 'On' ) then
-- récupération de la consigne
if ( otherdevices[pid['programmateur']] == 'On' ) then
consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat']
else
consigne = tonumber(otherdevices_svalues[pid['thermostat_eco']]) or pid['thermostat_eco']
end
Du coup, la fonction PID du modules.lua devient (sans l'autotune, je n'ai pas testé) :
Code : Tout sélectionner
function compute(pid)
local init = 0
local programmateur = 'Programmateur chauffage'
-- récupération température
local temp = getTemp(pid['sonde'])
-- récupération température ext
local temp_ext = nil
if pid['sonde_ext'] ~= '' and pid['sonde_ext'] ~= nil then
temp_ext = getTemp(pid['sonde_ext'])
end
-- création variable : 4 dernières températures
if (uservariables['PID_temps_'..pid['zone']] == nil ) then
creaVar('PID_temps_'..pid['zone'],string.rep(temp..';',3)..temp)
init = 1
end
-- création variable : intégrale
if (uservariables['PID_integrale_'..pid['zone']] == nil ) then
creaVar('PID_integrale_'..pid['zone'],'0')
init = 1
end
if init == 1 then
log('PID '..pid['zone']..' initialisation..',pid['debug'])
do return end
end
-- définition des variables locales
local moy_erreur = 0
local n = 1
local somme_erreurs = 0
local heatTime
local marche
local arret
local tmp = {}
-- définition des commandes marche/arrêt
if pid['invert'] then
marche = 'Off' ; arret = 'On'
else
marche = 'On' ; arret = 'Off'
end
-- à chaque cycle
if ( time.min%pid['cycle'] == pid['freq'] ) then
-- maj des 4 dernières temps
local temps = string.match(uservariables['PID_temps_'..pid['zone']],";([^%s]+)")..";"..temp
commandArray[#commandArray+1] = {['Variable:PID_temps_'..pid['zone']] = temps}
-- si l'on veut chauffer
if ( otherdevices[pid['OnOff']] == 'On' ) then
-- récupération de la consigne
if ( otherdevices[pid['programmateur']] == 'On' ) then
consigne = tonumber(otherdevices_svalues[pid['thermostat']]) or pid['thermostat']
else
consigne = tonumber(otherdevices_svalues[pid['thermostat_eco']]) or pid['thermostat_eco']
end
-- calcul de l'erreur
local erreur = consigne-temp
-- calcul intégrale auto consumée et moyenne erreur glissante
temps:gsub("([+-]?%d+%.*%d*)",function(t)
tmp[n] = tonumber(t)
err = tonumber(consigne-t)
somme_erreurs = somme_erreurs+err
moy_erreur = moy_erreur+err*n^3
n = n+1
end)
somme_erreurs = round(constrain(somme_erreurs,0,255),1)
moy_erreur = round(moy_erreur/100,2)
-- calcul de la dérivée (régression linéaire - méthode des moindres carrés)
local delta_erreurs = round((4*(4*tmp[1]+3*tmp[2]+2*tmp[3]+tmp[4])-10*(tmp[1]+tmp[2]+tmp[3]+tmp[4]))/20,2)
-- aux abords de la consigne, passage au second systême integrale
if somme_erreurs < 2 then
somme_erreurs = tonumber(uservariables['PID_integrale_'..pid['zone']])
-- re calcule intégrale si hors hysteresis
-- à moins d'un dixièmes de degré d'écart avec la consigne
-- le ratrapage est considéré OK, l'intégrale n'est pas recalculée
if math.abs(erreur) > 0.11 then
-- calcule intégrale
somme_erreurs = round(constrain(somme_erreurs+erreur/2,0,5),2)
-- maj
commandArray[#commandArray+1] = {['Variable:PID_integrale_'..pid['zone']] = tostring(somme_erreurs)}
end
end
-- boucle ouverte,
-- modification dynamique des paramètres de régulation suivant température extérieure
local Kb = 0
if temp_ext ~= nil then
Kb = pid['Kb'] * (consigne - temp_ext - pid['ref']) / 100
end
pid['Kp'] = round(pid['Kp'] + pid['Kp'] * Kb)
pid['Ki'] = round(pid['Ki'] + pid['Ki'] * Kb)
pid['Kd'] = round(pid['Kd'] + pid['Kd'] * Kb)
-- calcul pid
local P = round(pid['Kp']*moy_erreur,2)
local I = round(pid['Ki']*somme_erreurs,2)
local D = round(pid['Kd']*delta_erreurs,2)
-- calcul de la commande en %
local commande = round(constrain(P+I+D,0,100))
-- calcul du temps de fonctionnement
if commande == 100 then
-- débordement de 20s pour ne pas couper avant recalcule
heatTime = (pid['cycle']*60)+20
elseif commande > 0 then
-- secu mini maxi
heatTime = round(constrain(commande*pid['cycle']*0.6,pid['secu'],(pid['cycle']*60)-pid['secu']))
elseif commande == 0 then
-- coupure retardée
heatTime = constrain(pid['secu']-lastSeen(pid['radiateur']),0,pid['secu'])
end
-- AFTER n'aime pas 1 ou 2..
if heatTime == 1 or heatTime == 2 then
heatTime = 0
end
-- action sur l'élément chauffant
if heatTime > 0 then
commandArray[#commandArray+1] = {[pid['radiateur']] = marche}
commandArray[#commandArray+1] = {[pid['radiateur']] = arret..' AFTER '..heatTime}
else
commandArray[#commandArray+1] = {[pid['radiateur']]=arret}
end
-- journalisation
if pid['debug'] then
log('PID zone: '..string.upper(pid['zone']))
if temp_ext ~= nil then
log('temperature ext: '..temp_ext..'°C')
end
log('température int: '..temp..'°C pour '..consigne..'°C souhaité')
log('Kp: '..pid['Kp'])
log('Ki: '..pid['Ki'])
log('Kd: '..pid['Kd'])
log('erreur: '..moy_erreur)
log('somme erreurs: '..somme_erreurs)
log('delta erreurs: '..delta_erreurs)
log('P: '..P)
log('I: '..I)
log('D: '..D)
log('cycle: '..pid['cycle']..'min (sécu: '..pid['secu']..'s)')
-- avertissement si secu dépasse 1/4 du cycle
if ((100*pid['secu'])/(60*pid['cycle'])>25) then
warn('sécu trop importante, ralonger durée de cycle..')
end
log('commande: '..commande..'% ('..string.sub(os.date("!%X",heatTime),4,8):gsub("%:", "\'")..'\")')
log('')
end
-- maj sonde virtuelle
--commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[pid['sonde']..'_pid']..'|0|'..temp..';'..commande..';0'}
end
end
-- toutes les 15 minutes, si on ne veut pas chauffer
if ( time.min%15 == 0 and otherdevices[pid['OnOff']] == 'Off' ) then
-- arrêt chauffage (renvoi commande systematique par sécurité)
commandArray[#commandArray+1] = {[pid['radiateur']] = arret..' AFTER '..constrain(pid['secu']-lastSeen(pid['radiateur']),3,pid['secu'])}
-- maj sonde virtuelle
--commandArray[#commandArray+1] = {['UpdateDevice'] = otherdevices_idx[pid['sonde']..'_pid']..'|0|'..temp..';0;0'}
end
end
et le script pour une zone :
Code : Tout sélectionner
-- Ce script permet réguler la température de la zone
-- chargement des modules
dofile('/home/pi/domoticz/scripts/lua/modules.lua')
--------------------------------
------ Variables à éditer ------
--------------------------------
local pid={}
pid['debug'] = true -- true pour voir les logs dans la console log Dz ou false pour ne pas les voir
pid['zone'] = 'SdB enfants' -- nom de la zone pour affichage dans les logs et distinction de variables
pid['sonde'] = 'Temperature SdB enfants' -- nom de la sonde de température
pid['sonde_ext'] = 'Station Meteo Bouvesse' -- nom de la sonde de température ext si présente
pid['OnOff'] = 'Chauffage' -- nom de l'interrupteur virtuel de mise en route (été/hiver)
pid['programmateur'] = 'Programmateur chauffage' -- nom de l'interrupteur de programmation de la plage de fonctionnement en mode confort
pid['thermostat'] = 'Thermostat chambre Dorian' -- consigne ou 'nom' de l'interrupteur virtuel de thermostat
pid['thermostat_eco'] = 'Eco' -- consigne ou 'nom' de l'interrupteur virtuel du thermostat mode Eco
pid['thermostat_horsgel'] = 'Hors gel' -- consigne ou 'nom' de l'interrupteur virtuel du thermostat mode Hors gel
pid['ref'] = 8 -- écart entre temp ext et consigne au moment de l'autotune
-- actionneur
pid['radiateur'] = 'Radiateur SdB enfants' -- Nom de l'interrupteur de chauffage
pid['invert'] = false -- si On et Off doivent être inversé ou non
-- PID
pid['Kp'] = 45 -- Coefficient proportionnel
pid['Ki'] = 20 -- Coefficient intégrateur
pid['Kd'] = 45 -- Coefficient dérivateur
pid['Kb'] = 1 -- Coefficient de boucle ouverte
pid['cycle'] = 10 -- temps en minute d'un cycle PID
pid['freq'] = 3 -- décalage du cycle (reste division minutes/cycle)
pid['secu'] = 30 -- temps mini en seconde entre 2 ordres opposés
--------------------------------
-- Fin des variables à éditer --
--------------------------------
commandArray = {}
compute(pid)
--autotune(pid)
return commandArray
Merci à tout le monde pour votre aide et plus particulièrement à vil1driver qui a créé ce script !
J'en ai profité pour mettre l'interrupteur chauffage en mode switch (comme Ogulf) afin de gérer plus proprement la fonction "Eté / Hiver / Hors gel"