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

Migrated from github.com/Trevato/SO-ARM100

workbenchthis machine

Grow light schedule: a switch driver (smart plug, GPIO relay, or uhubctl only when it switches the light alone) with a photoperiod that runs on the Pi #582

shipped merged opened this has it
opened this

Part of the workshop issue. Owner: "setup the light schedule probably by turning the power off and on for the light!"

The hardware truth (probe this first, write it in the README): a Pi 4 cannot switch one USB port alone. uhubctl toggles all USB ports together (ganged on the VL805, and on this external VIA hub, check uhubctl -l 1-1). Cutting the light that way also cuts both cameras.

So the light switch is a driver behind one interface Switch { on(), off(), state() }, with these drivers:

  • uhubctl: only when the light is on a port that switches alone, which the check proves at setup (it lists which devices would drop). It refuses if a camera shares the switch.
  • shelly / tapo: a smart plug on the LAN (local HTTP; no cloud account). This is the recommended path; about $15.
  • gpio: a relay on a GPIO pin (libgpiod), for a 5 V relay module.

Done when:

  1. A schedule per light (photoperiod: on at 06:00, 16 h, in the Pi's timezone; spinach likes 12–16 h), set on /admin and shown on the grow card as "On until 22:00" or "Off until 06:00", with a manual override that expires at the next transition.
  2. The schedule runs on the Pi (systemd timer or the app's own clock with catch-up after a reboot: on boot, set the state the schedule says now). It never depends on the forge or the network.
  3. Every transition is logged (time, state, cause: schedule, override or boot) and shown as a strip on the grow card.
  4. Until a switch is configured, the card says "Light: always on (no switch set up)" with a link to the setup.
  5. Tests use a fake Switch: the schedule math across midnight and DST, reboot catch-up, override expiry, and the uhubctl driver refusing when a camera shares the port.
commented

Correction (steward, from research): the spinach default photoperiod is 12 h, capped at 14 h. Spinach is long-day sensitive: older lines bolt at 14 h or more, modern lines at about 16 h (Organic Seed Alliance manual; UAF). Cornell runs 16–24 h only for a 14–16 day baby-leaf crop where bolting does not matter. The schedule default is 06:00 + 12 h; the UI warns above 14 h for spinach.

commented

Also a pump (owner: the target system is a vertical tower, see #585): the Switch interface and schedule must support interval cycles (N min on / M min off) as well as a daily photoperiod, with one schedule per switch and both shown on the grow card.

commented

Night light caution (owner asked whether turning the shop light on affects growth): spinach is photoperiod-sensitive, so room light during its dark period can count as day and push bolting. The grow card shows "Dark period: keep room lights off" during the schedule's off-hours, and photos in the dark period use only a ≤2 s photo light (if one is set up).

commented

Already done on main in 82337a2 (#596): the daily photoperiod in the Pi's time zone (light-schedule.ts), the shelly, gpio and uhubctl drivers behind the Switch interface, with uhubctl refusing a ganged hub with a camera on it (light-switch.ts), the grow card with "Dark period: keep room lights off" (light-panel.ts), the owner-only /grow routes and terminal door, and the README Grow section. The pump came in the same commit. Pull #588 is now narrowed to one stricter body-cap test. A person can close this issue as done; my token is refused the close.

commented

Planner: not split. There is nothing left to build. This issue is at its run cap because every run finds the work already on main in 82337a2 (#596), as my note above says. The stricter body-cap test is now #600. Splitting would only hand builders finished work again. My done close is refused (forbidden, missing scope), so a person needs to close this as done. I removed #586's wait on it, so this issue holds nothing up now.

commented

Planner, 2026-10-27. State: done, but I can't close it. The work is on main in 82337a2 (#596) and 0ea35e6 (#599, the switch driver and photoperiod this issue names). My close as done is refused (forbidden: my credentials lack the scope). There is nothing left to split, so a person needs to close this as done. It holds nothing up.

commented

Planner, 2026-10-27 (run 2): done, waiting for a person to close it. I tried the close as done again just now and got forbidden ("your credentials lack the scope for this action"). The work is on main in 82337a2 (#596) and 0ea35e6 (#599). I did not split it: there is nothing left to build, so a split would only hand finished work back to a builder. It holds nothing up.

commented

Planner, 2026-10-27 (run 3): done, waiting for a person to close it. I retried the close as done just now and it was again refused with forbidden (missing scope). The work is on main in 82337a2 (#596) and 0ea35e6 (#599). There is nothing to split, and it holds nothing up.

commented

Hardware facts from the Pi (steward, 2026-10-27 02:40Z):

  • The grow light is power-only on hub 1-1, port 2 or 4. The cameras are on 1-1 port 1 (XWF-1080P) and port 3 (eMeet C960).
  • uhubctl -l 1-1 -p 2,4 -a off reported off, but the light stayed on (the owner checked). The uhubctl README confirms the RPi 4B hub 1-1 has "4 ports ganged, dual to USB3 hub 2", and the VL805 firmware is up to date. The driver's refusal is correct on this Pi.

The plan: a uhubctl-listed hub with real per-port switching. The README lists the UUGear MEGA4 (for Raspberry Pi 4B), 4 ports, USB 3.0. With the light on its own MEGA4 port, {driver:"uhubctl", hub:<MEGA4 location>, port:<n>, cameras:[]} passes verify().

Setup check: it toggles the configured port off for 2 s, checks that no listed camera disappeared from lsusb, and asks the owner to confirm "did the light go off?" in the app before saving the switch. It notes in the UI that a port showing "off" isn't proof on ganged hubs.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs