diff --git a/pythermostat/pythermostat/autotune.py b/pythermostat/pythermostat/autotune.py index 0cd45a4..682fb0f 100644 --- a/pythermostat/pythermostat/autotune.py +++ b/pythermostat/pythermostat/autotune.py @@ -2,7 +2,7 @@ import math import logging import time from collections import deque, namedtuple -from enum import Enum +from enum import Enum, auto from pythermostat.client import Client @@ -13,11 +13,12 @@ from pythermostat.client import Client class PIDAutotuneState(Enum): - STATE_OFF = 'off' - STATE_RELAY_STEP_UP = 'relay step up' - STATE_RELAY_STEP_DOWN = 'relay step down' - STATE_SUCCEEDED = 'succeeded' - STATE_FAILED = 'failed' + OFF = auto() + RELAY_STEP_UP = auto() + RELAY_STEP_DOWN = auto() + SUCCEEDED = auto() + FAILED = auto() + READY = auto() class PIDAutotune: @@ -45,7 +46,7 @@ class PIDAutotune: self._noiseband = noiseband self._out_min = -out_step self._out_max = out_step - self._state = PIDAutotuneState.STATE_OFF + self._state = PIDAutotuneState.OFF self._peak_timestamps = deque(maxlen=5) self._peaks = deque(maxlen=5) self._output = 0 @@ -57,6 +58,21 @@ class PIDAutotune: self._Ku = 0 self._Pu = 0 + def set_param(self, target, step, noiseband, sampletime, lookback): + self._setpoint = target + self._outputstep = step + self._out_max = step + self._out_min = -step + self._noiseband = noiseband + self._inputs = deque(maxlen=round(lookback / sampletime)) + + def set_ready(self): + self._state = PIDAutotuneState.READY + self._peak_count = 0 + + def set_off(self): + self._state = PIDAutotuneState.OFF + def state(self): """Get the current state.""" return self._state @@ -94,29 +110,30 @@ class PIDAutotune: """ now = time_input * 1000 - if (self._state == PIDAutotuneState.STATE_OFF - or self._state == PIDAutotuneState.STATE_SUCCEEDED - or self._state == PIDAutotuneState.STATE_FAILED): - self._state = PIDAutotuneState.STATE_RELAY_STEP_UP + if self._state not in { + PIDAutotuneState.RELAY_STEP_DOWN, + PIDAutotuneState.RELAY_STEP_UP, + }: + self._state = PIDAutotuneState.RELAY_STEP_UP self._last_run_timestamp = now # check input and change relay state if necessary - if (self._state == PIDAutotuneState.STATE_RELAY_STEP_UP - and input_val > self._setpoint + self._noiseband): - self._state = PIDAutotuneState.STATE_RELAY_STEP_DOWN + if self._state == PIDAutotuneState.RELAY_STEP_UP + and input_val > self._setpoint + self._noiseband: + self._state = PIDAutotuneState.RELAY_STEP_DOWN logging.debug('switched state: {0}'.format(self._state)) logging.debug('input: {0}'.format(input_val)) - elif (self._state == PIDAutotuneState.STATE_RELAY_STEP_DOWN - and input_val < self._setpoint - self._noiseband): - self._state = PIDAutotuneState.STATE_RELAY_STEP_UP + elif self._state == PIDAutotuneState.RELAY_STEP_DOWN + and input_val < self._setpoint - self._noiseband: + self._state = PIDAutotuneState.RELAY_STEP_UP logging.debug('switched state: {0}'.format(self._state)) logging.debug('input: {0}'.format(input_val)) # set output - if (self._state == PIDAutotuneState.STATE_RELAY_STEP_UP): + if self._state == PIDAutotuneState.RELAY_STEP_UP: self._output = self._initial_output - self._outputstep - elif self._state == PIDAutotuneState.STATE_RELAY_STEP_DOWN: + elif self._state == PIDAutotuneState.RELAY_STEP_DOWN: self._output = self._initial_output + self._outputstep # respect output limits @@ -184,16 +201,16 @@ class PIDAutotune: logging.debug('amplitude deviation: {0}'.format(amplitude_dev)) if amplitude_dev < PIDAutotune.PEAK_AMPLITUDE_TOLERANCE: - self._state = PIDAutotuneState.STATE_SUCCEEDED + self._state = PIDAutotuneState.SUCCEEDED # if the autotune has not already converged # terminate after 10 cycles if self._peak_count >= 20: self._output = 0 - self._state = PIDAutotuneState.STATE_FAILED + self._state = PIDAutotuneState.FAILED return True - if self._state == PIDAutotuneState.STATE_SUCCEEDED: + if self._state == PIDAutotuneState.SUCCEEDED: self._output = 0 logging.debug('peak finding successful')