watlowlib.registry¶
The cross-protocol parameter registry — PARAMETERS,
ParameterRegistry, ParameterSpec, RwesFlag, family table,
enumerations, and unit enums. See Parameters and
Design §5a.
Public surface¶
watlowlib.registry ¶
Parameter and family registry.
The registry is the cross-protocol seam: each parameter row carries
both Std Bus selector (cls / member / instance) and Modbus
selector (relative_addr / absolute_addr / register_count)
metadata so command variants can lower a single
read_parameter(...) call to either protocol with no per-parameter
bespoke code. See docs/design.md §5a.
ControllerFamily ¶
Bases: StrEnum
Watlow controller family discriminator.
Membership here is advisory — :class:watlowlib.devices.session.Session
treats family hints as priors, not gates. See docs/design.md §5b.
ParameterRegistry ¶
Indexed view over a sequence of :class:ParameterSpec rows.
Lookups are O(1) on canonical name, alias, and parameter_id.
Construction is O(N).
Source code in src/watlowlib/registry/parameters.py
has ¶
Return True if name_or_id resolves; never raises.
resolve ¶
Look up a spec by canonical name, alias, or parameter ID.
Raises:
| Type | Description |
|---|---|
WatlowValidationError
|
|
Source code in src/watlowlib/registry/parameters.py
validate_instance ¶
Raise if instance is out of range for spec.
Public so the variant layer can validate before encoding.
Source code in src/watlowlib/registry/parameters.py
validate_value ¶
Soft range check based on the spec's parsed range metadata.
Skipped silently if range_min / range_max couldn't be
parsed from the JSON range field — Watlow's range strings
are not always machine-readable. STRING parameters are not
range-checked.
Source code in src/watlowlib/registry/parameters.py
ParameterSpec
dataclass
¶
ParameterSpec(
parameter_id,
name,
aliases,
data_type,
unit_kind,
rwes,
safety,
cls,
member,
default_instance,
max_instance,
relative_addr,
absolute_addr,
register_count,
word_order=None,
range_min=None,
range_max=None,
default=None,
family_hints=_empty_family_hints(),
scale=1.0,
)
A single parameter row from pm_parameters.json.
Per-protocol fields:
- Std Bus selector: :attr:
cls, :attr:member, :attr:default_instance, :attr:max_instance. - Modbus selector: :attr:
relative_addr, :attr:absolute_addr, :attr:register_count, :attr:word_order(None→ client defaultHIGH_LOWper design §5a).
scale
class-attribute
instance-attribute
¶
Engineering-unit scale factor for the Modbus decode / encode path.
The wire stores raw integers (e.g. the Series SD reports a process
value of 68421 for 68.421 °F); scale is the multiplier
that turns the raw word into engineering units on read
(value * scale) and the divisor that turns engineering units
back into raw words on write (round(value / scale)).
1.0 (the default) means no scaling — and is applied as a
strict identity: the read path skips the multiply entirely when
scale == 1.0 so an integer parameter stays an int rather
than being promoted to float by int * 1.0. Std Bus rows are
never scaled (the Std Bus variant ignores this field).
RwesFlag ¶
Bases: StrEnum
Persistence + access flag from the EZ-ZONE register list.
R— read-only.W— write-only (rare; typically actions like "start autotune").RW— runtime read/write, not EEPROM-backed.RWE— RW + persisted to EEPROM.RWES— RWE + saved set ("save settings to user memory").
Mapping to :class:SafetyTier is in
:func:_safety_from_rwes; the registry binds the result to
:attr:ParameterSpec.safety at load time.
Unit ¶
Bases: StrEnum
Concrete display unit attached to a :class:Reading value.
UnitKind ¶
Bases: StrEnum
Structural unit family of a parameter, as declared by the registry.
Maps to a concrete :class:Unit at read time via
:func:resolve_unit. TEMPERATURE resolves to °C or °F depending
on the device's comms display setting (parameter 17050); the rest
are independent of device state.
classify_family ¶
Return the :class:ControllerFamily for a part-number string.
Only the leading family discriminator is parsed; per-family digit
decoding is in :func:decode_part_number.
Source code in src/watlowlib/registry/families.py
coerce_unit ¶
Normalise a :class:Unit-or-string into a :class:Unit.
Case-insensitive on the string side. Raises
:class:WatlowValidationError on an unknown alias so the setter
can fail pre-I/O before any wire bytes go out.
Raw integer device codes (15, 30) are not accepted — callers
who want the lower-level path use
write_parameter("display_units", 30).
Source code in src/watlowlib/registry/units.py
display_code_for_unit ¶
load_enumerations ¶
Load and return all symbol rows from enumerations.json.
Section-header rows (where the value column is a string) are
dropped; only (_, _, _, int) rows survive.
Source code in src/watlowlib/registry/enumerations.py
load_parameters ¶
Load every parameter spec from a bundled registry JSON file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Bare filename inside the :mod: |
required |
family
|
ControllerFamily
|
The controller family this file describes. Used as the
default single-member |
required |
family_hints
|
frozenset[ControllerFamily] | None
|
Explicit family-hint set stamped on every produced
spec. Defaults to |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
One |
ParameterSpec
|
class: |
...
|
winning on duplicate |
|
tuple[ParameterSpec, ...]
|
repeat ids with differing instance metadata). |
Source code in src/watlowlib/registry/parameters.py
load_pm_parameters ¶
Load and return every PM parameter spec from the bundled JSON.
load_sd_parameters ¶
Load and return every Series SD parameter spec from the bundled JSON.
resolve_unit ¶
Resolve a parameter's :class:UnitKind to a concrete :class:Unit.
TEMPERATURE→temperature_unit(passes the caller's asserted wire scale through, orNonewhen none was asserted).PERCENT→ :attr:Unit.PERCENT.- Everything else →
None.
Pure mapping; no I/O. The caller (typically
:class:watlowlib.devices.session.Session) is responsible for
determining the wire scale and passing it in.
Source code in src/watlowlib/registry/units.py
unit_from_display_code ¶
Parameter specs + registry¶
watlowlib.registry.parameters ¶
Parameter registry — the cross-protocol seam.
Each row of data/pm_parameters.json is loaded once into a
:class:ParameterSpec, indexed by canonical name (with aliases) and by
parameter_id. The spec carries enough information to lower a
read_parameter("setpoint") call to either Std Bus or Modbus with no
per-parameter bespoke code.
Loading is eager: a module-level :data:PARAMETERS is built at
import time so subsequent lookups are O(1) dict reads. Loading is also
fail-loud for malformed rows — a row missing decode metadata for
its declared :class:DataType (e.g. a PACKED row with no count) is
not silently dropped; it is surfaced as an
:class:watlowlib.errors.WatlowProtocolError at load time.
ParameterRegistry ¶
Indexed view over a sequence of :class:ParameterSpec rows.
Lookups are O(1) on canonical name, alias, and parameter_id.
Construction is O(N).
Source code in src/watlowlib/registry/parameters.py
has ¶
Return True if name_or_id resolves; never raises.
resolve ¶
Look up a spec by canonical name, alias, or parameter ID.
Raises:
| Type | Description |
|---|---|
WatlowValidationError
|
|
Source code in src/watlowlib/registry/parameters.py
validate_instance ¶
Raise if instance is out of range for spec.
Public so the variant layer can validate before encoding.
Source code in src/watlowlib/registry/parameters.py
validate_value ¶
Soft range check based on the spec's parsed range metadata.
Skipped silently if range_min / range_max couldn't be
parsed from the JSON range field — Watlow's range strings
are not always machine-readable. STRING parameters are not
range-checked.
Source code in src/watlowlib/registry/parameters.py
ParameterSpec
dataclass
¶
ParameterSpec(
parameter_id,
name,
aliases,
data_type,
unit_kind,
rwes,
safety,
cls,
member,
default_instance,
max_instance,
relative_addr,
absolute_addr,
register_count,
word_order=None,
range_min=None,
range_max=None,
default=None,
family_hints=_empty_family_hints(),
scale=1.0,
)
A single parameter row from pm_parameters.json.
Per-protocol fields:
- Std Bus selector: :attr:
cls, :attr:member, :attr:default_instance, :attr:max_instance. - Modbus selector: :attr:
relative_addr, :attr:absolute_addr, :attr:register_count, :attr:word_order(None→ client defaultHIGH_LOWper design §5a).
scale
class-attribute
instance-attribute
¶
Engineering-unit scale factor for the Modbus decode / encode path.
The wire stores raw integers (e.g. the Series SD reports a process
value of 68421 for 68.421 °F); scale is the multiplier
that turns the raw word into engineering units on read
(value * scale) and the divisor that turns engineering units
back into raw words on write (round(value / scale)).
1.0 (the default) means no scaling — and is applied as a
strict identity: the read path skips the multiply entirely when
scale == 1.0 so an integer parameter stays an int rather
than being promoted to float by int * 1.0. Std Bus rows are
never scaled (the Std Bus variant ignores this field).
RwesFlag ¶
Bases: StrEnum
Persistence + access flag from the EZ-ZONE register list.
R— read-only.W— write-only (rare; typically actions like "start autotune").RW— runtime read/write, not EEPROM-backed.RWE— RW + persisted to EEPROM.RWES— RWE + saved set ("save settings to user memory").
Mapping to :class:SafetyTier is in
:func:_safety_from_rwes; the registry binds the result to
:attr:ParameterSpec.safety at load time.
load_parameters ¶
Load every parameter spec from a bundled registry JSON file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
str
|
Bare filename inside the :mod: |
required |
family
|
ControllerFamily
|
The controller family this file describes. Used as the
default single-member |
required |
family_hints
|
frozenset[ControllerFamily] | None
|
Explicit family-hint set stamped on every produced
spec. Defaults to |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
One |
ParameterSpec
|
class: |
...
|
winning on duplicate |
|
tuple[ParameterSpec, ...]
|
repeat ids with differing instance metadata). |
Source code in src/watlowlib/registry/parameters.py
load_pm_parameters ¶
Load and return every PM parameter spec from the bundled JSON.
load_sd_parameters ¶
Load and return every Series SD parameter spec from the bundled JSON.
Family classification + part-number decoder¶
watlowlib.registry.families ¶
Controller families and per-family part-number decoders.
The :class:ControllerFamily enum is the family discriminator used
across the library. :func:classify_family parses the leading
characters of a part number to that enum; :func:decode_part_number
runs the family's full decoder when one is registered.
The EZ-ZONE PM decoder is the only full per-family decoder today. Other families fall through to the discriminator-only stub.
ControllerFamily ¶
Bases: StrEnum
Watlow controller family discriminator.
Membership here is advisory — :class:watlowlib.devices.session.Session
treats family hints as priors, not gates. See docs/design.md §5b.
capabilities_for_part_number ¶
Decode :class:Capability bits from a parsed :class:PartNumber.
PM is the only family decoded today; other families return the family prior unchanged. Bits derived here are facts about the SKU — they do not depend on the device responding to any particular query, only on the part-number string.
Returns the family prior OR-ed with any decoded bits, so callers
can use this as the authoritative seed for
:attr:DeviceInfo.capabilities after :meth:Controller.identify
captures the part number.
Source code in src/watlowlib/registry/families.py
classify_family ¶
Return the :class:ControllerFamily for a part-number string.
Only the leading family discriminator is parsed; per-family digit
decoding is in :func:decode_part_number.
Source code in src/watlowlib/registry/families.py
decode_part_number ¶
Decode raw into a populated :class:PartNumber.
Dispatches to the per-family decoder based on
:func:classify_family. Families without a decoder fall through
to a bare :class:PartNumber carrying only the family
discriminator.
Source code in src/watlowlib/registry/families.py
default_loops ¶
Return the default loop count for the controller behind part.
Used by :class:Controller.identify to seed
:attr:DeviceInfo.loops and by :meth:Controller.loop to
validate the n argument. Returns 1 whenever the family or
digits are unknown — never raises.
Source code in src/watlowlib/registry/families.py
pm_comms_code ¶
Return the position-8 comms character of a PM part number, or None.
Position 8 is the first character of the 7-char options block —
e.g. PM3R1CA-AAAAAAA has comms code A (Standard Bus only).
Returns None for non-PM families and for PM part numbers
without a parsed options string.
Source code in src/watlowlib/registry/families.py
pm_comms_supports_modbus ¶
Whether the part's comms position-8 character carries Modbus.
Enumerations¶
watlowlib.registry.enumerations ¶
Loader for data/enumerations.json.
The enumerations file groups the symbolic names Watlow uses for parameter values (heat algorithms, sensor types, alarm states, ...). It is shaped as a flat list of rows, where each row is one of:
- a 4-tuple
[7Seg, PC label, text enumeration, value]— the actual symbol entry - a 4-tuple where the last element is a string column header (e.g.
[..., "Value"]) — section header rows; skipped on load.
This module only loads the table. Binding specific symbol groups to
:class:watlowlib.registry.parameters.ParameterSpec.enum happens
elsewhere, once families and per-parameter enum metadata are wired
through.
load_enumerations ¶
Load and return all symbol rows from enumerations.json.
Section-header rows (where the value column is a string) are
dropped; only (_, _, _, int) rows survive.
Source code in src/watlowlib/registry/enumerations.py
Aliases¶
watlowlib.registry.aliases ¶
Friendly aliases for canonical parameter names.
Aliases like pv → process_value and sp → setpoint back
the public read_parameter("pv") / read_parameter("setpoint")
entry points. The :class:watlowlib.registry.parameters.ParameterRegistry
consults this table when resolving a string that doesn't match a
canonical name directly. Aliases are case-insensitive.
Adding new aliases is non-breaking — registry resolution is lookup, not generative.
Units¶
watlowlib.registry.units ¶
Unit vocabulary for Watlow parameters.
Two enums:
- :class:
Unit— the concrete unit a temperature/percent value is reported in (°C/°F/%). Attached to :class:Reading.unitand :class:Sample.unit. - :class:
UnitKind— the structural unit family of a parameter as declared in the registry JSON (temperature/percent/dimensionless/enumeration/string). Used by :func:resolve_unitto compute the concrete :class:Unitfor a temperature parameter given the (separately-determined) wire scale.
Watlow PM controllers expose two display-unit registers — 3005 ("Display - Units", front panel) and 17050 ("Communications - Display Units"). On at least one PM3 firmware (id 5678), 17050 is label- only: writing it changes the enum reported when 17050 is read back but does not change the scale of values exchanged over comms. The internal storage unit (the scale temperatures actually travel in over the wire) is governed by something else — and on devices where it cannot be determined empirically, the library refuses to guess.
Consequence for this module: :func:resolve_unit no longer assumes
17050 is the wire scale. The caller (the session) supplies an
explicit temperature_unit derived from the
assert_wire_temperature_unit user-assertion (or None when no
assertion was made). Reading.unit = None is the honest answer for
temperature reads when the wire scale is unknown.
See docs/devices.md §Units for the user-facing contract.
Unit ¶
Bases: StrEnum
Concrete display unit attached to a :class:Reading value.
UnitKind ¶
Bases: StrEnum
Structural unit family of a parameter, as declared by the registry.
Maps to a concrete :class:Unit at read time via
:func:resolve_unit. TEMPERATURE resolves to °C or °F depending
on the device's comms display setting (parameter 17050); the rest
are independent of device state.
coerce_unit ¶
Normalise a :class:Unit-or-string into a :class:Unit.
Case-insensitive on the string side. Raises
:class:WatlowValidationError on an unknown alias so the setter
can fail pre-I/O before any wire bytes go out.
Raw integer device codes (15, 30) are not accepted — callers
who want the lower-level path use
write_parameter("display_units", 30).
Source code in src/watlowlib/registry/units.py
display_code_for_unit ¶
resolve_unit ¶
Resolve a parameter's :class:UnitKind to a concrete :class:Unit.
TEMPERATURE→temperature_unit(passes the caller's asserted wire scale through, orNonewhen none was asserted).PERCENT→ :attr:Unit.PERCENT.- Everything else →
None.
Pure mapping; no I/O. The caller (typically
:class:watlowlib.devices.session.Session) is responsible for
determining the wire scale and passing it in.