diff --git a/custom_components/simple_pid_controller/sensor.py b/custom_components/simple_pid_controller/sensor.py index 4f26ec7..5b8e414 100644 --- a/custom_components/simple_pid_controller/sensor.py +++ b/custom_components/simple_pid_controller/sensor.py @@ -37,6 +37,7 @@ async def async_setup_entry( pid = PID(1.0, 0.1, 0.05, setpoint=50) pid.sample_time = 10.0 pid.output_limits = (-10.0, 10.0) + handle.last_contributions = (0, 0, 0, 0) async def update_pid(): """Update the PID output using current sensor and parameter values.""" @@ -69,24 +70,29 @@ async def update_pid(): output = pid(input_value) - # Calculate contributions - p_contrib = kp * (setpoint - input_value) if not p_on_m else -kp * input_value - i_contrib = pid._integral * ki - d_contrib = pid._last_output - output if pid._last_output is not None else 0.0 + # save last I contribution + last_i = handle.last_contributions[1] - handle.last_contributions = (p_contrib, i_contrib, d_contrib) + # save all latest contributions + handle.last_contributions = ( + pid.components[0], + pid.components[1], + pid.components[2], + pid.components[1] - last_i, + ) _LOGGER.debug( - "PID input=%.2f setpoint=%.2f kp=%.2f ki=%.2f kd=%.2f => output=%.2f [P=%.2f, I=%.2f, D=%.2f]", + "PID input=%s setpoint=%s kp=%s ki=%s kd=%s => output=%s [P=%s, I=%s, D=%s, dI=%s]", input_value, - setpoint, - kp, - ki, - kd, + pid.setpoint, + pid.Kp, + pid.Ki, + pid.Kd, output, - p_contrib, - i_contrib, - d_contrib, + handle.last_contributions[0], + handle.last_contributions[1], + handle.last_contributions[2], + handle.last_contributions[3], ) if coordinator.update_interval.total_seconds() != pid.sample_time: @@ -126,6 +132,7 @@ async def start_refresh(_: Any) -> None: hass, entry, "pid_d_contrib", "D contribution", coordinator ), PIDContributionSensor(hass, entry, "error", "Error", coordinator), + PIDContributionSensor(hass, entry, "pid_i_delta", "I delta", coordinator), ] ) @@ -196,7 +203,7 @@ def __init__( BasePIDEntity.__init__(self, hass, entry, key, name) self._attr_entity_category = EntityCategory.DIAGNOSTIC - # self._attr_entity_registry_enabled_default = False + self._attr_entity_registry_enabled_default = False self._attr_state_class = SensorStateClass.MEASUREMENT self._key = key self._handle = entry.runtime_data.handle @@ -217,5 +224,6 @@ def native_value(self): "pid_i_contrib": contributions[1], "pid_d_contrib": contributions[2], "error": error, + "pid_i_delta": contributions[3], }.get(self._key) return round(value, 2) if value is not None else None diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 509afaa..9201041 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -47,7 +47,7 @@ async def test_pid_contribution_native_value_rounding_and_none(hass, config_entr """Test that PIDContributionSensor.native_value rounds correctly and returns None for unknown key.""" handle = config_entry.runtime_data.handle # Provide known contributions - handle.last_contributions = (0.1234, 1.9876, 2.5555) + handle.last_contributions = (0.1234, 1.9876, 2.5555, 3.3789) coordinator = PIDDataCoordinator(hass, "test", lambda: 0, interval=1) # Map contribution keys to expected values @@ -56,6 +56,7 @@ async def test_pid_contribution_native_value_rounding_and_none(hass, config_entr ("pid_i_contrib", round(1.9876, 2)), ("pid_d_contrib", round(2.5555, 2)), ("error", -25), + ("pid_i_delta", round(3.3789, 2)), ("unknown_key", None), # Should return None ]