firmware recipe
Logger shape that emits schema-valid sample lines for grow and harvester runs.
Not a full binary — a recipe any ESP32 / Pico / laptop logger can follow. Samples go JSONL during the run; wrap into a locus-lab-log/1 object at the end with environment.world for Earth / Moon / Mars / analog. Examples: /locus/runs · /locus/worlds.
Grow: ≥1 Hz electrical + G during comparison windows. Harvester: ≥1–10 Hz with drive_on. Channels listed on /locus/measure.
grow (P0–P3 samples)
// locus-logger grow sketch (Arduino/ESP32 shape)
// Emits one JSON object per line — locus-lab-log samples[]
#include <WiFi.h> // optional NTP
// INA219, SHT, lux as your wiring
const char* RUN_ID = "YYYYMMDD-HHMM-p0-slug";
const float DT_S = 1.0;
void setup() {
Serial.begin(115200);
// init sensors; optional configTime for UTC
}
void loop() {
float G = readIrradiance(); // W/m2 or lux_proxy
float V = readPanelV();
float I = readPanelI();
float P = V * I;
// optional P2:
// float Tw, RHw, Td, RHd, OD;
Serial.print("{\"t\":\"");
Serial.print(utcIsoNow());
Serial.print("\",\"G\":");
Serial.print(G, 1);
Serial.print(",\"V_pv\":");
Serial.print(V, 2);
Serial.print(",\"I_pv\":");
Serial.print(I, 3);
Serial.print(",\"P_pv\":");
Serial.print(P, 2);
Serial.print(",\"P_load\":");
Serial.print(readLoadP(), 2);
Serial.println("}");
delay((int)(DT_S * 1000));
}
// After the run: wrap samples into a locus-lab-log/1 object with
// schema, id, prototype, status, goal, parts, summary.
// Validate against /locus/lab-log.schema.json
resonance harvester (RP0 samples)
// locus-logger RP0 harvester sketch shape
// Channels: f_drive, f0, P_piezo, drive_on
const float F0_HZ = 1.01; // measure or estimate
const float DT_S = 0.1; // 10 Hz if MCU allows
void loop() {
bool drive_on = readDriveActive(); // foot switch, load cell threshold, or operator flag
float f_drive = drive_on ? F0_HZ : 0;
float P_piezo = readHarvestPowerW(); // V_harv * I_harv after rectifier
Serial.print("{\"t\":\"");
Serial.print(utcIsoNow());
Serial.print("\",\"f0\":");
Serial.print(F0_HZ, 3);
Serial.print(",\"f_drive\":");
Serial.print(f_drive, 3);
Serial.print(",\"P_piezo\":");
Serial.print(P_piezo, 4);
Serial.print(",\"drive_on\":");
Serial.print(drive_on ? "true" : "false");
Serial.println("}");
delay((int)(DT_S * 1000));
}
wrap to lab-log
{
"schema": "locus-lab-log/1",
"id": "YYYYMMDD-HHMM-p0-slug",
"prototype": "P0",
"scheme": "grow_your_own_energy",
"status": "pass",
"goal": "…fixed for the whole run…",
"parts": [{ "role": "pv", "model": "…" }],
"summary": { "energy_baseline_wh": 0, "energy_treatment_wh": 0 },
"samples": [ /* lines from Serial */ ]
}File under public/locus/runs/ and list in index.json. Kit wiring: /locus/kit.