The Item config parameters were set to read-only, which is obviously wrong. Seems like the UI didn’t honor this flag until now. However, I set the read-only flag to false and updated the link in the original post.
@fwolter After few tries with cleaning up the cache, I finally got it working but I see that my Eurotronic Spirit radiator is not responding to the proposed values at all. I’m not sure what I did wrongly.
When set up dimmer manually (50%):
2021-01-24 13:34:02.548 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'SypialniaGrzejnikNode13_Dimmer' received command 50.0
2021-01-24 13:34:02.567 [INFO ] [penhab.event.ItemStatePredictedEvent] - Item 'SypialniaGrzejnikNode13_Dimmer' predicted to become 50.0
2021-01-24 13:34:02.588 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'SypialniaGrzejnikNode13_Dimmer' changed from 35 to 50.0
But when I try to set it using rules I start to get Errors/Exceptions
2021-01-24 13:34:28.927 [INFO ] [openhab.event.ItemCommandEvent ] - Item 'SypialniaGrzejnikNode13_Dimmer' received command 0.6570000000000004
2021-01-24 13:34:59.547 [WARN ] [l.handler.PIDControllerActionHandler] - Command was not posted because either the configuration was not correct or a service was missing: ItemName: SypialniaGrzejnikNode13_Dimmer, Command: null, eventPublisher: org.openhab.core.internal.events.OSGiEventPublisher@37f93b, ItemRegistry: org.openhab.core.internal.items.ItemRegistryImpl@10f252e
Additionally I see exception:
2021-01-24 13:51:26.771 [WARN ] [ab.core.internal.events.EventHandler] - Dispatching/filtering event for subscriber 'org.openhab.core.events.EventSubscriber' failed: No value present
java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:148) ~[?:?]
at org.openhab.automation.pidcontroller.internal.handler.PIDControllerTriggerHandler.receive(PIDControllerTriggerHandler.java:208) ~[?:?]
at org.openhab.core.internal.events.EventHandler.lambda$0(EventHandler.java:151) [bundleFile:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
at java.lang.Thread.run(Thread.java:834) [?:?
So now the question is how debug process should look like? Where to start analysis?
My rule:
I think I’m missing an command compared to a simple rule to set up the dimmer:
PS. I guess the feature request would be to get INT instead of Float as an output.
For sure I can do a virtual item and then round it on every update but I guess having an option to receive an integer instead of float would be demanded by more items/channels.
rule "Kitchen TRV PID Control Handler"
when
Item CentralHeatingState changed to ON or
Item KitchenTrvPidValvePosition changed
then
if (CentralHeatingState.state == ON) {
var int positiveOnlyPidTargetTrvValvePosition = new BigDecimal((KitchenTrvPidValvePosition.state as Number).floatValue).setScale(1, RoundingMode.HALF_UP).intValue()
// cap valve positions to between 0 & 100
if (positiveOnlyPidTargetTrvValvePosition < 0) {
positiveOnlyPidTargetTrvValvePosition = 0
}
if (positiveOnlyPidTargetTrvValvePosition > 100) {
positiveOnlyPidTargetTrvValvePosition = 100
}
logInfo("Kitchen", "PID control: target TRV valve position is " + positiveOnlyPidTargetTrvValvePosition + "%")
var int currentTrvPidValvePosition = (KitchenTrvValvePosition.state as Number).intValue()
logInfo("Kitchen", "PID control: current TRV valve position is " + currentTrvPidValvePosition + "%")
if (positiveOnlyPidTargetTrvValvePosition != currentTrvPidValvePosition) {
if (positiveOnlyPidTargetTrvValvePosition == 0
|| positiveOnlyPidTargetTrvValvePosition >= 100
|| Math::abs(positiveOnlyPidTargetTrvValvePosition - currentTrvPidValvePosition) >= 1) {
logInfo("Kitchen", "PID control: setting TRV valve position to " + positiveOnlyPidTargetTrvValvePosition + "%")
KitchenTrvValvePosition.sendCommand(positiveOnlyPidTargetTrvValvePosition)
}
}
}
end
You also really need to RESET the PID when the Setpoint changes or when you start the heating (e.g. turn on the boiler) to clear any accumulated Integral.
rule "Kitchen TRV PID Setpoint Change Handler"
when
Item KitchenTrvPidSetpoint changed
then
// reset PID controller
logInfo("Kitchen", "Setpoint changed, resetting Kitchen TRV PID controller")
KitchenTrvPidCommandItem.sendCommand("RESET")
end
rule "Kitchen Central Heating On"
when
Item CentralHeatingState changed to ON
then
// reset PID controller
logInfo("Kitchen", "Resetting Kitchen TRV PID controller")
KitchenTrvPidCommandItem.sendCommand("RESET")
end
You’ll need these imports at the top of the Rule file for the rounding bit:
@Morgano thanks - I implemented 2 out of 8 valves using scratch in very similar manner - bit of try catch - need to move those to actual code later.
Finally I ended up with virtual items like dimmer / setPoint temperature / Temperature higher one extracted from two thermometers / and PID controller for resetting the stats.
How did you figure out the PID values? As of now I just placed random values to make it work
@fwolter even after update I’m still getting those WARN messages. Not sure from where it’s coming from.
2021-01-24 19:14:00.995 [WARN ] [ab.core.internal.events.EventHandler] - Dispatching/filtering event for subscriber 'org.openhab.core.events.EventSubscriber' failed: No value present
java.util.NoSuchElementException: No value present
at java.util.Optional.get(Optional.java:148) ~[?:?]
at org.openhab.automation.pidcontroller.internal.handler.PIDControllerTriggerHandler.receive(PIDControllerTriggerHandler.java:208) ~[?:?]
at org.openhab.core.internal.events.EventHandler.lambda$0(EventHandler.java:151) [bundleFile:?]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
at java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
at java.lang.Thread.run(Thread.java:834) [?:?]
You basically start with just the ‘P’ part then add the ‘I’. I believe the ‘D’ part is not normally used for heating systems as the response is slow anyway so it is not really required.
@fwolter you were right for some reason I had 2 versions running - cleared tmp/cache and old version is gone.
Now I need some help with tunning - I used the values that @Morgano used (kp=65, ki=0.1) but it seems that I’m always undershot the desired setpoint.
I used virtual devices.
Blue = desired setpoint
Violet = Virtual temp based on which it should work (Xiaomi Aquara)
Light blue = Spirit Thermostat
Orange = additional (Xiaomi Aquara) that I can move around the house
Green = Dimmer
It seems that dimmer is shut down before setpoint is reached.
As getting the results is quite slow based on your experience should leave kp=65 and increase ki 0.1 => 0.3 or maybe even more?
I’m not an expert in PID Tuning, but my understanding the ‘I’ component is there to compensate for steady state error. So if the temperature remains steady (not oscillating) but it is below the setpoint, then you could try to increase Ki a little. This should help pull the temperature up to the set point. It seems with the Ki component a little goes a long way as it accumulates over time.
Hi, thanks for this automation!!! I’m very interested on it.
I understand why when the set point changes the calculation is made, but why is done when the input item (meassure) changes too?
Untill now all the info I have readed only takes it on account when the calculation is made at the end of the cicle in order to obtain the output for the next.
In the orther hand, it would be great that all the options (kp, ki, …) where configurable by items as I have read in other comments.
Because that is the goal of a PID controller - to create a correction when the input e.g. room temperature does not match the desired value (e.g room temperature setpoint). It is a continual repeating process with a goal of creating a set of output changes (e.g radiator valve position) that cause the input to eventually match the setpoint and be held there.
The output calculation is repeated regularly to allow the system to reach the setpoint and to also to cope with any external changes e.g. if the temperature outside a house drops, the room temperature might drop due to the extra heat loss, so the PID controller may need to open the radiator valve slightly more to compensate, and to keep the room at the setpoint.
But this not causes the calculation been done at every change of the temperarute? For example, if the meassure resolution is 0.01 grades when the output is high the meassure item will be changing too fast and the calculation done with each change.
Untill now I have been doing my PID control with a flow implemented in node-red. The PID is been calculated at 10mins intervals in which the heater can be ON for a time based in the output. And OFF the rest of the cicle. If one of the parameters is changed the cicle is restarted. But the input is readed only at calculations.
@aitorforero
You could probably do something like only switch the heater on if the PID output is indicating at least, say, 2 minutes of heat are required for the cycle. You would ignore shorter activations. The error would increase and so would the output time on following cycles until the activation time becomes > 2 mins and the heater would be turned on.
Maybe what you are doing (PID control) is slightly unusual for an on/off style heater or not a good fit? Did you try a simpler ‘bang/bang’ temperature control with hysteresis?
@Morgano is right. You have number as an output of calculation. It’s “kind of” infinite number. In my case anything above 100 means that heater is still opened fully. Below 0 means that i need to push the dimmer to 0 - between I can adjust the dimmer. In your case you could wait till output is some number like 100 and the leave heating working until calculated value will drop below 100.
I read that Electric heaters are also controlled by PID but there is this param calculated how much time it should stay ON to reach desired temperature.
Stove for ceramics for example. But don’t know the implementation details.
My intention is to use a time-proportional PID control. Maybe I have missunderstud how often the cycle must be calculated.
Till now what I have been doing is reading the output and calculate de proportinal time of the new cycle when the switch must be ON. Then wait until whole cycle ends and I reacalculate it again.
What you are saying is that this calculation has to be done at evey change of temperature?
@aitorforero
No, the PID cycle time (loop time) is normally based on the characteristics of the system. If it is a ‘slow’ system, like a heating system then the adjustment time will be in the ‘minutes’ realm as control changes take a while to have any noticeable effects.
On the other hand, if you were controlling something like the flight stability of a drone (fast system), the PID cycle would be in the ‘milliseconds’ realm as control changes would take effect quicker, and are needed much more often.
“The loopTime should be max a tenth of the system response. E.g. the heating needs 10 min to heat up the room, the loop time should be max 1 min. Lower values won’t harm, but need more calculation resources”
It’s kind of a bad timing as the heating period is coming to an end on the northern hemisphere, but I released a PWM module to control valves more easily in conjunction with a PID controller.