State and keys
Read state
Section titled “Read state”GET/api-gateway/v2/iot-shadow/device/{deviceId}/state
Returns the most recent merged state without contacting the controller.
{ "status": "SUCCESS", "data": { "v2_capable": true, "state": { "frame_version": 1, "counter": 327685, "seen_at": 1758400000, "telemetry_at": 1758400000, "config_at": 1758399000, "telemetry": { … }, "config": { … }, "aux_timers": [] } }}| Field | Meaning |
|---|---|
v2_capable |
A verified frame arrived in the last 10 minutes |
seen_at, telemetry_at, config_at |
Unix seconds of the newest frame of any kind, of telemetry, and of configuration |
counter |
The controller’s envelope counter on the newest frame |
telemetry |
Live readings and equipment modes. Omitted until the first telemetry frame |
config |
Numeric configuration and equipment types. Omitted until the first configuration frame |
aux_timers |
Running auto-off countdowns, [] when none, null before the first telemetry frame |
A frame replaces only the sections it carries, so telemetry and config can have different timestamps.
telemetry
Section titled “telemetry”{ "flags": { "heater": false, "solar": false, "spa_heater": false, "ph_switch": false, "orp_switch": true, "chem_stable": true, "is_naked": false, "pump_calib": true, "need_sen_cfg": false, "has_no_aux": false, "exp1_conn": true, "exp2_conn": false, "backwash": false, "dry_run": 3, "flow_ok": true }, "water_temp": 26.5, "ambient_temp": 24.5, "ph": 7.4, "orp": 652, "tds": 3368, "flow": 180, "pressure": 12, "prime_press": 0, "pump_speed": 60, "pump_power": 420, "pump_current": 2652, "drive_temp": 38, "main_pump": 99, "san": { "salt_chl": 3, "ph_doser": 1, "mineral_chl": 0, "liquid_chl": 3, "naked_ion": 3, "ozone": 3, "uv": 3 }, "cost": [0.12, 35, 0.08, 14.2], "has_gap": true, "flags2": { "pump_cooling": false, "pump_priming": false, "wifi_up": true, "eth_up": false, "mqtt_up": true, "internet_ok": true, "has_spa": false, "exp3_conn": false, "exp4_conn": false }, "aux_count": 37, "aux_mode": [99, 0, 99, 0, 0, …], "aux_trump": [0, 2], "pump_cooldown_remain": 0, "pump_prime_remain": 0}| Field | Meaning |
|---|---|
flags.heater, solar, spa_heater |
Heat source relays on |
flags.ph_switch, orp_switch |
Acid and chlorine dosing outputs energised |
flags.chem_stable |
Readings settled enough to dose on |
flags.pump_calib |
Flow calibration done |
flags.need_sen_cfg |
A sensor input needs configuration |
flags.exp1_conn … flags2.exp4_conn |
Wireless expanders 1 to 4 online |
flags.backwash |
Backwash in progress |
flags.dry_run |
Dry-run protection state, 0 to 3. 3 is normal |
flags.flow_ok |
Flow established |
water_temp, ambient_temp |
°C. ambient_temp is 0 without an air sensor |
ph, orp |
pH and mV |
tds |
Reserved; carries a placeholder value |
flow, pressure, prime_press |
L/min and kPa |
pump_speed, pump_power, pump_current, drive_temp |
Percent, W, mA and °C of the main pump drive. pump_speed is 0 unless the motor is running |
main_pump |
0 off, 1 to 20 running under that schedule, 99 manual |
san.* |
State of each sanitiser, 3 when not fitted |
cost |
Savings per hour, reduction percent, current running cost, accumulated savings, in currency units |
flags2.wifi_up, eth_up, mqtt_up, internet_ok |
Connectivity |
flags2.has_spa |
Spa actuators configured |
aux_count |
Number of equipment slots, 37 on current firmware |
aux_mode[i] |
Slot i: 0 off, 1 to 20 under that schedule, 99 manual. Slot 0 is the main pump; use main_pump for its real mode |
aux_trump |
Slots under manual override |
pump_cooldown_remain, pump_prime_remain |
Seconds |
Slot layout: 0 to 11 are outputs on the controller, 12 to 16 expander 1, 17 to 21 expander 2, 22 to 25 reserved, 26 the chlorinator’s ozone virtual slot, 27 to 31 expander 3, 32 to 36 expander 4.
config
Section titled “config”{ "fw_version": "2.5.46", "pool_size": 50, "electricity_cost": 30, "max_run_current": 12, "pump_prime_time100": 240, "pump_start_speed": 40, "min_allow_pump_speed": 50, "spa_pump_speed": 100, "heater_pump_speed": 100, "solar_pump_speed": 100, "cleaner_pump_speed": 100, "backwash_pressure": 150, "flow_retry_time": 60, "flow_retry_cycles": 3, "min_flow": 30, "min_pressure": 30, "desired_water_temp": 28, "spa_desired_temp": 38, "cfg_flags": 2, "heater_cooldown": 180, "spa_heater_cooldown": 180, "solar_hyst_temp": 5, "solar_hyst_time": 120, "ambient_hyst_time": 60, "solar_collector_flush": 840, "ph_dosing": true, "ph_dosing_time": 60, "desired_ph_level": 74, "acid_drum_volume": 20000, "remain_acid_volume": 12000, "ph_max_dose_per_day": 10, "ph_dose_intervals": 30, "ph_dose_rate": 100, "orp_controlled": true, "liquid_dosing": false, "desired_orp_mineral": 650, "mineral_max_duration_preday": 0, "desired_orp_liquid": 650, "liquid_dose_time": 60, "chlorine_drum_volume": 20000, "remain_chlorine_volume": 15000, "liquid_dose_rate": 100, "chlsave_sp": 0, "ozonesave_sp": 0, "pool_light_mode": 5, "spa_light_mode": 1, "water_temp_offset": 0, "ambient_temp_offset": 0, "sched_enabled": 5, "aux_count": 37, "aux_type": [31, 6, 12, 0, …]}Values are the controller’s raw settings, unscaled: pH set points are pH × 10, ORP in mV, volumes in mL, temperatures in whole °C, speeds in percent, times in seconds. cfg_flags bits: 0 solar heater selected, 1 pool heater selected, 2 spa heater selected, 3 tropical solar mode, 4 to 5 solar mode. sched_enabled bit i is set when schedule i is enabled. aux_type[i] is the equipment type in slot i.
aux_timers
Section titled “aux_timers”[ { "slot": 3, "remain_sec": 1740, "duration_sec": 3600 } ]Refresh state
Section titled “Refresh state”POST/api-gateway/v2/iot-shadow/device/{deviceId}/state/refresh
No body. Asks the controller for a full frame, waits up to 8 seconds, and returns { "state": … } with the same state document as GET …/state (without v2_capable). Both telemetry and config are present in the result. Use it when you need to be sure the data is current, for example right after the user changes something in another app; ordinary polling should use GET …/state.
Envelope key
Section titled “Envelope key”GET/api-gateway/v2/iot-shadow/device/{deviceId}/envelope-key
{ "status": "SUCCESS", "data": { "device_id": "02_53_4D_00_00_01", "key_hex": "00112233445566778899aabbccddeeff", "counter": "unix_seconds" }}The 16-byte key that signs everything this controller sends and accepts. Fetch it once, store it securely, and use it to talk to the controller on the LAN. The response is sent with Cache-Control: no-store. The key is unique to the controller; it cannot be used to derive any other controller’s key.
counter tells you which counter convention the cloud uses when signing outbound frames; see Envelope and keys for why that matters when several parties send actions to one controller.

