Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PID PID_LOCAL_SENSOR_NAME doesn't seem to update Pv #22094

Closed
13 of 14 tasks
spacelama opened this issue Sep 5, 2024 · 7 comments · Fixed by #22162
Closed
13 of 14 tasks

PID PID_LOCAL_SENSOR_NAME doesn't seem to update Pv #22094

spacelama opened this issue Sep 5, 2024 · 7 comments · Fixed by #22162

Comments

@spacelama
Copy link
Contributor

spacelama commented Sep 5, 2024

PROBLEM DESCRIPTION

Documentation is lacking for how to use PID, other than https://tasmota.github.io/docs/PID-Control/, so it's not clear I am using it correctly, but setting
USE_PID
PID_USE_LOCAL_SENSOR
PID_LOCAL_SENSOR_NAME "ANALOG"
PID_LOCAL_SENSOR_TYPE "Temperature1"

results in Pv not actually updating in PIDShowSensor every second when called by PIDEverySecond

REQUESTED INFORMATION

Make sure your have performed every step and checked the applicable boxes before submitting your issue. Thank you!

  • Read the Contributing Guide and Policy and the Code of Conduct
  • Searched the problem in issues
  • Searched the problem in discussions
  • Searched the problem in the docs
  • Searched the problem in the chat
  • Device used (e.g., Sonoff Basic): LOLIN32 DevKit
  • Tasmota binary firmware version number used: 14.2.0
    • Pre-compiled
    • Self-compiled
  • Flashing tools used: platformio
  • Provide the output of command: Backlog Template; Module; GPIO 255:
14:26:24.250 MQT: stat/fridge1/RESULT = {"NAME":"ESP32-DevKit","GPIO":[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
14:26:24.483 MQT: stat/fridge1/RESULT = {"Module":{"1":"ESP32-DevKit"}}
14:26:24.740 MQT: stat/fridge1/RESULT = {"GPIO0":{"0":"None"},"GPIO1":{"0":"None"},"GPIO2":{"0":"None"},"GPIO3":{"0":"None"},"GPIO4":{"0":"None"},"GPIO5":{"0":"None"},"GPIO6":{"0":"None"},"GPIO7":{"0":"None"},"GPIO8":{"0":"None"},"GPIO9":{"0":"None"},"GPIO10":{"0":"None"},"GPIO11":{"0":"None"},"GPIO12":{"0":"None"},"GPIO13":{"0":"None"},"GPIO14":{"0":"None"},"GPIO15":{"0":"None"},"GPIO16":{"0":"None"},"GPIO17":{"0":"None"},"GPIO18":{"0":"None"},"GPIO19":{"0":"None"},"GPIO20":{"0":"None"},"GPIO21":{"0":"None"},"GPIO22":{"0":"None"},"GPIO23":{"0":"None"},"GPIO24":{"0":"None"},"GPIO25":{"0":"None"},"GPIO26":{"0":"None"},"GPIO27":{"416":"PWM1"},"GPIO32":{"0":"None"},"GPIO33":{"0":"None"},"GPIO34":{"0":"None"},"GPIO35":{"4736":"ADC Temp1"},"GPIO36":{"0":"None"},"GPIO37":{"0":"None"},"GPIO38":{"0":"None"},"GPIO39":{"0":"None"}}
  Configuration output here:

  • If using rules, provide the output of this command: Backlog Rule1; Rule2; Rule3:
  Rules output here:

  • Provide the output of this command: Status 0:
  STATUS 0 output here:
{"Status":{"Module":1,"DeviceName":"Tasmota","FriendlyName":["Tasmota"],"Topic":"fridge1","ButtonTopic":"0","Power":"0","PowerLock":"0","PowerOnState":3,"LedState":1,"LedMask":"FFFF","SaveData":1,"SaveState":1,"SwitchTopic":"0","SwitchMode":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"ButtonRetain":0,"SwitchRetain":0,"SensorRetain":0,"PowerRetain":0,"InfoRetain":0,"StateRetain":0,"StatusRetain":0},"StatusPRM":{"Baudrate":115200,"SerialConfig":"8N1","GroupTopic":"tasmotas","OtaUrl":"http://ota.tasmota.com/tasmota32/release/tasmota32.bin","RestartReason":"Vbat power on reset","Uptime":"0T00:19:30","StartupUTC":"2024-09-05T13:08:47","Sleep":50,"CfgHolder":4617,"BootCount":36,"BCResetTime":"2024-09-04T13:47:14","SaveCount":97},"StatusFWR":{"Version":"14.2.0(tasmota32)","BuildDateTime":"2024-09-05T23:07:36","Core":"3_0_4","SDK":"5.1.4.240801","CpuFrequency":160,"Hardware":"ESP32-D0WDQ6 v1.0","CR":"464/699"},"StatusLOG":{"SerialLog":2,"WebLog":2,"MqttLog":0,"SysLog":0,"LogHost":"192.168.1.204","LogPort":514,"SSId":["Asio2.4",""],"TelePeriod":300,"Resolution":"958780C0","SetOption":["00008009","2805C80001000600003C5A0A192800000000","00000080","00006000","00004000","00000000"]},"StatusMEM":{"ProgramSize":2005,"Free":874,"Heap":142,"StackLowMark":3,"PsrMax":0,"PsrFree":0,"ProgramFlashSize":4096,"FlashSize":4096,"FlashChipId":"16405E","FlashFrequency":40,"FlashMode":"DIO","Features":["0809","9F9AD7DF","0015A001","B7F7BFCF","05DA9BC4","E0360DC7","480840D2","20E00000","D4BC482D","810A80B1","00000014"],"Drivers":"1,2,!3,4,!5,7,!8,9,10,11,12,!14,!16,!17,!20,!21,!24,26,!27,29,!34,!35,38,48,49,50,52,!59,!60,62,!63,!66,!67,!68,!73,82,!86,!87,!88,!121","Sensors":"1,2,3,5,6,7,8,9,10,11,12,13,14,15,17,18,19,20,21,22,26,31,34,37,39,40,42,43,45,51,52,55,56,58,59,64,66,67,74,85,92,95,98,103,105,109,127","I2CDriver":"7,8,9,10,11,12,13,14,15,17,18,20,24,29,31,36,41,42,44,46,48,58,62,65,69,76,77,82"},"StatusNET":{"Hostname":"fridge1-0368","IPAddress":"192.168.1.156","Gateway":"192.168.1.254","Subnetmask":"255.255.255.0","DNSServer1":"192.168.1.254","DNSServer2":"192.168.1.252","Mac":"24:0A:C4:59:E1:70","IP6Global":"","IP6Local":"fe80::260a:c4ff:fe59:e170%st1","Ethernet":{"Hostname":"","IPAddress":"0.0.0.0","Gateway":"0.0.0.0","Subnetmask":"0.0.0.0","DNSServer1":"192.168.1.254","DNSServer2":"192.168.1.252","Mac":"00:00:00:00:00:00","IP6Global":"","IP6Local":""},"Webserver":2,"HTTP_API":1,"WifiConfig":4,"WifiPower":16.0},"StatusMQT":{"MqttHost":"192.168.1.3","MqttPort":1883,"MqttClientMask":"fridge1","MqttClient":"fridge1","MqttUser":"DVES_USER","MqttCount":1,"MAX_PACKET_SIZE":1200,"KEEPALIVE":30,"SOCKET_TIMEOUT":4},"StatusTIM":{"UTC":"2024-09-05T13:28:17Z","Local":"2024-09-05T14:28:17","StartDST":"2024-03-31T02:00:00","EndDST":"2024-10-27T03:00:00","Timezone":"+01:00","Sunrise":"06:13","Sunset":"19:23"},"StatusSNS":{"Time":"2024-09-05T14:28:17","ANALOG":{"Temperature1":49.69},"PID":{"PidPv":53.02,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":300,"PidInterval":199,"PidUpdateSecs":0,"PidSensorLost":0,"PidPower":0.00},"TempUnit":"C"},"StatusSTS":{"Time":"2024-09-05T14:28:17","Uptime":"0T00:19:30","UptimeSec":1170,"Heap":140,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":21,"MqttCount":1,"Berry":{"HeapUsed":3,"Objects":45},"POWER":"OFF","Dimmer":14,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"Asio2.4","BSSId":"58:11:22:87:72:28","Channel":1,"Mode":"HT20","RSSI":78,"Signal":-61,"LinkCount":1,"Downtime":"0T00:00:05"}}}

  • Set weblog to 4 and then, when you experience your issue, provide the output of the Console log:
  Console output here:

14:49:50.771 MQT: stat/fridge1/STATUS8 = {"StatusSNS":{"Time":"2024-09-05T14:49:50","ANALOG":{"Temperature1":54.57},"PID":{"PidPv":54.75,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":293,"PidUpdateSecs":0,"PidSensorLost":1,"PidPower":0.00},"TempUnit":"C"}}
14:49:51.324 PID: no root
14:49:51.996 PID: no root
14:49:52.001 MQT: stat/fridge1/STATUS8 = {"StatusSNS":{"Time":"2024-09-05T14:49:51","ANALOG":{"Temperature1":54.23},"PID":{"PidPv":54.75,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":294,"PidUpdateSecs":0,"PidSensorLost":1,"PidPower":0.00},"TempUnit":"C"}}
14:49:52.266 PID: no root
14:49:53.225 PID: no root
14:49:53.230 MQT: stat/fridge1/STATUS8 = {"StatusSNS":{"Time":"2024-09-05T14:49:53","ANALOG":{"Temperature1":54.05},"PID":{"PidPv":54.75,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":295,"PidUpdateSecs":0,"PidSensorLost":1,"PidPower":0.00},"TempUnit":"C"}}
14:49:53.290 PID: no root
14:49:57.289 PID: no root
14:49:57.290 PID: Local temperature sensor missing for longer than PID_MAX_INTERVAL
14:49:57.947 PID: no root
14:49:57.948 PID: Local temperature sensor missing for longer than PID_MAX_INTERVAL
14:49:57.953 MQT: stat/fridge1/STATUS8 = {"StatusSNS":{"Time":"2024-09-05T14:49:57","ANALOG":{"Temperature1":49.35},"PID":{"PidPv":54.75,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":300,"PidUpdateSecs":0,"PidSensorLost":1,"PidPower":0.00},"TempUnit":"C"}}
14:49:58.277 MQT: tele/fridge1/STATE = {"Time":"2024-09-05T14:49:58","Uptime":"0T00:41:11","UptimeSec":2471,"Heap":143,"SleepMode":"Dynamic","Sleep":50,"LoadAvg":22,"MqttCount":1,"Berry":{"HeapUsed":3,"Objects":42},"POWER":"OFF","Dimmer":14,"Fade":"OFF","Speed":1,"LedTable":"ON","Wifi":{"AP":1,"SSId":"Asio2.4","BSSId":"58:11:22:87:72:28","Channel":1,"Mode":"HT20","RSSI":78,"Signal":-61,"LinkCount":1,"Downtime":"0T00:00:05"}}
14:49:58.316 PID: Got isNum: 	ܠ
14:49:58.320 MQT: tele/fridge1/SENSOR = {"Time":"2024-09-05T14:49:58","ANALOG":{"Temperature1":49.35},"PID":{"PidPv":54.75,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":300,"PidUpdateSecs":0,"PidSensorLost":1,"PidPower":0.00},"TempUnit":"C"}
14:49:59.175 PID: no root
14:49:59.180 MQT: stat/fridge1/STATUS8 = {"StatusSNS":{"Time":"2024-09-05T14:49:59","ANALOG":{"Temperature1":52.14},"PID":{"PidPv":49.35,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":1,"PidUpdateSecs":0,"PidSensorLost":0,"PidPower":0.00},"TempUnit":"C"}}
14:50:00.419 PID: no root
14:50:00.423 MQT: stat/fridge1/STATUS8 = {"StatusSNS":{"Time":"2024-09-05T14:50:00","ANALOG":{"Temperature1":56.28},"PID":{"PidPv":49.35,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":3,"PidUpdateSecs":0,"PidSensorLost":0,"PidPower":0.00},"TempUnit":"C"}}
14:50:01.261 PID: no root
14:50:01.635 PID: no root
14:50:01.640 MQT: stat/fridge1/STATUS8 = {"StatusSNS":{"Time":"2024-09-05T14:50:01","ANALOG":{"Temperature1":54.75},"PID":{"PidPv":49.35,"PidSp":19.50,"PidShutdown":0,"PidPb":5.00,"PidTi":1800.00,"PidTd":15.00,"PidInitialInt":0.50,"PidDSmooth":3.00,"PidAuto":1,"PidManualPower":0.00,"PidMaxInterval":3,"PidInterval":4,"PidUpdateSecs":0,"PidSensorLost":1,"PidPower":0.00},"TempUnit":"C"}}
14:50:02.254 PID: no root
14:50:02.862 PID: no root

("PID: no root" and "PID: Got isNum" are my debug traces I inserted on lines 279 and 282 of xdrv_49_pid.ino respectively)

TO REPRODUCE

Steps to reproduce the behavior:

Provide an analogue voltage to GPIO35, set the #defines listed above, set GPIO35 to ADC temperature, and set adcparam if necessary (not really necessary for this test)

and notice how Status PidPv doesn't change when the voltage (measured through Status ANALOG.Temperature1) changes, except for once every 3 minutes (itself a fault - you can adjust PidMaxInterval and this doesn't change - you can see status pidinterval still incrementing to 300 before resetting, implying Pid.max_interval is not being updated).

Putting a trace in PIDShowSensor shows that root is false for every call to PIDEverySecond and only gets set to true at that time when pidinterval gets reset to 0 from 300. Only at that moment does Pv finally take on the current value that ANALOG.Temperature1 had been set to that whole time. And then we have to wait another 5 minutes before it's reset again.

EXPECTED BEHAVIOUR

A clear and concise description of what you expected to happen.

With PID told to use
PID_USE_LOCAL_SENSOR
PID_LOCAL_SENSOR_NAME "ANALOG"
PID_LOCAL_SENSOR_TYPE "Temperature1"
I would expect it to be polling Status ANALOG.Temperature1 every second and using that as the current Pv value in the PID loop.

SCREENSHOTS

If applicable, add screenshots to help explain your problem.

ADDITIONAL CONTEXT

Add any other context about the problem here.

(Please, remember to close the issue when the problem has been addressed)

@spacelama
Copy link
Contributor Author

OK, found the hint in the PID_USE_LOCAL_SENSOR #define comment. By dropping TelePeriod down from 300 to 10 (minimum, not really documented), I get it to do the PID loop more timely.

But why should it be limited to the TELE_PERIOD? We're explicitly servoing on a local parameter that isn't obtained set with mqtt. As #527 explains, we don't want TELE_PERIOD < 10, but it's perfectly acceptable to have PID recalculating on a 1 second loop.

But I still don't understand PIDShowSensor() - by testing for parser.getRootObject, we're bailing out of every loop every second except for the one at the end of TELE_PERIOD. This change was introduced in 9eb184c which introduced local sensor handling in the first place, so it seems unlikely it doesn't work at all.

@blacknell , any ideas what the code was trying to achieve or what I'm doing wrong?

@blacknell
Copy link
Contributor

As I recall, the sensor data only updated every 10s (I used TELEPERIOD 10) and my PID system times were much longer than that (in the order of minutes). So I suspect I wouldn't have seen the behaviour you are.

I believe PIDShowSensor works to update sensor values when there are made available (from the main tasmota loops) but sometimes the values were erroneous - hence the testing.

Sorry my recollection is a bit ropey as it was about a year ago.

Does yours work with slightly longer than 10s for the PID loop?

@spacelama
Copy link
Contributor Author

spacelama commented Sep 10, 2024

Mine will work with TelePeriod 10 seconds, but it does respond slower than it should. Take a look at my trace above with "Got isNum" vs "no root" (failing the test on value_token.isNum, line 277). So when fed with local sensor, every call to PidShowSensor is not been given a valid ResponseData except for the one call triggered by the MQTT TELE_PERIOD poll update - unsurprising since we're deliberately not getting data from MQTT when reading a local sensor. Since I don't quite understand the data flow, I can't work out how to convince it to use the most recent local sensor value that ought to have been obtained the last second (since it is being accurately updated in cmnd "Status 8" and the main webpage).

Looks like there was an attempt before this commit was made in response to #17636 to fix a similar problem, but I think that one actually dealt with values being updated by MQTT rather than local sensor.

@Wintespe
Copy link

Wintespe commented Sep 10, 2024

The problem was and is fixed.

The PID algorithm is called at the time intervals specified by the PID-command PidUpdateSecs. The temperature for the algorithm is updated by TelePeriod time slice.
If the time interval of TelePeriod is greater then the time interval from PidUpdateSecs the temperature value for the PID algorithm is outdated.

All values ​​were processed from the local sensor. I do not use MQTT because the controller has been running continuously without any external influences since then.

@Wintespe
Copy link

Mhm, you remove line 255 in your changes of the PID controller.

PIDShowSensor(); // set actual process value

Refer to:
PID-Feature computes with outdated temperature values #17636

We are back to outdated temperature values.
Now missing:

    Pid.pid.setPv(sensor_reading, Pid.last_pv_update_secs);

@spacelama
Copy link
Contributor Author

spacelama commented Sep 21, 2024

Yes @Wintespe, the old PIDShowSensor, whose job it was to copy the current values to PV (the function was misnamed, I believe, hence me renaming it to PIDProcessSensor() (FUNC_SHOW_SENSOR, "When FUNC_JSON_APPEND completes", https://tasmota.github.io/docs/API/#driver-sensor-energy-and-light-callback-ids ) was also called by PIDEverySecond, except that it didn't have a valid JSON structure when doing so, so this achieved nothing. The only time that structure was valid was at the end of FUNC_JSON_APPEND, so only that one single call to FUNC_SHOW_SENSOR resulted in PV being copied across. However, both PIDShowValuesWeb and PIDShowValuesWeb, whose job it is to relay the current status of the PID loop to the user and MQTT, was abused to also run pick.tick. Since these calls can happen at every time, they should never have resulted in such a fundamental side-effect.

That setPV has moved to PIDProcessSensor, called by PIDEverySecond. The mechanism to reliably access the valid JSON data is discussed in the link linked in the code: #18328. Calling MqttShowSensor actually ends in that call to FUNC_SHOW_SENSOR. By that stage, we now have valid JSON data, but there's no advantage calculating the PID loop at that point rather than carrying on after the call to MqttShowSensor() and setting run_pid_now then so the PID can be ticked as soon as PIDPRocessSensor returns and we immediately call PIDRun(). The code flow is now much clearer now that it's not jumping through the callback state machine. And it's using current sensor values immediately, with latency of no more than 1 second from the actual physical process change, rather than calling pid.tick at essentially random times using PV values that are up to TELE_PERIOD old (imagine a scenario where a physical process is changing smoothly between 10 and 20 degrees, but you'd PID looping on the assumption that the physical value is 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, so I will wind up and D will suddenly jump and P will suddenly jump in sign).

As for testing - it demonstrably isn't copying stale data, and I had it reliably using current values within 1 second both in the LOCAL_SENSOR case and when pushed PidPV values. I tested also in the circumstance that tasmota lost contact with the MQTT server - the process carried on updating with the real physical sensor values. Are you seeing different behaviour?

@Wintespe
Copy link

Wintespe commented Sep 21, 2024

Thanks for the detailed explanation. I don't use MQTT because my PID controller has to run completely independently. I can't even judge whether the new code can do this. My system is very small and needs the PID value to be updated every second. However, I don't have any problems at the moment and I follow the rule of "never change a running system".

The result look like this:

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants
@spacelama @blacknell @Wintespe and others