chauffage PID

Vous avez crée un script lua dont vous êtes fier, un .sh génial, un programme python hors du commun, un tuto , c'est ici que vous pouvez les partager.
Soyez précis quant aux prérequis, les manips à faire pour que votre bijou fonctionne (des chmod ?, un apt-get à faire ...)
Décrivez précisément son fonctionnement
Placez votre code entre [Quote] et {/Quote]
denis_brasseur
Messages : 193
Enregistré le : 24 déc. 2018, 17:05
Localisation : (26)

Re: chauffage PID

Message par denis_brasseur » 28 févr. 2019, 05:59

garycooper a écrit :
26 févr. 2019, 22:48
Merci pour le lien. J'ai fait ce script qui fonctionne (à priori) :

Code : Tout sélectionner

-- script pour activer le device "Programmateur chauffage" 

local programmateur_chauffage = 'Programmateur chauffage'
local vacances_scolaires = 'Aujourdhui vacances scolaires'
local jf = uservariables['jf']

-- retourne le jour actuel
days = {"dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"}
jour = days[(os.date("%w")+1)]
-- retourne l'heure actuelle ex: "12:45"
heure = string.sub(os.date("%X"), 1, 5)


commandArray = {}
	commandArray[programmateur_chauffage] = 'On'
-- tous les jours sauf les jours de travail => éteindre le chauffage entre minuit et 6h du matin
	if (heure > '00:00' and heure < '06:00') then
		commandArray[programmateur_chauffage] = 'Off'
-- journée de travail hors vacances scolaires => arrêter chauffage entre 7h30 et 16h30
		elseif otherdevices[vacances_scolaires]=='Off' or uservariables['jf']=='false' or jour=='lundi' or jour=='mardi' or jour=='jeudi' then
		if (heure > '07:30' and heure < '16:30') then
		commandArray[programmateur_chauffage] = 'Off'
		end
	end

return commandArray

Sinon, la philosophie est :
L'interrupteur "Programmateur de chauffage" est sur "OFF" tous les jours entre minuit et 6h du matin mais aussi entre 8h30 et 16h30 les lundi, mardi et jeudi hors vacances et jours fériés.

J'attends demain pour voir si ça c'est bien coupé à minuit et si c'est bon, j'essaie de l'intégrer au PID. Le "problème" c'est qu'à chaque exécution du script (donc toutes les minutes), ça implémente les logs de l'interrupteur d'un "ON" ou d'un "Off"
Pour l'implémentation des logs d'un "On" suivi d'un "Off", cela correspond à ton script, puisque avant de tester

Code : Tout sélectionner

if (heure > '00:00' and heure < '06:00') then
tu fais

Code : Tout sélectionner

commandArray[programmateur_chauffage] = 'On'
Je ne vois pas l'interet de cette ligne, et elle explique tes logs.
Dans tout les cas, ton script étant exécuté toute les minutes, (puisque non basé sur un changement d'état ou d'heure), tu auras son exécution régulière, avec trace d'un log toute les minutes entre 00:00 et 06:00 par exemple.
Tu vas donc éteindre ton chauffage toutes les mn de 00:00 à 06:00.
Un test sur le changement d'heure (du genre, il est minuit) serait peux être plus adapté.
Ou alors, exécuter ce script toutes les 1/2 h ou toute les h.
Domoticz + Raspberry Pi3 + Disque Dur PiDrive + RFXtrx433
10 Getdio 54755 (gestion chauffage)
2 CHACON 34131 (détecteur fumées)
5 Bresser Capteur thermo/hygro RC 5CH
2 CHACON DiO 54781 (contacteur porte)
1 Compteur de consommation OWL Micro+ CM180

Disable adblock

This site is supported by ads and donations.
If you see this text you are blocking our ads.
Please consider a Donation to support the site.


garycooper
Messages : 154
Enregistré le : 07 août 2017, 23:58

Re: chauffage PID

Message par garycooper » 01 mars 2019, 16:58

Merci denis_brasseur, je pense avoir enfin trouver comment gérer plus proprement le script de programmation du chauffage. C'est certainement pas le plus léger, mais ça fonctionne (à priori) :

Code : Tout sélectionner

-- script pour activer le device "Programmateur chauffage" 

local programmateur_chauffage = 'Programmateur chauffage'
local vacances_scolaires = 'Aujourdhui vacances scolaires'
local jf = uservariables['jf']

-- retourne le jour actuel
days = {"dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"}
jour = days[(os.date("%w")+1)]
-- retourne l'heure actuelle ex: "12:45"
heure = string.sub(os.date("%X"), 1, 5)


commandArray = {}

-- commande journalière quel que soit le jour (arrêt de minuit à 6h du matin / marche entre 6h et 7h30 / marche entre 16h30 et minuit)
	if (heure > '00:00' and heure < '06:00') and otherdevices[programmateur_chauffage]=='On' then
		commandArray[programmateur_chauffage] = 'Off'
	end
	if (heure > '06:00' and heure < '07:30') and otherdevices[programmateur_chauffage]=='Off' then
		commandArray[programmateur_chauffage] = 'On'
	end
	if (heure > '16:30') and otherdevices[programmateur_chauffage]=='Off' then
		commandArray[programmateur_chauffage] = 'On'
	end
-- Arrête le chauffage sur les jours travaillés	
	if otherdevices[programmateur_chauffage]=='On' and ((otherdevices[vacances_scolaires]=='Off' or uservariables['jf']=='false' or jour=='lundi' or jour=='mardi' or jour=='jeudi') and (heure > '07:30' and heure < '16:30')) then
		commandArray[programmateur_chauffage] = 'Off'
	end
	
return commandArray
@vil1driver : après avoir LONGTEMPS chercher, je pense qu'en fait je n'avais pas compris ta solution ... Tu proposes que je fasse un thermostat virtuel pour chaque pièce qui prendra la valeur soit du thermostat "confort", soit celle du thermostat "eco", soit celle du thermostat "hors gel" en fonction des plages que j'aurais programmé ?
Ce n'est pas possible de faire la même chose sans surcharger la page "mesures" ?

vil1driver
Messages : 5095
Enregistré le : 30 janv. 2015, 11:07
Localisation : Rennes (35)

Re: chauffage PID

Message par vil1driver » 01 mars 2019, 17:21

Je pensais à un unique thermostat par pièce.
Dont la valeur serait générée par le script que tu viens de présenter.

Dedans je supprimerais ton 'programmateur_chauffage'
Et j'enverrais directement la bonne valeur au thermostat.

Donc dans l'idée c'est un script par zone pour régler le thermostat selon les besoins
Et celui de ce topic (un par zone) pour s'y conformer

ogulf
Messages : 219
Enregistré le : 15 juin 2017, 14:41

Re: chauffage PID

Message par ogulf » 01 mars 2019, 17:26

Autant de scripts que de zones à chauffer chez moi, avec quelques modifications (ajout d'un décalage sur la fréquence, ajout d'un inter global Off/HG/On qui pilote toutes les zones plus 2-3 bricoles spécifiques à une zone).
Domoticz Beta sur Raspberry Pi3 + RFPlayer + ZWave+ + RFLink R48 :
- 11 x RF660P (gestion chauffage)
- 1 x FGSD-002 (détecteur fumée)
- 10 x F007TH (sonde température/hygro)
- 5 x Emcoluxr EV1527 (contacteur ouverture porte)

Disable adblock

This site is supported by ads and donations.
If you see this text you are blocking our ads.
Please consider a Donation to support the site.


garycooper
Messages : 154
Enregistré le : 07 août 2017, 23:58

Re: chauffage PID

Message par garycooper » 02 mars 2019, 00:55

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&param=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&param=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&param=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"

vil1driver
Messages : 5095
Enregistré le : 30 janv. 2015, 11:07
Localisation : Rennes (35)

Re: chauffage PID

Message par vil1driver » 02 mars 2019, 11:18

Bien joué ;)

Tu feras attention, tes modif seront effacées par une maj de modules.lua

garycooper
Messages : 154
Enregistré le : 07 août 2017, 23:58

Re: chauffage PID

Message par garycooper » 02 mars 2019, 12:55

Oui, je ferais attention de ne pas écraser la partie "compute PID" et "autotune".

J'ai malgré tout eu la désagréable suprise de voir que mon script "programmateur chauffage" ne fonctionne pas comme je veux, mais je devrais finir par y arriver. C'est simplement que j'ai des ordres qui se contredisent. Une fois je le fais mettre en "off" et une fois en "on" donc ça change toutes les minutes. Quand je n'ai pas cette alternance, le chauffage passe en mode éco même si c'est vacances ou week-end ou ...

Bref, pas facile à caler tout ça, mais je devrais y arriver.

vil1driver
Messages : 5095
Enregistré le : 30 janv. 2015, 11:07
Localisation : Rennes (35)

Re: chauffage PID

Message par vil1driver » 04 mars 2019, 12:22

Je ne pense pas que cela intéresse grand monde mais dans le cas où certains d'entre vous utiliseraient ce script avec une consigne fixe, pour piloter des modules DI.O, je peux partager..

J'ai porté avec succès le script pid dans la puce attiny85 du projet
'sonde radio oregon DIY'
La sonde est donc totalement autonome pour contrôler le chauffage de la pièce et maintenir la température.

Avantage, une fiabilité sans faille :)
la domotique peut subir des avaries, si madame n'a pas froid, l'ambiance est meilleure ;)

baliku
Messages : 8
Enregistré le : 31 mai 2018, 18:39

Re: chauffage PID

Message par baliku » 04 mars 2019, 20:19

Bonjour et merci pour tes réponses des pages 26 & 27, Nickel, tous va bien dans le meilleur des mondes, MERCI à toi JoliPassenger :idea: :?: :idea:
Tu excite ma curiosité avec ta 'sonde radio oregon DIY' je vais voir le post...
à quand le package prêt à commander ....
NAS Syno, Last Stable Ver°
RFLink 433.92+NRF24L01 : 6 THN132N, 5 KIT_FP433TEMP / ++MiLights / ++DI-O
HarmonyHub : FreeRev, TV LG, Amp Sony
Cabasse StreamAmp100, 3 Awox StriimLightWifi
KLF200 : 5 Somfy IO
IFTTT : GoogleAgenda
Blockly, DzVents, Bash
Tasker

acefx
Messages : 3
Enregistré le : 17 déc. 2018, 22:47

Re: chauffage PID

Message par acefx » 13 avr. 2019, 19:17

Hello a tous, desolé de vous deranger avec ca

Je fait tourner domoticz sur un Syno, tout fonctionne bien mise a part l'emplacement des script un peu chiant a trouver mais ca : C'est bon !
Je suis en cours d'autotune sur la zone salon, ca fait bien 3-4h.
Par contre je n'ai que tres peu de log pour l'instant :
019-04-13 18:59:55.631 Status: LUA: PID autotune SALON
2019-04-13 18:59:55.631 Status: LUA: mesures en cours..
2019-04-13 18:59:55.632 Status: EventSystem: Script event triggered: Chauffage Salon PID

répété a peu pres toutes les minutes.
J'espere que ca roule ;-)

mais j'ai une autre question,
Sur quelle valeur vous jouez pour le passage en mode nuit / eco / absent
Est ce que l'on fait un planning sur la valeur de temp. de la consigne ou bien sur le virtuel On Off du chauffage en general ?

Merci a tous

Disable adblock

This site is supported by ads and donations.
If you see this text you are blocking our ads.
Please consider a Donation to support the site.


Répondre