[LUA] Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Vous avez créé 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.
greg
Messages : 6
Inscription : 17 déc. 2016, 22:37

[LUA] Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par greg »

Hello,

Nouveau sur ce forum et débutant en domotique, j'ai le plaisir de partager le script que j'utilise pour chauffer mon chalet.
Il est situé à 1000m d'altitude, et équipé outre d'un poêle et d'un plancher chauffant (à la difficulté à chauffer et à l'inertie folles),
d'une paire de radiateurs électriques à fil pilote que j'ai équipés de relais DIO pour mode Hors-Gel ou Comfort.
Ce script sert à commander ces radiateurs, qui constituent les principales sources de chaleur.

Je remercie grandement les membres de ce forum pour leurs idées, leur code, leur aide aux membres du forum,
et en particulier Vil1driver, Guitoo et Jackyhi, dont je me suis largement inspiré du travail.

J'ai voulu un script assez complet, et voici les fonctionnalités implémentées :

- Multi- radiateurs ;
- Multi-thermomètres, avec détection de défaillance et fallback ;
- Multi-algorithmes, avec Hysteresis ou PID ;
- Comptage de la puissance instantanée et consommée ;
- Mode Présence ;
- Mono-zone. Plusieurs zones demandent plusieurs instances du script.

Le script demande de renseigner quelques paramètres simples dont les noms des composants.

Les composants nécessaires à l'utilisation du script sont :

- Un thermostat Confort
- Un thermostat Eco

- Un selecteur de mode de controle (Off / Hysteresis / PID )
- Un selecteur de mode de fonctionnement (Off / Eco / Confort / Forcé )

- Un switch de présence
- Un compteur d'energie

Les noms de ces devices sont à renseigner en paramètres au début du script.

En ce qui concerne les variables utilisateurs nécessaires, il faut en créer 4, et elles sont nommées :

- fISumLast, c'est un Float qu'on initialise à 0. C'est la valeur de l'intégrale du PID;
- fTempLastInput, c'est un Float qu'on initialise à 0. C'est la dernière température relevée pour le calcul du PID;
- fSetpointLast, c'est un Float qu'on initialise à 0. C'est la dernière consigne. Permet de vérifier si la consigne
a changée entre deux executions du script.
- iResetDeviceMeterTime, c'est un Integer qu'on initialise à 0. La variable est utile pour la mise à jour du compteur
électrique virtuel en mode PID.

Les thermomètres sont à déclarer dans un tableau, qui renseigne leur nom et le delta constaté par rapport au thermomètre de référence.
Si le thermomètre principal ne répond plus pendant plus de 10 minutes, le premier des suivants est utilisé et son delta est appliqué
pour constituer une "température virtuelle" dans la zone à chauffer. Un email d'alerte est envoyé. Si aucun thermomètre n'a répondu
durant les dernières 10 minutes, le script s'arrête sans action.

Les radiateurs sont à déclarer dans un tableau, qui renseigne, outre le nom attribué au périphérique dans Domoticz,
sa puissance en Watts (utilisé pour calcul de conso) et ses commandes pour l'allumer et l'éteindre.

Pour la partie PID, on doit régler les 3 fameux paramètres P, I et D, et là ça se complique un peu, mais rien de bien méchant.

Je me réfère aux travaux décrits sur les sites brettbeauregard.com [1], rhaaa.fr [2] et controlguru.com [3], qui sont passionants et très bien faits.
J'en remercie ici vivement leurs auteurs.

Notre controle de chauffage est ce qui s'appelle, en science de l'automatique, un régulateur PID.
Wikipedia : "Action Proportionnelle - Intégrale - Dérivée, [...] est un des outils les plus utilisés pour l'asservissement d'un système."
Et en effet, nous asservissons les radiateurs à la température de la pièce. L'équation de calcul du PID va nous donner une
valeur qui va déterminer la puissance instantanée du chauffage à produire pour arriver à la consigne. Le script va
appliquer cette valeur de puissance à nos radiateurs (en les allumant X minutes toutes les Y minutes, car ils fonctionnent seulement
en mode On/Off).
Pour calculer cette valeur, il nous faut déterminer une fois pour toutes les 3 coefficients Kp, Ki, et Kd, inhérents à
notre système de chauffage, notre habitation, ses pertes et son inertie.
Il y plusieurs étapes pour calculer ces valeurs, et je pense que cela vaut le coup de le faire ! L'efficience de notre
chauffage, le confort et les économies d'énergie sont à la clé ! Je vous conseille de mettre tout ca dans une feuille de calcul,
afin de pouvoir faire varier les paramètres facilement.

Il y a 8 valeurs à calculer :

1- Kp, le gain du process. Quel écart de température j'aurais si je change la commande de ma source de chaleur de tant ?

Kp = ΔPV / ΔCO avec PV (Process Variable) la température de la pièce et CO (Controller Output), le pourcentage de puissance
des radiateurs (le réglage).

Pour obtenir cette valeur, j'ai fait tourner le script avec des valeurs basiques, j'ai attendu d'avoir un bon plat
dans la courbe de température et j'ai regardé dans le log à combien de % le chauffage fonctionnait.
En augmentant la consigne et en stabilisant la température, même observation. On obtient un écart de température et
un écart de puissance, on a Kp (exprimé en °C/%)

2- Tp, la constante de temps. Décrit la vitesse de variation du chauffage.

Il a été determiné que cette valeur est atteinte quand la réaction (température de la pièce) attend 63% de la consigne.

Je lis sur un graphe que si je passe de ma consigne de 20°C à 21°C, la pièce atteint 21°C en une heure.
Les 63% d'une heure correspondent à 37.8 minutes, soit 2268 secondes.

3- θp, le temps mort, qui est le temps passé entre l'action et la réaction.

Je l'ai determiné en mesurant en combien de temps mon thermomètre se mettait à monter lorsque je passait
d'une température de 20 à 22.

4- Tc, le temps de réponse. C'est la vitesse à laquelle le système de chauffage va réagir. Si il est rapide, on
peut s'attendre à un dépassement de la consigne. Si il est lent, on n'aura pas cette tendance. Une valeur moyenne
doit être bonne pour un chauffage.

On choisit son paramètre Tc en se plaçant dans un des trois cas :

4-1- Réglage Aggressif : Tc est la valeur la plus grande entre 0.1 x Tp et 0.8 x θp
4-2- Réglage Intermédiaire : Tc est la valeur la plus grande entre 1 x Tp et 8 x θp
4-3- Réglage Conservateur : Tc est la valeur la plus grande entre 10 x Tp et 80 x θp

5- Kc, le gain du controleur. Ce sera notre P. Il donne la pente principale à prendre pour rattraper la consigne.

Kc = P = (1/Kp)*(Tp/(θp+Tc))

6- I, le coefficient d'intégration. Il pondère ce que le système a accumulé en dépassement de consigne.

I = Kc/Ti

7- Td, temps de dérivation, permet de calculer notre dernier paramètre. Il donne du poids à l'action dérivée.

Td = (Tp x θp)/(2Tp+θp)

8- D, le coefficient de dérivation. Il améliore la stabilité du système, notamment en amortissant les oscillations.

D = Kc * Td

Comme il est difficile d'obtenir des valeurs exactes, il peut être intéressant de jouer un peu dans les plages
de valeurs que l'on mesure (température, temps et réglage de la puissance de chauffe) pour s'approcher au mieux
d'un triplet de valeurs Kp, Ki, Kd qui donne une courbe la plus plate possible.

Le blog Coding Laboratory a une très belle interface pour se rendre compte de l'importance de chacun des paramètres P, I et D :
http://codinglab.blogspot.ch/2016/04/on ... ainer.html

Pour ma part, avec un réglage légerement aggressif afin d'avoir une montée rapide en température, j'obtient ce type de graphe de température, par exemple pour une montée à 15 degrés :
pid-regul-temp-1.png
pid-regul-temp-1.png (447.43 Kio) Consulté 18988 fois
Limitation : le script ne supporte que les thermomètres qui mesurent aussi l'humidité.

Je suis curieux d'avoir des retours sur l'utilisation éventuelle de ce script, en particulier en terme de
confort de chauffage et d'économie d'energie. Merci d'avance.

Greg

[1] http://brettbeauregard.com/blog/category/pid/
[2] http://www.rhaaa.fr/regulation-pid-comment-la-regler-12
[3] http://controlguru.com

Code : Tout sélectionner

--[[

Type : Time
Name : script_time_heating.lua
Description : Controls heating in a room with hysterisis or PID method
Usage : Place in scripts/lua directory of Domoticz instance

This script provides heating control in a room, providing different modes (Comfort, Eco), according
to presence in the room and to a couple of setpoints. The heating control is proposed through
two differents algorithms (Hysterisis or PID). The script supports multiple temperature control
devices used in fallback, and multiple heating devices used simultaneously.
A power consumption computation is made, based on the declared power consumption of each heating device.

Required Domoticz configuration :

- A Thermostat to set the comfort temperature, created with Dummy hardware and a Thermostat device
  Variable : sSetPointConfortDeviceName

- A Thermostat to set the eco temperature, created with Dummy hardware and a Thermostat device
  Variable : sSetPointEcoDeviceName

- A Mode switch to set and program with timers the heating scenarii, created with Dummy hardware and a Selector Switch device
  Variable : sHeatingModeDeviceName

- A Control Mode switch to switch between the Hysterisis and PID ways of control.
  Variables : sHeatingControlModeDeviceName
  sHeatingControlModePIDName, sHeatingControlModeHysteresisName are used for the name given to either mode.

- A Presence detection switch. The switch would be controlled either by hand or by some external scripts/commands.
  Variable : sPresenceDeviceName

- An Electricity consumption meter, created with an Instant+Counter meter
  Variable : sPowerMeterDeviceName

- Heaters
  One or more heaters have to be declared in an array, together with their power consumption and commands.
  Variable : aHeatingDeviceNames

- Temperature sensors
  They are declared in a array, with fall back mode implemented. The script is written for sensors that gather both temperature and humidity.
  Variable : aTempSensorDeviceNames

- User variables
  - fISumLast, a float value initialized to 0, that's the PID current integral value ;
  - fTempLastInput, a float value initialized to 0, used for the PID derivative computation ;
  - fSetpointLast, a float value initialized to 0, used to check a setpoint change ;
  - iResetDeviceMeterTime, an integer value initialized to 0, used to record the power meter reset time.

The PID parameters are to be determined for your own installation. Three parameters need to be calculated,
according to the following formulas :

Kp = ΔPV / ΔCO  -- On steady temperature states, ratio of temperature difference for command difference
Tp -- Time needed to reach 63% of the setpoint
θp -- Time between action on the heating and measurable reaction of the temperature sensor
Tc -- Response time, highest value among 0.1Tp or 0.8θp (agressive), 1Tp or 8θp (middle), 10Tp or 80θp (conservative)
Kc = P = (1/Kp)*(Tp/(θp+Tc)) -- Our fPIDKp
I = Kc/Ti -- Our fPIDKi
Td = (Tp x θp)/(2Tp+θp) -- Needed to compute the last constant
D = Kc * Td -- Our fPIDKd

This script distributed under the GPL license. Please see https://www.gnu.org/licenses/gpl.html
--]]

-- Zone name
local sZoneName = 'Living room'

-- Setpoint
local sSetPointConfortDeviceName = 'Thermostat Confort'         -- Thermostat for comfort Setpoint
local sSetPointEcoDeviceName = 'Thermostat Eco'                 -- Thermostat for eco Setpoint

-- Power Meter
local sPowerMeterDeviceName = 'Consommation Chauffage'          -- Power meter based on configured heating devices consumption

-- Modes
-- These modes belong to the heating mode selector switch
local sHeatingModeDeviceName = 'Mode Chauffage'
local sHeatingModeComfortName = 'Confort'
local sHeatingModeEcoName = 'Eco'
local sHeatingModeForceOnName = 'Force'
local sHeatingModeFrostFreeName = 'Off'

-- Heating control mode (PID or Hysteresis)
local sHeatingControlModeDeviceName = 'Mode Controle Chauffage'
local sHeatingControlModePIDName = 'PID'                             -- Selection switch name for PID
local sHeatingControlModeHysteresisName = 'Hysteresis'         -- Selection switch name for hysterisis mode

local fHysteresis = 0.4                          -- Hysterisis value

-- Sensors
-- Will be choosen in fallback. Second parameter is a delta to the first temp sensor
local aTempSensorDevices = {
                             { 'Living-room 1',0 } ,

                             { 'Chambre Enfant',1.2 }     -- The room is usually ~1.2 deg hotter than the living room
                           }

local sPresenceDeviceName = 'Presence'          -- Presence device switch. Heating goes in Eco mode when Presence is Off.

-- Heaters
-- Domoticz Device Name, power in Watts, On command, Off command.
local aHeatingDevices = {
                             { 'Hors-Gel Radiateur Salon Est', 1500 , 'Off AFTER 3', 'On' } ,

                             { 'Hors-Gel Radiateur Salon Sud', 1500 , 'Off AFTER 3', 'On' }

                        }

-- PID - Proportional, Integral, Derivative - Parameters

local iHeatingCycleDuration = 10 -- Duration of a heating cycle in minutes, to be adapted to the heating devices
local fPIDKp = 113  -- Change this !
local fPIDKi = 0.05 -- Change this !
local fPIDKd = 30045 -- Change this !

-- Alerts
local sEmailContact = 'name@domain.tld'

-- Debug
local bDebug = true
---------------------------------------------- End of configuration section ----------------------------------------------

-- Variables

local fCurrentTemp = 1000

-- Statics variables
-- Heating commands, constants not to be changed
local sHeatingOnCommand = 'ON'
local sHeatingOnForCommand = 'ONFOR'
local sHeatingOffCommand = 'OFF'

-- Functions

function prDebug(sString)
  if(bDebug) then
   print ( sString )
  end
end

function addCommand( sDevice, sCommand )
   commandArray[#commandArray+1] = { [sDevice] = sCommand }
end

function timeDifference(sDeviceName)
   sDeviceTimeChanged = otherdevices_lastupdate[sDeviceName]
   sYear = string.sub(sDeviceTimeChanged, 1, 4)
   sMonth = string.sub(sDeviceTimeChanged, 6, 7)
   sDay = string.sub(sDeviceTimeChanged, 9, 10)
   sHour = string.sub(sDeviceTimeChanged, 12, 13)
   sMinutes = string.sub(sDeviceTimeChanged, 15, 16)
   sSeconds = string.sub(sDeviceTimeChanged, 18, 19)
   t1 = os.time()
   t2 = os.time{year=sYear, month=sMonth, day=sDay, hour=sHour, min=sMinutes, sec=sSeconds}
   return os.difftime (t1, t2)
end

function round(fNumber, iPrecision)
  local iMult = 10^(iPrecision or 0)
  return math.floor(fNumber * iMult + 0.5) / iMult
end

function commandHeating(sCommand,iTime)
 local fIntervalEnergy = 0
 local fInstantPower = 0

      -- Send command to heaters, calculate power and energy

       for iHeatingDeviceIndex = 1, #aHeatingDevices do
        local sActiveHeatingDevice = aHeatingDevices[iHeatingDeviceIndex]
        fInstantPower = fInstantPower + sActiveHeatingDevice[2]
        if( sCommand == sHeatingOnForCommand ) then
          fIntervalEnergy = fIntervalEnergy + (tonumber(fInstantPower) / 60 ) * iHeatingCycleDuration 
        else
           fIntervalEnergy = fIntervalEnergy + tonumber(fInstantPower) / 60 
        end
        if( sCommand == sHeatingOnCommand ) then
         prDebug('Heating device : - '..sActiveHeatingDevice[1]..' - , power : ' .. sActiveHeatingDevice[2]..' Watts gets command : '..sActiveHeatingDevice[3])
         addCommand(sActiveHeatingDevice[1],sActiveHeatingDevice[3])
        end
        if( sCommand == sHeatingOnForCommand ) then 
         prDebug('Heating device : - '..sActiveHeatingDevice[1]..' - , power : ' .. sActiveHeatingDevice[2]..' Watts gets command : '..sActiveHeatingDevice[3]..' FOR '..tostring(iTime))
         addCommand(sActiveHeatingDevice[1],sActiveHeatingDevice[3] .. ' FOR ' .. tostring(iTime))  -- Can be missed :-( --> zwave!
        end
        if( sCommand == sHeatingOffCommand ) then
         prDebug('Heating device : - '..sActiveHeatingDevice[1]..' - , power : ' .. sActiveHeatingDevice[2]..' Watts gets command : '..sActiveHeatingDevice[4])
         addCommand(sActiveHeatingDevice[1],sActiveHeatingDevice[4])
        end
       end

      -- Energy accounting
       -- Get current power-meter values
       sCurrentPower,sCurrentTotalEnergy = string.match(otherdevices_svalues[sPowerMeterDeviceName], "(%d+%.*%d*);(%d+%.*%d*)" )
       local fCurrentTotalEnergy = tonumber(sCurrentTotalEnergy)
       if(sCommand == sHeatingOffCommand ) then -- No instant power consumption
         addCommand('UpdateDevice', iPowerMeterIdx .. '|0|0;' .. sCurrentTotalEnergy)
         return
       end

       fUpdatedEnergy = fCurrentTotalEnergy + fIntervalEnergy
       if(sCommand == sHeatingOnForCommand ) then -- System heating iTimes minutes
         addCommand('UpdateDevice', iPowerMeterIdx .. '|0|' .. fInstantPower .. ';' .. fUpdatedEnergy)
         addCommand('Variable:iResetDeviceMeterTime',tostring(iTime))
       end

       if(sCommand == sHeatingOnCommand ) then -- System in On/Off mode, heating happends until a stop command
       -- Total instant power update
         addCommand('UpdateDevice', iPowerMeterIdx .. '|0|' .. fInstantPower .. ';' .. fUpdatedEnergy)
       end
end


-- Init
commandArray = {}
iPowerMeterIdx = otherdevices_idx[sPowerMeterDeviceName]

-- Get time
local sCurrentTime = string.sub(os.date("%X"), 1, 5)
local sCurrentMinute = os.date('%M')

-- Check temperature sensors, choose the first one with response time < 10 min
-- set setpoint delta

for iTempSensorIndex = 1, #aTempSensorDevices do
      prDebug('Temp Sensor Device : '..aTempSensorDevices[iTempSensorIndex][1]..' - Delta to reference : ' .. aTempSensorDevices[iTempSensorIndex][2] )
      sTempSensorDeviceName = aTempSensorDevices[iTempSensorIndex][1]
      sTempSensorDeltaToReference = aTempSensorDevices[iTempSensorIndex][2]
  -- Last seen ?
      local sTempSensorLastSeen = string.sub(os.date("!%X", timeDifference(sTempSensorDeviceName)), 1, 5)
        -- if (sTempSensorLastSeen >= '00:10' and sTempSensorLastSeen < '00:12') then
        if (sTempSensorLastSeen >= '00:10') then
                  prDebug('Temp sensor missing')
          addCommand('SendEmail',sZoneName..' Heating Alert#Temperature sensor '..sTempSensorDeviceName..' has not updated for more than 10m.#'..sEmailContact)
        else -- Sensor has been seen, we use it
          sCurrentTemp,sCurrentHumidity = string.match(otherdevices_svalues[sTempSensorDeviceName],"(%d+%.*%d*);(%d+%.*%d*)")
          fCurrentTemp = tonumber(sCurrentTemp) + tonumber(sTempSensorDeltaToReference)
          prDebug ('Current measured temperature and delta applied : '..fCurrentTemp)
          break
        end
end
if ( fCurrentTemp == 1000) then return commandArray end -- No temp sensor, end of execution

-- Check for energy accounting timer to reset the meter
local iResetMeterDeviceTime = tonumber(uservariables['iResetDeviceMeterTime'])
if ( iResetMeterDeviceTime > 0 ) then -- There is an ongoing power consumption
    local iNewResetDeviceMeterTime = iResetMeterDeviceTime - 1
     if( iNewResetDeviceMeterTime == 0) then
  -- reset energy counters on time
         sCurrentPower,sCurrentTotalEnergy = string.match(otherdevices_svalues[sPowerMeterDeviceName], "(%d+%.*%d*);(%d+%.*%d*)" )
         addCommand('UpdateDevice', iPowerMeterIdx .. '|0|0;' .. sCurrentTotalEnergy)
     end
    addCommand('Variable:iResetDeviceMeterTime',tostring(iNewResetDeviceMeterTime))
end

-- Get current heating mode
sHeatingMode = otherdevices[sHeatingModeDeviceName]

-- Heating in Eco or Comfort, needs a calculation

if ( sHeatingMode == sHeatingModeComfortName
     or
     sHeatingMode == sHeatingModeEcoName
   )
   then
            -- Inits
            bPresence = false
            fSetPointTemp = 7

            -- Check for presence
            sPresenceDeviceStatus = otherdevices[sPresenceDeviceName]
            if ( sPresenceDeviceStatus == 'On' ) then
                   prDebug('Presence is on')
                   bPresence = true
             else
                   prDebug('Presence is off')
                   bPresence = false
            end

            -- Comfort mode, set heating setpoint to thermostat value, only applies if Presence is true.
            if( (sHeatingMode == sHeatingModeComfortName) and bPresence ) then
                fSetPointTemp = tonumber(otherdevices_svalues[sSetPointConfortDeviceName])
                prDebug ('Heating in *Comfort mode*, Setpoint : '..fSetPointTemp..' at '..sCurrentTime)
            end

            -- Eco mode, setpoint adjusted. Use this setpoint if no Presence.
            if( sHeatingMode == sHeatingModeEcoName or bPresence == false) then
               fSetPointTemp = tonumber(otherdevices_svalues[sSetPointEcoDeviceName])
                prDebug ('Heating in *Eco mode*, Setpoint : '..fSetPointTemp..' at '..sCurrentTime)
            end
                        -- Control mode

            local sControlMode = otherdevices[sHeatingControlModeDeviceName]
            prDebug('Heating Control mode : ' .. sControlMode)

            if( sControlMode == sHeatingControlModeHysteresisName ) then -- Control mode set to hysteresis

                             -- Decision to heat or not

                             -- Is it cold ?
                             if(fCurrentTemp <= (fSetPointTemp - fHysteresis) ) then
                                 prDebug ('Heating needed with delta : ' .. fCurrentTemp - fSetPointTemp)
                                 -- startHeating(aHeatingDeviceNames) --GH get rid of variable
                                 commandHeating(sHeatingOnCommand)
                            end

                             -- Is it warm ?
                            if(fCurrentTemp >= (fSetPointTemp + fHysteresis) ) then
                                 prDebug ('Stopping heating needed with delta : ' .. fCurrentTemp - fSetPointTemp)
                                 -- stoptHeating(aHeatingDeviceNames)
                                 commandHeating(sHeatingOffCommand)
                            end
             end

            if( sControlMode == sHeatingControlModePIDName ) then -- Control mode set to PID
                   -- We control the execution frequency
                   if( sCurrentMinute % iHeatingCycleDuration == 0) then -- We run the cycle

                                -- Set PID coefficients according to sample time
                                local fPIDTKi = fPIDKi * iHeatingCycleDuration * 60
                                local fPIDTKd = fPIDKd / (iHeatingCycleDuration * 60)
                                -- Current temperature error
                                 fTempError = fSetPointTemp - fCurrentTemp
                                 -- Compute new Integral
                                        -- If Setpoint changed, reset the integral action
                                         if( fSetPointTemp ~= tonumber(uservariables['fSetpointLast']) ) then
                                          fISum=0
                                         else
                                          -- Get the last Integral
                                          fISum = uservariables['fISumLast']
                                         end
                                 fISum = fISum + (fPIDTKi * fTempError)
                                 -- if(fISum > 255) then fISum = 255 end
                                 if(fISum > 255) then fISum = 255 end -- Integral limitation
                                 if(fISum < 0) then fISum = 0 end
                                 -- Derivative computation
                                 local fDeltaInput = fCurrentTemp - uservariables['fTempLastInput']  -- to number
                                 -- Sum up the PID output
                                 local fPIDOutput = fPIDKp * fTempError + fISum - fPIDTKd * fDeltaInput
                                 prDebug('PID Output : fPIDKp * fTempError = ' ..fPIDKp..' * '..fTempError..' = '..fPIDKp*fTempError..', fISum + '..fPIDTKi * fTempError..'  = '..fISum..', -fPIDTKd * fDeltaInput = '..fPIDTKd..' * '..fDeltaInput..' = -' .. fPIDTKd*fDeltaInput..', Output : '..fPIDOutput)
                                 if(fPIDOutput > 255) then fPIDOutput = 255 end
                                 if(fPIDOutput < 0) then fPIDOutput = 0 end
                                 -- Update user variables for next cycle
                                 addCommand('Variable:fTempLastInput',tostring(fCurrentTemp))
                                 addCommand('Variable:fISumLast',tostring(fISum))
                                 addCommand('Variable:fSetpointLast',tostring(fSetPointTemp))
                                 
                                  -- Heating cycle duration calculation
                                 if( fPIDOutput > 0 ) then -- heat
                                    fCycleDuration = round(fPIDOutput * iHeatingCycleDuration / 255,0)
                                    if( fCycleDuration == 0 ) then fCycleDuration = 1 end -- Heating is needed, let's go for at least 1 minute
                                    prDebug('Going to heat for : ' ..fCycleDuration..' minutes during the next '..round(iHeatingCycleDuration*60)..' seconds ('..iHeatingCycleDuration..' minutes) period.' )
                                    commandHeating(sHeatingOnForCommand,fCycleDuration)
                                  else -- Output null or negative, stop the heating
                                    prDebug('No heating needed')
                                    commandHeating(sHeatingOffCommand)
                                 end

            end -- Time period
       end -- PID mode
end

-- Heating forced on
if ( sHeatingMode == sHeatingModeForceOnName )
   then
            prDebug('Heaters forced On')
            commandHeating(sHeatingOnCommand)
end

-- Heating forced off
if ( sHeatingMode == sHeatingModeFrostFreeName )
   then
            prDebug('Heaters forced Off - Anti-frost mode')
            commandHeating(sHeatingOffCommand)
end

return commandArray

Benj29
Messages : 71
Inscription : 20 janv. 2017, 18:54

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par Benj29 »

Génial !!!!
Exactement ce que je cherchais !!!!

Je profite de ce topic mais je suis débutant !
et comme je suis en train de m'équiper et de réfléchir mon petit projet... je profite de ce topic si je peux !

A ce jour, j'ai un capteur de température/humidité dans chaque pièce de la maison et zone commune (en attendant la version stable, j'utilise des Xiaomi temp/humidité).

Mon cahier des charges :
- pouvoir tenir compte de la température des pièces :
* une chambre est au RDC, plein est et a le soleil de bon matin, j'aimerai anticiper avec une régulation adaptée (ras le bol des chauffages qui démarre pour avoir 20° et 1h après on a 22° dans la pièce),
* une autre chambre est plein ouest et voir moins le soleil,
* bref connaître les constantes de temps de chauffe de mes pièces, en tenir compte et adapter des modèles de chauffe,
* pouvoir gérer les consignes sur les pièces différentes (commun vers 20°, chambre vers 18.5/19°)
* piloter à distance of course !
* le top serait de tenir compte de la météo...

A ce stade, j'ai acquis 3 zwave qubino avec gestion du fil pilote : éco, confort, confort -1, confort -2, off et hors gel.
J'ai câblé 3 zones à la maison car à ce jour, j'ai un transmetteur Siemens 3 zones qui pilote mes chauffages.
Mais je veux changer tout ça...

Actuellement :
- zone commune : salle à manger/salon et entrées (4 radiateurs à inertie sèche)
- chambres : 2 chambres, 1 dressing/bureau 3 radiateurs à inertie fluide)
- salle d'eau/bains/chambre ami : 2 fluides serviette, 1 fluide.

En me basant sur de la lecture web :
http://www.maison-et-domotique.com/5010 ... o-zmnhja2/
https://www.domotique-fibaro.fr/topic/1 ... t-de-zone/

L'excellent topic PID mais chaudière...
viewtopic.php?f=17&t=318

Ceux là sont la base dans mon cas :
http://www.domotique-info.fr/2014/05/domoticz/
https://www.latelierdugeek.fr/2014/01/2 ... lectrique/

On aurait pu pousser dans le cas des chacon/zwave avec 2 diodes pour avoir 3 modes : On, Off, confort, eco.
http://www.maison-et-domotique.com/9397 ... radiateur/

Mais je vais rester simple dans le cas de la salle d'eau/bain : on/off.

A priori, la zone 3 (salle d'eau / chambre ami), j'envisage de découper.

- zone commune : un zwave qubino (j'ai déjà porté tous les fils pilote entre eux pour avoir les 3 radiateurs SAM, salon et commun),
- chambres : un zwave qubino (idem toutes les chambres sont pilotées),
- chambre d'ami : un zwave qubino (tout seul donc)
- salle d'eau : un chacon + diode,
- salle de bains : un chacon + diode.

Du coup à ce jour, chaque radiateur se coupe et se gère sur sa température de consigne (18.5 pour les chambres, 19 pour le salon) mais j'aimerai aller plus loin en tenant compte de la température/humidité de la pièce.

Avez-vous des idées, des expériences, des conseils à me donner ?
greg
Messages : 6
Inscription : 17 déc. 2016, 22:37

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par greg »

Hello Benj29,

Merci pour ton sympathique commentaire :-) Je trouve ton projet ambitieux et c'est formidable !
Une fois que tu auras réalisée la partie physique (relais), je pense que tu pourras te consacrer à la partie logicielle, et la faire évoluer petit à petit.

Si tu arrives à une solution où la météo à N heures est prise en compte, ce sera très intéressant ! Tiens nous au courant ;-)

Greg
Benj29
Messages : 71
Inscription : 20 janv. 2017, 18:54

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par Benj29 »

Je vais déjà tenter de mettre en place :

- les interrupteurs chacon/zwave pour chaque zone,
- faire fonctionner tout cela avec ce que tu as proposé et le mettre à niveau.

Puis-je te demander de l'aide le cas échéant ?

Merci !
greg
Messages : 6
Inscription : 17 déc. 2016, 22:37

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par greg »

Oui, je ferais mon possible pour supporter ce script. Dans quel environnement se situe ton habitation ? Finistère ?
Benj29
Messages : 71
Inscription : 20 janv. 2017, 18:54

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par Benj29 »

greg a écrit :Oui, je ferais mon possible pour supporter ce script. Dans quel environnement se situe ton habitation ? Finistère ?
Non, dans les Alpes Maritimes.
Installation sur RPI, qui va migrer sur mon syno à terme.
Chauffages à inertie fluide et sèche.
LudoLooping
Messages : 1
Inscription : 22 mars 2017, 11:15

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par LudoLooping »

Bonjour à tous,

impressionnant ton script greg ! Je suis tout nouveau en domotique et je mets en place progressivement mon installation Domoticz sur base d'une raspberry 3.
je dispose actuellement de 2 sondes Oregon pour la température et l'hygrométrie ainsi que d'un RFXtrx433E pour les écouter.
A venir rapidement, un OWL pour les relevés électriques et quelques prises intelligentes.

Mes années de programmation sont très loin derrière moi aussi je souffre à me remettre dans le bain et les différentes réactions ne seront pas superflues.

Pour planter le décors, je suis Belge. J'habite la région de Tournai et je loue un appartement (donc hors de question de faire des trous ou refaire quoi que ce soit). L'appartement se compose d'un coin cuisine donnant sur la salle à manger et le salon, une salle de bain et deux chambres.

Actuellement, une sonde Oregon se trouve dehors et l'autre dans le coin salon. La chaudière est au gaz (donc radiateurs à eau) et également communautaire. Je ne dispose de ce fait pas d'un accès à cette dernière, juste mon thermostat (honeywell cm 707) branché avec deux fils sur le circuit de commande.

Ton script est-il adaptable pour un chauffage centrale ? J'imagine d'ici la domotisation à faire pour contrôler mes radiateurs (1 au salon, 1 dans la salle à manger, 1 dans la salle de bain, 1 dans le chambre 1 et 1 dans la chambre 2) et le remplacement du thermsotat (vanne thermostatique zwave dont l'achat est prévu et relais contact sec sans doute pour le déclenchement de la chaudière)

Ce que j'envisage est de pouvoir adapter ton script sur plusieurs mode de fonctionnement (eco/confort/confort plus/Force/hors-gel/Off) et également un cycle selon l'heure de la journée (eco/confort/confort plus).

Je tente de faire fonctionner virtuellement ton script sous Domoticz mais je souffre.

Les différentes zones sont bien définies
Le thermostat sélecteur virtuel avec mes différents modes nommé [Thermostat Mode]
Mon script de présence basé sur l'ip de mon smartphone ainsi que celui de madame est présent et fonctionne à merveil nommé [Presence]


Là où je suis noyé c'est pour adapter ta partie radiateur électrique à mon installation chauffage central. je ne sais par où commencer.

Saurais-tu me donner des indices ?

Merci d'avance,
greg
Messages : 6
Inscription : 17 déc. 2016, 22:37

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par greg »

LudoLooping a écrit :...
Actuellement, une sonde Oregon se trouve dehors et l'autre dans le coin salon. La chaudière est au gaz (donc radiateurs à eau) et également communautaire. Je ne dispose de ce fait pas d'un accès à cette dernière, juste mon thermostat (honeywell cm 707) branché avec deux fils sur le circuit de commande.
J'ai l'impression qu'il faudrait que tu regardes comment est câblé/paramétré le thermostat Honeywell pour comprendre
le fonctionnement du chauffage collectif et sa distribution sur le chauffage individuel.
Apparement, le thermostat propose une régulation PI ( https://products.ecc.emea.honeywell.com ... 3r0206.pdf ),
ce qui est déjà excellent..

Le script est pour le moment en mode PWM, mais facilement adaptable au mode d'ailleurs plus adapté à la régul PID de pourcentage de puissance.
Au lieu de calculer un temps de chauffe, on peut ajouter une fonction pour la commande d'ouverture de vannes ou peut être imaginer
de se substituer au CM707.

Greg
lmet
Messages : 252
Inscription : 30 juin 2017, 18:16
Localisation : Val d'Oise
Contact :

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par lmet »

Bonjour @greg

Heureusement que tu débutes ;) Quel script!
J'envisage de l'implémenter pour cet hiver et vu mon niveau je m'y prends en juillet.
Si je puis me permettre voici quelques idées/suggestions :
Au niveau du code dans la partie déclaration :

Code : Tout sélectionner

-- Heaters
-- Domoticz Device Name, power in Watts, On command, Off command.
local aHeatingDevices = {
                             { 'Hors-Gel Radiateur Salon Est', 1500 , 'Off AFTER 3', 'On' } ,

                             { 'Hors-Gel Radiateur Salon Sud', 1500 , 'Off AFTER 3', 'On' }

                        }
Si l'on n'y prête pas attention en tous cas pour moi on éteint au-lieu d'allumer et AFTER 3 est écrit en dur.
J'obtiens assez souvent un message : Warning!, lua script Gère_Chauff has been running for more than 10 seconds
Le switch "Presence" ne semble pas forcer le passage en mode "Eco" ou "Off"
J'envisage de n'utiliser que le mode PID pour simplifier un peu le script : Est-ce une erreur ?

Parmi les améliorations, j'utilisais un plugin sur une autre box qui offrait deux possibilités :
° Des inhibits sensors (Détecteurs de porte, fenêtre) coupant le chauffage pendant le temps d'ouverture.
° Un capteur de température extérieur venant en pondération dans le calcul du temps de chauffe.

Un grand merci à toi pour cette contribution.
lmet
Domoticz : V4.10717
Zigate : V4.11230 plugin:4.5.4 firmware:031a
Mon petit blog domotique
Djodo
Messages : 86
Inscription : 23 févr. 2016, 12:32

Re: Script chauffage Hysteresis et PID, multi radiateurs et thermomètres

Message par Djodo »

Moi aussi j'ai eu les mêmes problèmes que Imet.

Du coup j'ai interverti le "On" et "Off" dans le script comme le fait remarquer Imet.

Et pour le passage automatique Confort<=>Eco en fonction du switch présence, j'ai rajouté deux lignes comme ceci :

Code : Tout sélectionner

            
            -- Check for presence
            sPresenceDeviceStatus = otherdevices[sPresenceDeviceName]
            if ( sPresenceDeviceStatus == 'On' ) then
                   prDebug('Presence ON')
                   bPresence = true
                   commandArray ['Mode Chauffage'] = 'Set Level: 20' --Passage en mode Confort
             else
                   prDebug('Presence OFF')
                   bPresence = false
                   commandArray ['Mode Chauffage'] = 'Set Level: 10' --Passage en mode Eco
            end
Alors je redonne pas le script en entier parce que je ne suis pas sûr de mon code, si des pros le valide, on pourra alors mettre le script à jour !

Et merci greg ! :)
Répondre