Skip to content

test_refused_write_settles.py silently skips HTTP-protocol control drivers #80

Description

@frahlg

drivers/tests/test_refused_write_settles.py only probes drivers whose manifest declares PROTOCOL == "modbus". It holds every Modbus control driver to the write-refusal-counting rule in docs/WRITING-A-DRIVER.md ("The same rule for writes"): count refusals, stop after N, report the default as held rather than failed.

nibe_local (PROTOCOL = "http", writes via host.http_patch) is the first HTTP-protocol driver to gain a write path — see #46 — and it falls through this check entirely, silently. In the current code, driver_default_mode has no bounded refusal counter: if the pump keeps refusing the clear write (e.g. left read-only on the pump side via installer menu 7.5.15), it retries every 60s indefinitely instead of counting to N and reporting the state as held, the way sungrow 1.5.7 does.

This gap applies to any future HTTP-protocol control driver, not just nibe_local — the check's protocol filter is the root cause, not the individual driver.

Ask: widen test_refused_write_settles.py (and refused-write-baseline.json bookkeeping) to also probe HTTP-protocol drivers that declare a write path, the same way it already does for Modbus. Surfaced during automated review of #46; filing separately since it's a pre-existing coverage gap in the test suite rather than something that PR's diff introduced.

Activity

  1. frahlg commented on Aug 31, 2026

    @frahlg
    MemberAuthor

    Status check, no code change: audited every currently-merged HTTP/websocket-protocol driver's driver_default_mode (the path this gap concerns) to see whether this is live exposure or still forward-looking.

    easee_cloud, tesla_vehicle, myuplink, esphome_dsmr, esphome-dsmr, zap, tibber — every one of their driver_default_mode functions is currently a no-op ("No-op — cloud charger manages itself.", "Read-only: nothing to release.", etc.). None of them write anything there today, so the untested path this issue describes has nothing to hide yet on main. This is still correctly scoped as blocking on #46 (nibe_local's solar-PV write path), which would be the first HTTP-protocol driver with an actual write in driver_default_mode — not an active gap on any shipped driver right now.

    Leaving this open and unclaimed; worth widening test_refused_write_settles.py/refused_write_probe.lua (protocol filter + host mock support for simulating an http_patch/http_post refusal) before or alongside #46, not urgently before it for unrelated drivers.


    Generated by Claude Code

  2. frahlg commented on Sep 16, 2026

    @frahlg
    MemberAuthor

    Status update, no code change: the gap this issue describes just went from forward-looking to live on main.

    #46 (nibe_local Solar PV write path) merged yesterday (f3771d7, 2026-09-15). Its driver_default_mode (drivers/lua/nibe_local.lua:739-751) now does exactly the unbounded-retry thing this issue warns about:

    function driver_default_mode()
        if not write_cfg.requested then return end
        if feed_last_w == nil or feed_last_w == 0 then return end
        local now = host.millis()
        if default_clear_ms and (now - default_clear_ms) < 60000 then return end
        default_clear_ms = now
        local ok, err = write_pv_surplus(0, "default mode")
        if not ok then
            host.log("warn", "NIBE: default-mode solar PV clear failed " ..
                "(will retry): " .. tostring(err))
        end
    end

    No refusal counter — on a pump where the clear write keeps failing (e.g. Local REST API left read-only via installer menu 7.5.15, or register 2107 not accepting the write), this logs a warn and retries every 60s for the life of the session. Same shape as the Sungrow SG12RT incident that motivated sungrow 1.5.7.

    And it's invisible to CI: confirmed drivers/tests/lua_harness/refused_write_probe.lua:87 still hard-codes if PROTOCOL ~= "modbus" then print("SKIP not modbus") return end, so test_refused_write_settles.py skips nibe_local outright rather than measuring it — make check is green with this gap sitting in a merged, live driver.

    This is no longer "worth widening before or alongside #46" — #46 is in, so the exposure is live now. Recommend prioritizing the PROTOCOL == "http" widening (+ a bounded refusal counter in nibe_local.driver_default_mode, mirroring sungrow's count-to-N-then-report-held pattern) rather than leaving it queued behind other work. Flagging for a maintainer — this is a control-path change so it should get the same hardware-evidence treatment as the rest of nibe_local's write path, not a same-day autonomous merge.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions