@@ -205,21 +205,37 @@ from neopool_modbus.capabilities import (
205205 is_uv_lamp_present,
206206)
207207from neopool_modbus.decoders import (
208+ CELL_BOOST_MODE_LABELS ,
209+ FILTRATION_MODE_LABELS ,
210+ FILTRATION_SPEED_LABELS ,
211+ FILTRATION_SPEED_STATE_LABELS ,
212+ FILTVALVE_MODE_LABELS ,
213+ HIDRO_POLARITY_LABELS ,
214+ ION_POLARITY_LABELS ,
215+ PH_PUMP_STATUS_LABELS ,
216+ PH_STATUS_ALARM_LABELS ,
208217 aggregate_filtration_remaining,
209218 build_timer_block,
210219 combine_u32,
211220 decode_cell_boost,
212221 decode_filtration_mode,
213222 decode_filtration_speed,
223+ decode_filtvalve_mode,
224+ decode_hidro_polarity,
225+ decode_ion_polarity,
214226 decode_par_model_modules,
227+ decode_ph_alarm,
228+ decode_ph_pump_status,
215229 derive_timer_stop,
216230 encode_cell_boost,
217231 encode_filtration_mode,
218232 encode_filtration_speed,
233+ encode_filtvalve_mode,
219234 get_machine_name,
220235 hhmm_to_seconds,
221236 is_hydrolysis_in_percent,
222237 parse_timer_block,
238+ ph_pump_options,
223239 seconds_to_hhmm,
224240 # ... see neopool_modbus.decoders for the full list
225241)
@@ -233,6 +249,42 @@ from neopool_modbus.status_mask import (
233249)
234250```
235251
252+ ### Enum labels
253+
254+ The ` decoders ` module publishes the label collections that pair with
255+ each enum-shaped decoder, so integrations do not have to duplicate the
256+ mappings in their own UI code:
257+
258+ | Collection | Type | Pairs with |
259+ | ------------------------------- | ----------------- | ----------------------------------------------------- |
260+ | ` FILTRATION_MODE_LABELS ` | ` dict[int, str] ` | ` decode_filtration_mode ` / ` encode_filtration_mode ` |
261+ | ` FILTRATION_SPEED_LABELS ` | ` dict[int, str] ` | ` decode_filtration_speed ` / ` encode_filtration_speed ` |
262+ | ` CELL_BOOST_MODE_LABELS ` | ` dict[int, str] ` | ` decode_cell_boost ` / ` encode_cell_boost ` |
263+ | ` FILTVALVE_MODE_LABELS ` | ` dict[int, str] ` | ` decode_filtvalve_mode ` / ` encode_filtvalve_mode ` |
264+ | ` PH_STATUS_ALARM_LABELS ` | ` dict[int, str] ` | ` decode_ph_alarm ` |
265+ | ` FILTRATION_SPEED_STATE_LABELS ` | ` tuple[str, ...] ` | return values of ` compute_filtration_speed_state ` |
266+ | ` HIDRO_POLARITY_LABELS ` | ` tuple[str, ...] ` | return values of ` decode_hidro_polarity ` |
267+ | ` ION_POLARITY_LABELS ` | ` tuple[str, ...] ` | return values of ` decode_ion_polarity ` |
268+ | ` PH_PUMP_STATUS_LABELS ` | ` tuple[str, ...] ` | return values of ` decode_ph_pump_status ` |
269+
270+ Dict-shaped collections use the wire value as the key; tuple-shaped
271+ ones enumerate the string outputs of a pure decoder that reads more
272+ than one register. The ` ph_pump_options(data) ` helper returns the
273+ subset of ` PH_PUMP_STATUS_LABELS ` reachable under the current
274+ ` MBF_PAR_RELAY_PH ` mode (acid-only / base-only / both).
275+
276+ ``` python
277+ from neopool_modbus.decoders import (
278+ FILTRATION_MODE_LABELS ,
279+ decode_filtration_mode,
280+ ph_pump_options,
281+ )
282+
283+ modes = list (FILTRATION_MODE_LABELS .values()) # ("manual", "auto", ...)
284+ current = decode_filtration_mode(data.get(" MBF_PAR_FILT_MODE" ))
285+ options = ph_pump_options(data) # narrowed by MBF_PAR_RELAY_PH
286+ ```
287+
236288### Capabilities
237289
238290` neopool_modbus.capabilities ` exposes pure predicates over a register
@@ -262,16 +314,16 @@ The client exposes named operations for the writes integrations
262314typically need, so callers do not have to reach for raw register
263315addresses:
264316
265- | Method | Effect |
266- | ---------------------------------------------- | ------------------------------------------------------------------------------------- |
267- | ` async_set_filtration_mode(name, apply=True) ` | manual / auto / heating / smart / intelligent / backwash |
268- | ` async_set_cell_boost(name, apply=True) ` | inactive / active / active_redox |
269- | ` async_set_filtration_speed(name, apply=False) ` | low / mid / high; RMW on ` MBF_PAR_FILTRATION_CONF ` (cache hot path, fresh-read cold path) |
270- | ` async_set_temp_setpoint(raw, apply=True) ` | writes the same scaled value to heating + intelligent registers in sync |
271- | ` async_clear_errors() ` | one-shot to ` MBF_ESCAPE ` |
272- | ` async_save_to_eeprom() ` | one-shot to ` MBF_SAVE_TO_EEPROM ` |
273- | ` async_reset_user_counters() ` | resets user counters and chains the EEPROM save (the reset is volatile) |
274- | ` async_sync_device_time(timestamp) ` | writes the 32-bit ` timestamp ` to ` MBF_PAR_TIME ` and triggers ` MBF_ACTION_COPY_TO_RTC ` |
317+ | Method | Effect |
318+ | ----------------------------------------------- | ---- ------------------------------------------------------------------------------------- |
319+ | ` async_set_filtration_mode(name, apply=True) ` | manual / auto / heating / smart / intelligent / backwash |
320+ | ` async_set_cell_boost(name, apply=True) ` | inactive / active / active_redox |
321+ | ` async_set_filtration_speed(name, apply=False) ` | low / mid / high; RMW on ` MBF_PAR_FILTRATION_CONF ` (cache hot path, fresh-read cold path) |
322+ | ` async_set_temp_setpoint(raw, apply=True) ` | writes the same scaled value to heating + intelligent registers in sync |
323+ | ` async_clear_errors() ` | one-shot to ` MBF_ESCAPE ` |
324+ | ` async_save_to_eeprom() ` | one-shot to ` MBF_SAVE_TO_EEPROM ` |
325+ | ` async_reset_user_counters() ` | resets user counters and chains the EEPROM save (the reset is volatile) |
326+ | ` async_sync_device_time(timestamp) ` | writes the 32-bit ` timestamp ` to ` MBF_PAR_TIME ` and triggers ` MBF_ACTION_COPY_TO_RTC ` |
275327
276328Unknown mode/speed names raise ` ValueError ` before any I/O happens.
277329
@@ -285,12 +337,12 @@ All client methods translate underlying pymodbus exceptions into the
285337` NeoPoolError ` hierarchy at the library boundary, so callers never need
286338to import ` pymodbus ` to catch errors:
287339
288- | Class | Raised when |
289- | ------------------------ | -------------------------------------------------------------------------------- |
290- | ` NeoPoolConnectionError ` | TCP connect fails, returned ` False ` , or the client is in its post-failure backoff |
291- | ` NeoPoolTimeoutError ` | Connect, read, or write times out (` asyncio.TimeoutError ` ) |
340+ | Class | Raised when |
341+ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
342+ | ` NeoPoolConnectionError ` | TCP connect fails, returned ` False ` , or the client is in its post-failure backoff |
343+ | ` NeoPoolTimeoutError ` | Connect, read, or write times out (` asyncio.TimeoutError ` ) |
292344| ` NeoPoolModbusError ` | A read returns a Modbus exception response (` isError() ` true), or ` async_write_aux_relay ` / one of the timer write follow-ups returns ` isError() ` |
293- | ` NeoPoolError ` | Common base; catch this to handle any of the above |
345+ | ` NeoPoolError ` | Common base; catch this to handle any of the above |
294346
295347> [ !WARNING]
296348> ` NeoPoolModbusClient.async_write_register() ` is the exception to the
0 commit comments