Public: anyone can read this; the crew can change it.

Migrated from github.com/Trevato/SO-ARM100

Dosing: temperature and level sensor drivers (DS18B20, SHT31/BME280, float switches) as Reading sources #608

Merged opened this

Check · Review · Land done · Live — Landed; nothing deploys from this branch, so this is the end of its path.

Merged

This adds the sensor drivers and logs their readings into the grow log book. The dosing controller from #586 isn't on main, so nothing here talks to it yet. The new and related suites pass (148 tests, including `src/sensors.test.ts`) and the type check shows no errors in the files I touched; I didn't run the whole check, and I haven't tried any of the drivers on real hardware.

shipped merged

opened this

This adds the sensor drivers and logs their readings into the grow log book. The dosing controller from #586 isn't on main, so nothing here talks to it yet. The new and related suites pass (148 tests, including src/sensors.test.ts) and the type check shows no errors in the files I touched; I didn't run the whole check, and I haven't tried any of the drivers on real hardware.

  • Drivers (src/sensors.ts):

- ds18b20 reads the 1-Wire file for water temperature. It rejects a failed CRC and the power-on 85 °C value. - sht31 reads air temperature with i2ctransfer and checks the sensor's CRC. - bme280 reads air temperature with the datasheet compensation. - float reads a GPIO float switch with gpioget and reports level as 100 when wet and 0 when dry, with an activeLow option.

  • Config: the sensors are listed in sensors.json under FORGE_APP_DATA and validated on load. A bad file is ignored with a message on stderr.
  • Arm server: it reads the sensors every 60 s and serves them at GET /grow/sensors with each one's last value, time and error. One sensor failing doesn't stop the others.
  • Log book: the relay pulls the arm's readings every 10 min in bench/fake-serve.ts and in the startRelay option sensorsMs. They go through a new CareLog.addReading, which keeps at most one reading per kind per hour, checks the same limits as manual entries, and tags them source: "sensor". If the book is full, the oldest sensor reading is dropped first, so manual entries are never the ones lost.

The /grow/sensors route isn't owner-gated on the arm server, so any caller that reaches the arm can read it.

Closes #605

commented

This adds the sensor drivers and logs their readings into the grow log book. The dosing controller from #586 isn't on main, so nothing here talks to it yet. The new and related suites pass (148 tests, including src/sensors.test.ts) and the type check shows no errors in the files I touched; I didn't run the whole check, and I haven't tried any of the drivers on real hardware.

  • Drivers (src/sensors.ts):

- ds18b20 reads the 1-Wire file for water temperature. It rejects a failed CRC and the power-on 85 °C value. - sht31 reads air temperature with i2ctransfer and checks the sensor's CRC. - bme280 reads air temperature with the datasheet compensation. - float reads a GPIO float switch with gpioget and reports level as 100 when wet and 0 when dry, with an activeLow option.

  • Config: the sensors are listed in sensors.json under FORGE_APP_DATA and validated on load. A bad file is ignored with a message on stderr.
  • Arm server: it reads the sensors every 60 s and serves them at GET /grow/sensors with each one's last value, time and error. One sensor failing doesn't stop the others.
  • Log book: the relay pulls the arm's readings every 10 min in bench/fake-serve.ts and in the startRelay option sensorsMs. They go through a new CareLog.addReading, which keeps at most one reading per kind per hour, checks the same limits as manual entries, and tags them source: "sensor". If the book is full, the oldest sensor reading is dropped first, so manual entries are never the ones lost.

The /grow/sensors route isn't owner-gated on the arm server, so any caller that reaches the arm can read it.

Changes requested — before the latest push

The drivers are careful: CRC checks, the 85 °C power-on guard, strict config validation, injected commands, and one failing sensor stops nothing. Several items on the list are missing, though.

  1. Both doors / reachable. A person cannot see a sensor anywhere. There is no page card and no src/tty.ts command for the sensors' last values or errors. The only route is GET /grow/sensors on the arm server, and nothing proxies it to the relay or the page. A DS18B20 that is miswired shows nothing but a line on stderr. Fix first: add a sensors line to the grow/care card (label, value, 'last read N min ago' or the error) and the same in the tty, both through the relay's gating, with a test for each.
  2. README. Nothing says how to use it. The README has no sensors.json section: no file location, no example for each driver, no note that i2ctransfer and gpioget must be installed on the Pi, and no mention of the 1-Wire overlay.
  3. Tests. pullSensors in relay.ts has no test, and it is the only path that writes to the book. Nothing would fail if it were deleted or if it called the wrong URL. Add a relay test with a fake arm that serves /grow/sensors, and assert that bad entries are skipped and that a failing arm logs nothing. Also add a test for the full-book eviction in addReading, so a hand's entries are shown to survive. The current test never fills the book.
  4. Direction. Sensors going into the log book is reasonable. The bench fake-serve change is fine. The PR text says 'dosing' but the controller isn't there, so say plainly in the description that this only feeds the log book.

The unauthenticated /grow/sensors on the arm server matches the arm server's other reads. Once it is shown on the page, gate it on the relay like GET /grow.

commented

This adds temperature and level sensor drivers (DS18B20, SHT31, BME280, float switch) and logs their readings into the care log book. It does not touch the dosing controller from #586, which isn't on main. The new tests, the readme, terminal and light-endpoint suites pass, and the type check shows nothing in the touched files. I didn't run the whole check or try any driver on real hardware.

  • Drivers: each sensor is a reading source for water temperature, air temperature or water level. The list lives in sensors.json under FORGE_APP_DATA. The CRC checks, the 85 °C power-on guard and the validation of that file are unchanged from before.
  • Sensor values:

- The arm server reads the sensors every minute and serves them in GET /grow (and GET /grow/sensors). - The relay pulls the last good reading of each into the care log book, at most one per kind per hour, marked as a sensor's. - The pull is a relay option, sensorsMs, which only bench/fake-serve.ts sets (every 10 minutes).

  • Seeing it:

- /admin → Grow has a "Sensors" list. Each line shows the value and how long ago it was read, or the error, for example a miswired probe "not on the 1-Wire bus". - The terminal's /grow prints the same lines. - The sensors ride in GET /grow, so both go through the relay's existing owner-only gating; readGrow skips malformed entries, and the page escapes the labels.

  • Readme: a new "Sensors" section covers where sensors.json goes, an example for each driver, the 1-Wire overlay and wiring, and that i2c-tools (i2ctransfer) and gpiod (gpioget) must be installed on the Pi.
  • Tests:

- src/sensors-relay.test.ts runs a relay against a fake arm. Good readings are logged, bad ones (out of range, wrong type, unknown kind, null) are skipped, and an arm that has gone away logs nothing. - A full-book test shows only sensor readings are evicted and a hand's entries survive. With none left to evict, addReading throws. - Further tests cover the sensor line, the card and terminal output, and GET /grow carrying the sensors.

I left GET /grow/sensors unauthenticated on the arm server, like its other reads. Nothing a person reaches serves it unguarded, because the card and terminal use the gated /grow.

🤖 Generated with Claude Code

Approved

Approved from the diff and tests. The preview has no sensors.json and /grow is owner-only, so I could not see the card there. The drivers are validated at the boundary, the CRC and 85 °C guards are tested, and the card and terminal escape and bound what they show. They share the gated /grow path, so the terminal matches the page. The log book never loses a hand-written entry, and the README covers wiring and setup.

Two things to do next:

  1. Guard Sensors.tick against overlap. If i2ctransfer or gpioget hangs, a 60 s interval will stack reads. Skip a tick while one is still running, and cap the run time.
  2. Make pullSensors check options.care explicitly instead of relying on the inner catch to swallow a TypeError. Also move the .sensors li.bad colour onto the page's existing error token so the design lint and contrast checks cover it.

Smaller point: GET /grow/sensors on the arm server is unauthenticated like its other reads, and nothing public reaches it. If the arm server ever faces a network wider than the relay, gate it.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs