New Automation: PID Controller

I’m facing a similar issue with my heating controls. It does seem that the I-part will get stuck at the lower bound for some reason. Here’s my config and I’m running the latest .jar file posted here in this thread.

configuration: {}
triggers:
  - id: 399da826-0190-4855-b2a8-8d3e36551c2a
    label: PID Controller Trigger
    configuration:
      input: BedroomTH_temperature
      setpoint: BedroomHeating_temperature_setpoint
      kp: 115
      ki: 0.2
      kd: 0
      kdTimeConstant: 1
      loopTime: 60000
      integralMinValue: -50
      integralMaxValue: 100
      iInspector: BedroomHeating_pid_i
      pInspector: BedroomHeating_pid_p
      eInspector: BedroomHeating_error
    type: pidcontroller.trigger
conditions: []
actions:
  - inputs: {}
    id: "1"
    configuration:
      itemName: BedroomHeating_dutycycle
    type: core.ItemCommandAction

Here’s the graph of temperature, setpoint, controller output and inspector items. I have done 2 manual resets of the automation during this time - these are the points where the I-part is reset to zero and the graph starts moving again.

EDIT: I’ve taken a look at the code changes included in that last release and I think the problem is here:

The internal integralResult value is unbounded. I was expecting that it would be limited by the min/max values I set, so whenever the temperature crosses into the other side of the setpoint, the integral value would immediately change.

EDIT2: I prepared a pull request in attempt to fix this.

@lnagel Thanks for the fix! I updated the JAR in the first post of this thread.

@fwolter Thanks for your response and merge!

I have some more work in progress that I can share. Since I’m running floor heating, then losing state for the integrator component is rather painful, it will take a day for the system to stabilize after each rule change or openhab restart. So I implemeted recovery for the PID controller’s internal state from the inspector items on startup. This can be combined with restoreOnStartup strategy in the persistence module to create a system where you can restart openhab or edit rule parameters without upsetting control.

Feel free to take a look at my dev tree here:

While working on this code I start to realize that it would benefit from some cleanup among the helper functions defined in these classes and such smaller things. Since you’re the package maintainer for this addon, could you maybe suggest how should the workflow be for this?

Also, how do we get this code upstream for the next release?

Great to see progress on the PID controller! Your changes look good so far. Go ahead and do the cleanup. When you’re finished, you can file a PR against the upstream repo. I will file the I limiting PR tomorrow, after the milestone release is out. After it has been merged, you can rebase your changes onto the upstream/main branch and file your PR. I will review it and merge it upstream when everything is alright.

Alright, thanks! This sounds like a plan.

@rgabo74 you can do it using openhab-js (part od jss plugin) but PID controller is available only in master (not relased branch). You can do install npm i openhab in /etc/openhab/automation ten git clone the openhab-js repo and move the files manually

PID controller is not reseting on every RESET command. Don’t know exactly how to log/reproduce this but i have a suggestion to change PID code to reset the controller on ReceivedCommand not ItemChanged. It will help to resolve the issue which i am describing below. What do you think @fwolter

1/ i know one situation when this could happen : PID controller rule is temporarly disabled and is receiving RESET command.
2/ when you enable the rule again RESET string is sitting in the item and sending it again will not reset the controller.

but i think it’s not the case i am facing here

2022-11-08 22:56:06.372 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC3_PID_commandItem' received command RESET
2022-11-08 22:56:06.377 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from NULL to RESET
2022-11-08 22:56:06.383 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from RESET to NULL
2022-11-08 22:56:06.548 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC3_PID_commandItem' received command RESET
2022-11-08 22:56:06.556 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from NULL to RESET
2022-11-08 22:56:06.563 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from RESET to NULL
2022-11-08 22:56:06.655 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC3_PID_commandItem' received command RESET
2022-11-08 22:56:06.663 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from NULL to RESET
2022-11-08 22:56:06.670 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from RESET to NULL
2022-11-08 22:56:07.708 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC3_PID_commandItem' received command RESET
2022-11-08 22:56:07.723 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC3_PID_commandItem' received command RESET
2022-11-08 22:56:07.734 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from NULL to RESET
2022-11-08 22:56:07.741 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from RESET to NULL
2022-11-08 22:56:07.942 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC3_PID_commandItem' received command RESET
2022-11-08 22:56:07.949 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from NULL to RESET
2022-11-08 22:56:07.956 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC3_PID_commandItem' changed from RESET to NULL
2022-11-09 08:20:11.505 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC5_PID_commandItem' received command RESET
2022-11-09 08:22:13.636 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC5_PID_commandItem' received command RESET
2022-11-09 08:26:44.954 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC5_PID_commandItem' received command RESET

as you can see AC5 is not responding to RESET, .state of the item is keeped “RESET” i need to send empty string ‘’ comand and then it works again:


2022-11-09 08:28:40.998 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC5_PID_commandItem' received command

manually sended “”

2022-11-09 08:28:41.006 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC5_PID_commandItem' changed from RESET to

now it’s working again from rules

2022-11-09 08:28:56.770 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'RadiatorAC5_PID_commandItem' received command RESET
2022-11-09 08:28:56.790 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC5_PID_commandItem' changed from  to RESET
2022-11-09 08:28:56.795 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'RadiatorAC5_PID_commandItem' changed from RESET to NULL

Hi,
just finished my heating / cooling system based on PID and PWM automation. You can easily use it also to cooling system.

1/ Heat pump supports only Heating OR Cooling so there is only one switch to control all rooms/thermostats

2/ logic is based on PID rule (i am using js-scripting to write my rules, but you can easily adjust it. I am manipulating the dutycycle result based on a switch item which is ON or OFF (or doesn’t exist). If it’s ON - cooling, the dutycycle is negative

rules.JSRule({
    name: `Termostat ${i} PID controller`,
    id: `Termostat_${i}_PID_controller`,
    tags: [`Room${i}`, `_DYNAMIC_`],
    overwrite: `true`,
    description: `PID automation`,
    triggers: [triggers.PIDTrigger(`TempSensor${i}_CurrentTemp`,`RadiatorAC${i}_TargetTemperature`,items.getItem(`RadiatorAC${i}_PID_kp`).state,items.getItem(`RadiatorAC${i}_PID_ki`).state,items.getItem(`RadiatorAC${i}_PID_kd`).state,items.getItem(`RadiatorAC${i}_PID_kdTimeConstant`).state,items.getItem(`RadiatorAC${i}_PID_loopTime`).state,`RadiatorAC${i}_PID_commandItem`,null,null,`RadiatorAC${i}_PID_pInspector`,`RadiatorAC${i}_PID_iInspector`,`RadiatorAC${1}_PID_dInspector`,`RadiatorAC${i}_PID_eInspector`)],
    execute: (event) => {
      var command = parseInt(event.receivedCommand)
      try {
        
       
            if (items.getItem(`Radiators_Mode`).state == "ON") { 
              command = (command * -1);
                     };
            
       
      } catch {}
     
      if (command <= 0 ) { command = 0} else { if (command >=100 ) {command = 100}}
      items.getItem(`RadiatorAC${i}_PWM_dutycycleItem`).sendCommand(command);
    }
  });

waiting for your feedback :slight_smile:

There’s an issue with the RESET command if the state is already in RESET when the rule is enabled. Then, there will be no ItemStateChangedEvent when the RESET command is sent and we’ll see the behavior you describe. You could work around it by sending NULL when enabling the rule or do it periodically.

Confgratulations on managing to implement a cooling system, too, looks good!

thank you!
will it be fixed to accepted reset command even if it state is already RESET ?

Not by me. I’m not a big fan of the RESET command.

I’m sure I must be missing something, but I can’t find the CommandItem in the configuration which can be used for the RESET of the I (and D) part? I am running the latest official OpenHAB release 3.3.

Here is the configuration that is produced when I add a rule with the PID-Controller template.

configuration: {}
triggers:
  - id: "1"
    configuration:
      input: BathRoom_PIDController_Input_Temperature
      setpoint: BathRoom_PIDController_Input_SetPoint
      iInspector: BathRoom_PIDController_Output_IInspector
      kp: 20
      eInspector: BathRoom_PIDController_Output_ErrorInspector
      pInspector: BathRoom_PIDController_Output_PInspector
      kd: 0
      kdTimeConstant: 0
      dInspector: BathRoom_PIDController_Output_DInspector
      ki: 0.1
      loopTime: 60000
    type: pidcontroller.trigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      itemName: BathRoom_PIDController_Output
    type: core.ItemCommandAction

It seems to be missing in the trigger module definition in the code. Did you try to add it manually to your configuration?

configuration:
    commandItem: MyResetItem
...

Manual addition seems to work. Thanks!

Hi,
actually I’m trying to setup the PID Controller the fist time.
Setup: Eurotronic Spirit Zwave Heating Regulator, Aquara Temperature Sensor.

But every time if I try to enable the rule, I received errors:

023-01-01 19:46:41.369 [WARN ] [.handler.PIDControllerTriggerHandler] - Setpoint item: TestPidSetpoint: Not a number: UnDefType: NULL

Here is my setup

That’s the pid config

Thats the Eurotronic Spirit with the setpoint

So could someone give me a hint what this error message means?
The Setpoint from the Zwave is a Number…

Actually it is working, or it seems to.
But I can not see any output

2023-01-01 23:18:36.695 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestPid_Setpoint' changed from 20 °C to 22 °C

2023-01-01 23:18:36.706 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestPid_P' changed from 18.599999999999994 to 38.599999999999994

2023-01-01 23:18:36.707 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestPid_I' changed from 2.604102399999999 to 2.962670666666666

2023-01-01 23:18:36.711 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestPid_D' changed from 0.00000007086713177090044 to 0.0014856740146629624

2023-01-01 23:18:36.713 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestPid_E' changed from 1.8599999999999994 to 3.8599999999999994

2023-01-01 23:18:40.966 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestPid_I' changed from 2.962670666666666 to 2.990115266666666

2023-01-01 23:18:40.969 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestPid_D' changed from 0.0014856740146629624 to 0.0014855683869956279

This is the setting:

and this the setting item ( Dimmer item of the eurotronic )

Don’t have time now to go thru setup you have but I would recommend to go and check my how to ‘tutorial’.

I saw this doc from you.
but in the first quick reading my thought was that it is not for my use case, because I want to play a little bit with the pid controller in general.
I think that the pid controller can be used out of the box.
so define input item and output item and it works.

nearly it is so, but not for the output.
but thanks again for the hint with you documentation.
I will read it with more concentration.
maybe I will find the solution why I see no output in my side.

I just scrolled thru and I think I know what you are trying to do. I can’t remember it now but I think it wasn’t that simple because of underlying metric casting.

Spirit needed an Integer value 0 - 100 while PID provides Float as output.

When I was setting it up it wasn’t also possible to limit output to range so I was getting numbers like -356,28… What also wasn’t proper value for dimmer.

I think this is why I ended up with virtual items.
But tbh I can’t recall now.

If I see correctly, you linked the setpoint Item of the PID controller to the setpoint Channel of the device. The PID controller’s setpoint item needs to be an independent Item, not linked to anything, otherwise the system can behave weird.