Skip to content

Redesign dual-master architecture: independent per-controller intake/exhaust buses + unified firmware #26

Description

@TalkingJupiter

Context

Today the two controllers (A/B) share a single physical sensor-bus pair — one intake OneWire
chain (ONE_WIRE_BUS_INTAKE=4) and one exhaust chain (ONE_WIRE_BUS_EXHAUST=21). Access is
arbitrated by RelayControl::BusOwner (NONE/A/B), which RoleManager claims/releases on
failover, so only one controller is electrically connected to the sensors at any moment. The two
firmware images differ only by a compile-time -DDEVICE_ID (A=65 / B=66).

Problem

The shared/switched bus is a single point of failure: a bad switch, stuck relay, or fault on the
shared harness takes out sensing for both controllers. It also couples "who can read sensors"
to "who transmits," and adds arbitration complexity (claim/release, settle delays) that exists
only because the bus is shared.

Proposal

Separate the two masters electrically. Each controller gets its own dedicated intake + exhaust
OneWire buses with direct, unswitched access to its own sensors — no SPDT handoff, no BusOwner
arbitration. Heartbeat failover then governs only telemetry transmit ownership, decoupled from
sensor access.

Decisions (resolved)

  • Sensor placement: co-located redundant. A's sensor N and B's sensor N sit at the same
    physical intake/exhaust point, so the two controllers read the same airflow points independently.
  • SPDT/relay switches: fully removed from the BOM — the design has no switches.
  • Firmware image: unified into one image; no compile-time A/B (DEVICE_ID dropped). The host
    assigns identity/role at runtime.
  • Host-unreachable fallback: since identity now comes from the host, if the host is
    unreachable we require a manual write to the DB (device_map MAC→rack_id/role) to identify/
    provision a device out-of-band.

Tasks

  • Finalize wiring diagram + BOM: two independent intake+exhaust OneWire pairs (one per
    controller), sensors co-located per index; switches removed
  • Unify firmware image — drop -DDEVICE_ID from platformio.ini and the DeviceConfig.h
    #error guard; remove INTAKE_SWITCH_PIN/EXHAUST_SWITCH_PIN; give each controller its
    own intake+exhaust OneWire pins
  • Retire RelayControl BusOwner switching and the claim/release + settle logic in
    RoleManager; each controller reads its own TemperatureBus directly
  • Decide standby sensing/telemetry: both report their own readings (dual redundant telemetry
    of the same points) vs standby silent per current failover rule; update schema accordingly
  • Add host-unreachable fallback: documented manual DB write procedure for identity/role
    (device_map) so devices can be provisioned out-of-band
  • Update README "Sensor Bus Configuration" + wiring docs for two independent bus pairs

Files affected

  • ESP32-Firmware/platformio.ini — collapse esp32_a/esp32_b (currently differ only by DEVICE_ID) into one image
  • ESP32-Firmware/include/DeviceConfig.h — remove DEVICE_ID #error guard, INTAKE_SWITCH_PIN/EXHAUST_SWITCH_PIN; per-controller OneWire pins
  • ESP32-Firmware/src/RoleManager.cpp + include/RoleManager.h — remove bus claim/release/settle logic
  • ESP32-Firmware/src/RelayControl.cpp + include/RelayControl.h — remove BusOwner sensor-bus switching
  • ESP32-Firmware/src/TemperatureBus.cpp + include/TemperatureBus.h — per-controller bus init/read
  • ESP32-Firmware/src/main.cpp — telemetry assembly (buses[] inlet/exhaust), failover gating, runtime identity
  • README.md — "Requirements: Sensor Bus Configuration" + wiring
  • Connecting_ESP32_Telemetry_to_Radxa.md, docs/mqtt-contract.md — if sensor payload buses / provisioning change

Acceptance criteria

  • Wiring diagram/BOM shows two independent intake+exhaust bus pairs, sensors co-located per index, no switches.
  • A single unified firmware image runs on both controllers; identity/role assigned by the host at runtime.
  • Firmware reads each controller's own bus with no SPDT/BusOwner arbitration.
  • Documented manual-DB fallback exists for host-unreachable provisioning.
  • README Sensor Bus Configuration requirements updated to match.

Relates to #11 (config schema), #12 (provisioned role), #24 (broker bootstrap).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions