Heating Controller State
The controller tracks sensors, zones, valves, time-periods and demand values.
Loosely, Zones represent separate controllers (in the control theory sense), sensors can be soft-mapped as controller inputs. TimePeriods provide demand signals to each controller that switch in real time following a schedule. Values are assigned to take corrective action from the demand output from the controller.
e.g. one could map all sensors as average inputs for a single zone, that has every valve configured as it's output. Or use all "downstairs" sensors as an input to one of two controllers (up, down) etc. etc. - Sensor - each sensor has
- a 16 byte address,
- last value & update time
- allocation to zone
- Valves - each value has a
- pair of bytes to represent the desired and achieved position (0= closed, 1=open),
- a count-down timer to detect stuck valves, and
- allocation to a zone
- Zone
- string to represent a room name,
- state:
- 0: manual_off
- 2: manual_temp_time
- 3: auto
- 4: sad_stuck_open
- 5: sad_stuck_closed
- 6: sad_dead_sensor
- zone countdown time (for manual_temp_countdown)
- zone_demand
- TimePeriods
- period_switchtime - end time of the period
- period_dowmask - bit flag of days_of_week that can use this period
- period_zone_demand - a vector of demand values for each zone within the period
- TZ Calendar
To help with the pseduo-code functionality descriptions, here is a representation of the state as variables:
long[16] sensor_address1 long[16] sensor_address2 short[16] sensor_lasttime short[16] sensor_lastyymmdd short[16] sensor_lastvalue byte[16] sensor_zone -1 unallocated, otherwise zone allocated 0..15 byte sensor_count byte sensor_next
long sensor_lastscan
byte[16] valve_demand byte[16] valve_position byte[16] valve_timeout byte[16] value_zone -1 unallocated, otherwise zone allocate 0..15
string[16] zone_name byte[16] zone_state short[16] zone_demand short[16] zone_temp short[16] zone_countdown
short[8] period_switchtime byte[8] period_dowmask short[8][16] period_zone_demand byte period_count
?? tz_yymmdd_switch date to apply switch ?? tz_utc_adjust +1 or 0
// live state byte live_period short live_time byte live_dow ?? live_yymmdd ?? live_utclocal_shift
At each rollover of the seconds counter (i.e. every minute): - increment the minutes-since-midnight counter
- check for date rollover, set live_yymmdd
- check for DST switch
- set calendar_pos = 0
- while (live_yymmdd > calendar_switch[calendar_pos]) increment calendar_pos
- apply the local clock offset from calendar_utc_adjust[calendar_pos] to live_utclocal_shift
- check for time-period switch
- update live_dow to the current day-of-week, initialise check_limit = 100
- while ((period_end[live_period] <= live_time || period_dow[live_period] does not permit live_dow ) && check_limit > 0)
- increment live_period, decrement check_limit
- if (live_period == period_count) set live_period = 0
- if (check_limit == 0) "go into scheduling error state"? set live_period = 0
- for each zone,
- copy the period_zone_demand[live_period][z] to zone_demand[z] if zone_state[z] == auto
- check for stuck valves
- decrement each valve_timeout counter that is greater than zero, where the valve_demand is different to valve_position
- if a valve_timeout[v] reaches zero, lookup the zone z = , set the zone_state[z] to sad_stuck_closed or sad_stuck_open (if operating)
- check for dead sensor
- if a sensor hasn't updated in an hour, and the sensor is allocated, set the corresponding zone status to sad_dead_sensor (if operating)
- Usability note: corrective action is to
- 1) remove sensor from zone, then
- 2) set the zone to manual_off, manual_temp_time (or auto if another sensor exists for the zone), which all clear the sad state
- 3) re-allocate the valve to take output from a nearby zone as a substitute !
- update the sensor measurement
- if last asynchronous (conversion successful) perform
- sensor_lasttime[sensor_next] = live_time
- sensor_lastyymmdd[sensor_next] = live_yymmdd
- sensor_lastvalue[sensor_next] = (conversion_result)
- increment sensor_next
- if sensor_next == sensor_count then sensor_next = 0
- send a conversion request on the I2C bus for sensor_address[sensor_next]
- copy sensor values to zone_temp, taking average where more than one sensor is active for a given zone (many values will not have changed)
|
|