Skip to content

feat(drivers): accept the canonical driver spellings alongside the current ones#667

Merged
frahlg merged 1 commit into
masterfrom
accept-canonical-driver-names
Jul 25, 2026
Merged

feat(drivers): accept the canonical driver spellings alongside the current ones#667
frahlg merged 1 commit into
masterfrom
accept-canonical-driver-names

Conversation

@frahlg

@frahlg frahlg commented Jul 25, 2026

Copy link
Copy Markdown
Member

Summary

srcfl/device-drivers is the single source for our drivers and is converting
its catalog to the Blixt L1 host API and the @srcful/data-models emit keys.

Doing that in one step is not possible from the driver side. emitTelemetry
unmarshals "w" and returns emit_telemetry: %s missing required w when it is
absent, so the first converted driver would take its site's telemetry down.

This accepts both spellings, so neither repository has to move first.

What changed

host.emit reads W when w is absent, and SoC_nom_fract when soc is
absent. When both are present the lowercase key wins, so a driver that
emits both during conversion keeps the value it means as primary. Unknown
fields were already preserved verbatim in the reading's Data payload, so
nothing else about the shape changes.

Host functions write, write_registers and now_ms are registered as
aliases of modbus_write, modbus_write_multi and millis.

Nothing is removed. The older names keep working until the catalog has moved,
and the two sets can then be retired together.

Why these names

Blixt L1 is where the driver contract was worked through, so device-drivers
uses it as the naming reference and FTW adapts. Two details it gets right:

  • endianness belongs in the name — decode_u32_be, not decode_u32. FTW
    already agrees here; it registers only the _be and _le spellings.
  • @srcful/data-models uses W / SoC_nom_fract. Blixt reads each emit table
    by exact key and drops a mistyped key without an error, which makes case a
    contract rather than a convention.

Tests

go/internal/drivers/lua_canonical_names_test.go:

  • a driver emitting only canonical keys produces correct meter and battery
    readings, including SoC from SoC_nom_fract;
  • a driver emitting only lowercase keys is unchanged;
  • a driver emitting both keeps the lowercase value;
  • write, write_registers, now_ms and the three original names all resolve
    to functions, and now_ms returns the same kind of value as millis.

go test ./internal/drivers/ ./internal/telemetry/ ./internal/nova/ passes.

Not in this PR

set_model, set_rated_w, set_warmup_s and decode_string exist in Blixt
and not here. They are host services rather than arithmetic, so a driver cannot
supply them itself. They need their own change once we agree on the semantics.

Helpers that are pure arithmetic — decode_f32_be, decode_u64, scale — are
deliberately not added. The catalog now carries those in the driver's own
Lua, which is where device logic belongs and keeps the host surface smaller.

🤖 Generated with Claude Code

…rrent ones

srcfl/device-drivers is the single source for our drivers and is converting
its catalog to the Blixt L1 host API and the @srcful/data-models emit keys.
Doing that in one step is not possible: emitTelemetry unmarshals "w" and
rejects a payload without it, so the first converted driver would take its
site's telemetry down.

Accept both spellings instead, so neither side has to move first.

host.emit reads W when w is absent and SoC_nom_fract when soc is absent.
When both are present the lowercase key wins, so a driver that sets both
during conversion keeps the value it means as primary. Unknown fields were
already preserved verbatim, so nothing else changes.

write, write_registers and now_ms are registered as aliases of modbus_write,
modbus_write_multi and millis.

Nothing is removed. The older names keep working until the catalog has moved
and the two can be retired together.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
@frahlg
frahlg merged commit 86a6c83 into master Jul 25, 2026
11 checks passed
@frahlg
frahlg deleted the accept-canonical-driver-names branch July 25, 2026 15:52

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0c7a67a408

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +477 to +478
if env.SoC == nil {
env.SoC = env.CanonicalSoC

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Convert canonical vehicle SoC to percent

When a vehicle driver emits canonical SoC_nom_fract (for example, 0.87), this fallback stores it unchanged even though DerVehicle SoC uses the 0..100 percentage scale. telemetry.PickBestVehicle therefore interprets that reading as 0.87% rather than 87%, which can distort loadpoint planning and charging decisions; convert the fraction for DerVehicle while retaining fractional semantics for battery/V2X readings.

Useful? React with 👍 / 👎.

Comment on lines +464 to +465
CanonicalW *float64 `json:"W,omitempty"`
CanonicalSoC *float64 `json:"SoC_nom_fract,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Normalize canonical phase-current fields

When a site-meter driver completes the same canonical migration and emits L1_A/L2_A/L3_A without their lowercase counterparts, only W and SoC_nom_fract are recognized here and the canonical phase keys remain unchanged in DerReading.Data. control.perPhaseOverageW unmarshals only l1_a/l2_a/l3_a, so it sees no current and silently disables the per-phase breaker clamp while the meter otherwise appears healthy; accept these canonical aliases before storing the payload or teach the safety consumer both spellings.

AGENTS.md reference: AGENTS.md:L31-L31

Useful? React with 👍 / 👎.

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