Skip to content

Placing a component

A component’s field addresses are declared coordinates: where the layout sits when it stands alone. Two knobs read that same layout somewhere else: a per-field stride selected by index, and base_offset for the whole block. They compose additively.

Model the sub-unit once and instantiate it per index. Pass index (1-based) to the component, and give each field a stride (the address step between sub-units for that register). The absolute address read is field.address + field.stride * (index - 1).

Each field carries its own stride because devices usually group registers by type, not by sub-unit. One logical sub-unit’s fields are then interleaved across the map at different steps:

class Circuit(Component):
flow_temp = gauge(12, 0.1, stride=1) # circuits 1–3 at 12, 13, 14
control_signal = integer(106, stride=2) # ... at 106, 108, 110
flow_setpoint = gauge(999, 0.1, stride=200) # ... at 999, 1199, 1399
circuits = [Circuit(unit, index=n) for n in (1, 2, 3)]

A field with the default stride=0 sits at a fixed address shared by every index.

base_offset — the whole layout at another address

Section titled “base_offset — the whole layout at another address”

base_offset places the whole declared layout at another base address. It is added to every address the component touches — fields, bits, group counts, scale_register addresses and the readable ranges — on reads and writes alike. Declare the layout once and instantiate it where the block actually sits:

class Cell(Component):
voltage = integer(0, signed=False) # one cell; addresses are instance 0's
temperature = gauge(1, 0.1)
cells = [Cell(unit, base_offset=i * 10) for i in range(16)]

The other big use is a block whose location is only known at runtime — a SunSpec model at its discovered address.

One caution. base_offset moves scale_register addresses with the block, so it cannot hand-roll instances of a repeating sub-unit whose scale factors live in the parent’s shared fixed block (a SunSpec multiple-MPPT module). Model those as a repeating_group: each instance shifts while its scale registers keep following the parent’s block.