Skip to content

docs: consumers, serving a machine to another protocol - #26

Merged
neu-rah merged 3 commits into
mainfrom
docs-consumers
Oct 8, 2026
Merged

neu-rah merged 3 commits into
mainfrom
docs-consumers

Conversation

@neu-rah

@neu-rah neu-rah commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

Adds docs/consumers.md (rules for serving a machine to another protocol), linked from the README (next to the examples list), from docs/role.md ("The consumer's contract") and from examples/sila/README.md.

examples/sila/README.md, "The rules you meet": a value that bypasses SiLA was described as ignored by the device in all cases. It is clamped by lamp (a light) and ignored by step, mode, note and duty. Checked by running the host build and sending the values straight over the link (python/onemachine, no gateway): lamp.level = 250 → {'level': 200, 'clamped': True}; step.value = 7 (was 50), mode.index = 7 (was 2), a note buffer with bytes 0xC3 0xA1 (was bye) and duty.raw = 1001 (was 250, max 1000) → the previous value, reported.

docs/consumers.md: rule 4 now says that examples/sila meets it by refusing tuned roles (their run-time values are not served yet); the first sentence of "What the machine provides" is scoped to a consumer on the other side of the link.

Every claim in docs/consumers.md, against the code

claim evidence
Eight role kinds examples/sila/gateway.py:57 KINDS: switch, light, discrete, select, analog, text, scaled, action
The firmware carries no protocol library, vocabulary or generated files examples/sila/src/ and platformio.ini: no sila/grpc/protobuf/nghttp text except a comment line in platformio.ini:1; the link is role::Link (src/main.cpp)
The consumer gets the description (m, c, r) at connect python/onemachine/machine.py:153-154 (_text('m'), _text('r'), _text('c')); the ops are documented at include/oneMachine/role/link.h:6 and served at :82
Frames are binary, positional, checked by hash include/oneMachine/role/link.h:8 (s/g), BadHash handling at python/onemachine/machine.py:175-186
value, scale, unit lines a kind prints include/oneMachine/role/face.h:37-47 (Params::value/scale/unit); read in python/onemachine/machine.py (RoleInfo.values/scales/units)
1. One table, rows about kinds; machine-specific values read from the description gateway.py:57 (rows are kinds); role names, limits, values, labels, scales, units and text length come from the description in model() gateway.py:92-168 (info.params, info.values, info.scales, info.units, the command field's size at :147)
A light's level is bounded by its max parameter gateway.py:59 (upper='max'), :117-121
2. The FDL is generated at start gateway.py:171 fdl(), :216 write_fdl, called at start :321; a changed label gives a new Set after a reconnect (ran on a Nano: the machine hash changes and the served Set follows)
3. Refuses by name: unknown kind, tuned role, unused line, unknown unit symbol gateway.py:97 (kind), :98 (tuned), :102 (line the row does not use), :142/:153 (unit symbol); "never serves part of a machine": model() raises on the first problem and :168 on no roles; the exit message names the role: :317. Ran: 13 edited descriptions (labels, stray lines, unit symbols, scale, unknown kind and line) each refused as expected
4. Constraints only from fixed values The constraint values come from param max (gateway.py:117), the value lines (:123-135), max and scale (:154-161). examples/sila meets the rule by refusing tuned roles (gateway.py:98); it has no path that turns a run-time value into a readable property, which is what the page now says. Main's description format has no compile-time/run-time column on param
5. Refused at the edge, nothing reaches the device The server's constraint check runs before setter (gateway.py:259); ran with an independent client (unitelabs-sila): ValidationError and no command frame on the link
5. The device is the backstop: clamped, or ignored clamp: include/oneMachine/role/kinds.h:54-56 (Light::apply); ignore: examples/sila/src/kinds.h:19 (Discrete), :43 (Select), :73 (Text), :88 (Scaled). Ran (above)
5. The report carries the value the device holds the same apply functions end with r.* = E::get() (kinds.h:56; examples/sila/src/kinds.h:19,43,73,88)
5. A command in presented units is rounded and read back gateway.py:72-78 (to_raw: nearest, halves away from zero), publish converts the report back (gateway.py:279..); ran on a Nano: SetValue(12.35) reads back 12.4
6. Forwarded once; nothing resent gateway.py:268 and :273 (m.push() once; fire sets the flag around exactly one push)
6. Whatever the device does when commands stop is its own examples/sila/src/main.cpp:3 ("There is no timeout: a value that was set stays set")
6. Serialised on the link one RLock around every push and poll: gateway.py:248, :260, :270, :280; ran: 20 concurrent Fire() + 20 SetLevel() → exactly +20
7. One process, one machine; UUID from originator + machine hash gateway.py:313 (one Machine), :249 (uuid5 of originator, server type and hash); the same firmware gave the same UUID on the host and on the Nano
Adding a kind: one row; unknown kinds refused gateway.py:57-66, :97
Adding a consumer, step 2: check against the protocol's schema the generated feature definitions were checked against the sila_base FDL schema (all of them valid; copies with a required element removed are rejected)

Statements that are design, not code, and so not checkable here: "a machine that a consumer can serve can be served by every other consumer that knows the same kinds" and "kinds and consumers grow independently".

Not changed: HAPI; any code.

🤖 Generated with Claude Code

neu-rah and others added 3 commits October 8, 2026 18:51
The rules any consumer follows (a table of kinds, generated self-description, refusal by name, validation at the edge with the device as backstop, holding
nothing, a stable identity) and how to add a kind or a consumer, with examples/sila as the worked example. Linked from the README and from role.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
… SiLA does

"The rules you meet": a value sent straight to the board is clamped by lamp (a light) and ignored by step, mode, note and duty, not ignored by all.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…hing consumer-specific" to a consumer on the other side of the link

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@neu-rah
neu-rah merged commit 3f5f308 into main Oct 8, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant