Appendix¶
Comprehensive reference material for GenMaster operators — troubleshooting tables, command cheat sheets, state machine details, file locations, and recovery procedures.
Troubleshooting¶
Generator won't start¶
| Symptom | Likely cause | Action |
|---|---|---|
| Start button is grayed out | System is disarmed | Toggle Generator Run Relay to Armed on the Generator Control page. |
| Click Start, nothing happens | GenSlave is offline | Check GenSlave for ONLINE status. Restart the slave container or fix WiFi. |
| Start command returns error toast | API secret mismatch | Re-save secret on both ends via GenSlave → Connection Settings. |
| Generator starts then stops within seconds | Run Time Limits min-time set high but Victron released signal early | Check Run Time Limits. |
| Generator starts but won't pull load | Hardware issue (transfer switch, wiring) | Outside GenMaster's scope — check generator + ATS manuals. |
Generator won't stop¶
| Symptom | Likely cause | Action |
|---|---|---|
| Stop button does nothing | GenSlave offline | Use Emergency Stop which bypasses normal flow. If that fails too, manually open the breaker. |
| Generator restarts after stop | Victron signal still HIGH | Enable Manual Override until Victron releases. |
| Stop command 200 but generator runs | Relay wired NC instead of NO, or relay stuck | Check Pimoroni Automation Hat Mini wiring; replace if a relay contact is welded. |
GenSlave shows OFFLINE¶
| Likely cause | Action |
|---|---|
| Pi Zero powered off | Verify physical power, indicator LEDs. |
| WiFi dropped | Check router for the genslave device; check WiFi Watchdog status in System and on GenSlave page. |
| API secret rotation drift | Re-save secret on both ends from GenSlave → Connection Settings. |
| Tailscale issue (if used) | tailscale status on both ends. |
| Heartbeat firewall block | Verify nothing on the network is blocking outbound TCP from GenMaster to the slave's :8001. |
| Container crashed | SSH the slave: cd /opt/genslave && docker compose logs --tail=100 genslave. |
Victron signal not detected¶
| Likely cause | Action |
|---|---|
| Wiring loose | Reseat Cerbo GX Relay 1/2 to GPIO17 + GND on the Pi 5. |
| Wrong relay polarity | In Cerbo settings, Relay function should be Generator start/stop. The contact should close on Generator wanted. |
| GPIO permissions | Verify GenMaster container has privileged: true and /dev/gpiochip0 mapped. |
| GPIO17 in use elsewhere | No other process or HAT should be claiming GPIO17. |
| Cerbo SOC threshold not crossed | Check Cerbo's battery monitor — if SOC is above the trigger threshold, the relay won't close. |
Database connection failed¶
| Likely cause | Action |
|---|---|
genmaster_db container not running |
Containers → start genmaster_db. |
DATABASE_PASSWORD mismatch |
Verify in Settings → Environment; should match genmaster_db's POSTGRES_PASSWORD. |
| Postgres data volume corrupt | Restore from backup downloaded earlier — see Backup / restore below. |
| Disk full | Check System → Health Host Disk metric; clear old logs/Docker images. |
Web UI inaccessible¶
| Symptom | Likely cause | Action |
|---|---|---|
| Browser timeout | Cloudflare tunnel down or Tailscale down | Try the LAN IP directly. Check genmaster_cloudflared and genmaster_tailscale containers. |
| HTTPS cert error | Let's Encrypt cert expired | System → Health → SSL Certificates → Force Renew. |
| 502 Bad Gateway | genmaster API container down/unhealthy |
Restart genmaster from Containers. |
| 403 Forbidden | Your IP isn't in the allowed Access Control list | Add your IP via Settings → Access Control (or temporarily disable geo-block for diagnosis). |
| Stuck "loading..." spinner | Backend reachable but DB query hung | Restart genmaster_db, then genmaster. |
Notifications not arriving¶
| Symptom | Likely cause | Action |
|---|---|---|
| No notifications, channels show ✓ Success | Cooldown timers active | GenSlave → Notification Settings → Clear cooldown timers (master cooldowns are similar). |
| Channel shows × Failed | Wrong URL, expired token, blocked sender | Click the test (▷) button on that channel to see the error message. |
| Email channel keeps failing | TLS misconfig or auth issue | Confirm SMTP host/port and that the username has SMTP-send permissions (some providers require an app password). |
| Apprise URL not working | Service-specific URL syntax | See the Apprise wiki for the exact format. |
Schedules not firing¶
| Symptom | Likely cause | Action |
|---|---|---|
Schedule status shows Pending long after expected fire time |
System was disarmed at trigger time | Re-arm and wait for next occurrence. The skip is recorded in Run History. |
| Schedule fires but generator doesn't run | GenSlave offline | Same as "GenSlave shows OFFLINE" above. |
| Wrong day or wrong time | Server timezone mismatch | Check TZ env var on genmaster container — should match your physical location. |
State machine reference¶
GenMaster's state machine has these states. Transitions are driven by Victron, schedules, manual commands, and timeouts.
| State | Description | Typical exit conditions |
|---|---|---|
| idle | Generator off, no run in progress. | Victron signal goes HIGH, schedule fires, or manual start. |
| starting | Start command sent to GenSlave. Waiting for relay confirmation. | Relay confirmed (→ running) or timeout (→ failed). |
| running | Generator is on. Heartbeat continues, runtime accumulates. | Victron signal goes LOW, schedule duration elapsed, manual stop, or runtime limit hit. |
| stopping | Stop command sent. Waiting for relay to open. | Relay confirmed off (→ cooldown) or timeout (→ failed). |
| cooldown | Brief post-stop period (configurable, default 60s). Prevents short-cycling. | Cooldown elapsed → idle. |
| failed | Start or stop returned an error. State persists until acknowledged. | Manual reset via API or UI clears to idle. |
A run is recorded when the state machine transitions starting → running and closed when it transitions out of running (to stopping or failed).
Event types reference¶
Events that can fire notifications (configurable on the Notifications → Configure tab):
| Event | Fires when |
|---|---|
generator.starting |
Start command issued. |
generator.started |
Generator confirmed running. |
generator.stopping |
Stop command issued. |
generator.stopped |
Generator confirmed off. |
generator.failed |
Start or stop command returned an error. |
generator.exercise_started |
An exercise run kicked off. |
generator.exercise_completed |
An exercise run finished normally. |
system.armed |
Operator armed the system. |
system.disarmed |
Operator disarmed. |
system.boot_reset |
GenMaster booted and reset state to safe defaults. |
slave.online |
Heartbeat resumed after being lost. |
slave.offline |
Heartbeat lost (configurable threshold). |
slave.failsafe_triggered |
Slave's independent failsafe forced relay OFF. |
victron.signal_high |
GPIO17 went HIGH (Victron requesting generator). |
victron.signal_low |
GPIO17 went LOW (Victron releasing). |
victron.signal_ignored |
Signal received while disarmed (logged-only). |
scheduled_run.fired |
Schedule trigger fired. |
scheduled_run.skipped |
Schedule fired but was skipped (disarmed, slave offline, etc.). |
scheduled_run.completed |
Scheduled run completed. |
notification.test |
Operator triggered a test notification. |
system.cert_expiring |
SSL cert is within 14 days of expiring. |
system.disk_low |
Host disk usage above 90%. |
system.memory_high |
Host memory usage above 90% sustained for >60s. |
Hardware-switch events¶
Added with the optional EPO + HOA hardware switches. See Hardware Switches for the operator guide and Notifications for routing.
| Event key | Severity | Triggered by |
|---|---|---|
hardware_safety_engaged_genslave |
warning | GenMaster detects EPO has been engaged (via heartbeat or fast-poll). |
hardware_safety_released_genslave |
info | EPO transitions back to released. |
quiet_mode_engaged_genmaster |
info | HOA selector flipped to Quiet (after the boot delay). |
quiet_mode_released_genmaster |
info | HOA selector flipped out of Quiet. |
quiet_override_enabled |
info | Operator started a Quiet override window from the Generator page. |
manual_run_started_genmaster_switch |
info | HOA selector flipped to Run and a run started. |
manual_run_ended_genmaster_switch |
info | HOA selector flipped out of Run, ending the run. |
manual_run_reminder |
info | A long-running manual or HOA-Run run hit the configured reminder milestone (default 2h). |
manual_run_blocked_by_safety |
warning | A start attempt was refused because the EPO was engaged. Also fires for HOA Run that was refused. |
auto_run_suppressed_by_quiet |
warning | An automation trigger (Victron / schedule / exercise) was suppressed by HOA Quiet without an override. |
genmaster_boot_hardware_state |
warning | One-shot ~20 s after boot if the hardware came up in a non-default state (EPO engaged or HOA != Auto). A fully-normal boot fires nothing. |
Several internal events also exist that are logged but not operator-routable: QUIET_OVERRIDE_EXPIRED, QUIET_OVERRIDE_CANCELLED (with reason = operator_cancel | hoa_left_quiet), MANUAL_RUN_RECLASSIFIED_BY_HOA, HOA_RUN_START_REFUSED. These appear in application logs only — wire them up through the regular state-change events above if you need operator notification.
Default ports¶
| Service | Internal port | External access | Notes |
|---|---|---|---|
| Nginx | 443 | Yes (HTTPS only) | Main entry point. HTTP→HTTPS redirect on 80. |
| FastAPI (GenMaster) | 8000 | No (internal) | Reverse-proxied through Nginx. |
| PostgreSQL | 5432 | No (internal) | Container-only. |
| Redis | 6379 | No (internal) | Container-only. |
| GenSlave API | 8001 | LAN / Tailscale only | Pi Zero 2W. Never expose publicly. |
| Portainer | 9000 | /portainer/ path |
Optional, gated by Nginx. |
| Cloudflared | (outbound) | Tunnel-only | Outbound HTTPS to Cloudflare edge; no incoming port. |
| Tailscale | UDP 41641 | (mesh) | WireGuard-based. |
| WiFi Watchdog | (host service) | None | Local-only systemd service. |
Environment variables — hardware switches¶
.env settings introduced with the optional EPO + HOA feature. Defaults match a clean install on dedicated hardware; change them only if your build deviates. Pin assignments can also be edited interactively from System → Hardware → GPIO Assignments (which writes the same .env keys).
| Variable | Service | Default | Purpose |
|---|---|---|---|
HARDWARE_SAFETY_ENABLED |
GenSlave | true |
Master toggle for the EPO monitor. Set false to skip startup if the EPO isn't wired yet. The NC contact in the start-relay circuit still works regardless — disabling only stops the LCD/notification side. |
HOA_SWITCH_ENABLED |
GenMaster | true |
Master toggle for the HOA monitor. Set false to disable; the system then behaves as if the selector were always in Auto. |
HOA_GPIO_QUIET |
GenMaster | 22 |
BCM pin for the Quiet-position NO contact. |
HOA_GPIO_RUN |
GenMaster | 27 |
BCM pin for the Run-position NO contact. |
HOA_BOOT_DELAY_SECONDS |
GenMaster | 30 |
Post-boot grace window before the HOA position is honored — avoids spurious state-change notifications if the selector happens to be in Quiet or Run when GenMaster starts. Set 0 for bench testing. |
VICTRON_GPIO_PIN |
GenMaster | 17 |
BCM pin for the Cerbo GX generator-request relay. Pre-existing in the project but compose-wired alongside the HOA pins so all three operator-side inputs flow through .env consistently. |
GenMaster also gains two non-hardware DB-backed config columns surfaced under the same area:
| Config column | Default | Purpose |
|---|---|---|
manual_run_reminder_enabled |
true |
Master toggle for the manual-run reminder timer. |
manual_run_reminder_interval_hours |
2 |
How often to fire the manual_run_reminder notification during a long-running manual or HOA-Run run. |
Changes to HOA_GPIO_QUIET, HOA_GPIO_RUN, or VICTRON_GPIO_PIN require a GenMaster restart — the pins are bound when the monitors start. The GPIO Assignments panel shows a "Restart required" banner with the still-running pins until the container restarts.
Schema migrations — hardware switches¶
Alembic migrations introduced with the optional EPO + HOA feature. Apply with docker compose exec genmaster alembic upgrade head.
| Revision | Adds |
|---|---|
| 015 | system_state.slave_physical_safety_engaged (boolean, nullable) — caches the EPO state GenSlave reports via heartbeat. |
| 017 | Updates three CHECK constraints (chk_run_trigger on system_state, chk_trigger_type and chk_stop_reason on generator_runs) to accept local_switch_genmaster, local_switch_genmaster_end, and hoa_quiet. |
| 018 | Widens system_state.run_trigger, generator_runs.trigger_type, and generator_runs.stop_reason from VARCHAR(20) to VARCHAR(40). Required because local_switch_genmaster (22 chars) and local_switch_genmaster_end (26 chars) exceed the original 20-char limit — 017 added the values to the CHECK constraints but the column width was overlooked. |
| 019 | system_state.quiet_override_active (boolean) and system_state.quiet_override_expires_at (int, nullable) — persistent state for the Quiet web override. |
| 020 | Seeds 10 notification-event rows into system_notification_events using INSERT ... ON CONFLICT DO NOTHING. Mirrors DEFAULT_SYSTEM_NOTIFICATION_EVENTS in the model. |
| 021 | Adds config.manual_run_reminder_enabled and config.manual_run_reminder_interval_hours; seeds the genmaster_boot_hardware_state event row. |
| 022 | Adds system_notification_global_settings.rate_limit_alert_sent (boolean, default false) so the "Rate Limit Exceeded" emergency-contact alert fires at most once per hour window instead of on every suppressed notification. |
Migration 016 was intentionally skipped — 017 and 018 shipped before the Quiet override design landed; the linear chain is 014 → 015 → 017 → 018 → 019 → 020 → 021 → 022.
File and directory locations¶
On the GenMaster host¶
| Path | Purpose |
|---|---|
/root/pizero_generator_control/genmaster/ |
Compose stack root. docker-compose.yaml, .env, scripts. |
/root/pizero_generator_control/genmaster/.env |
Environment configuration (DB password, API secrets, Cloudflare token, etc.). |
/var/lib/docker/volumes/genmaster_postgres_data/ |
Postgres data directory. |
/var/lib/docker/volumes/genmaster_redis_data/ |
Redis persistence. |
/var/lib/docker/volumes/genmaster_nginx_certs/ |
Let's Encrypt certificates. |
/var/lib/docker/volumes/genmaster_app_logs/ |
Application log files. |
/var/lib/docker/volumes/genmaster_backups/ |
Database / config backups. |
Inside the genmaster container¶
| Path | Purpose |
|---|---|
/app/ |
Backend Python source. |
/app/logs/ |
Application logs (mounted from host volume). |
/app/data/ |
Runtime SQLite cache (if used). |
/app/alembic/ |
Database migration scripts. |
On the GenSlave host¶
| Path | Purpose |
|---|---|
/opt/genslave/ |
Compose root. |
/opt/genslave/.env |
Slave-side env (must contain matching API_SECRET). |
/opt/genslave/data/ |
Optional SQLite cache. |
/opt/genslave/logs/ |
Slave application logs. |
Useful commands¶
GenMaster host (SSH'd to the Pi 5)¶
# View logs from each service
docker compose logs --tail=100 genmaster
docker compose logs --tail=100 genmaster_nginx
docker compose logs --tail=100 genmaster_db
# Restart a single service
docker compose restart genmaster
# Restart the entire stack
docker compose down && docker compose up -d
# Pull new image and recreate (after a release)
docker compose pull genmaster
docker compose up -d --force-recreate genmaster
# Apply pending DB migrations
docker compose exec genmaster alembic upgrade head
# Reset admin password
docker compose exec genmaster python -m app.cli reset_password admin
# Open a Postgres shell
docker compose exec genmaster_db psql -U genmaster -d genmaster
# Tail nginx access log
docker compose exec genmaster_nginx tail -f /var/log/nginx/access.log
# Force renew Let's Encrypt certs
docker compose exec genmaster_certbot certbot renew --force-renewal
# Check Tailscale status
docker compose exec genmaster_tailscale tailscale status
# Check Cloudflare tunnel
docker compose logs --tail=50 genmaster_cloudflared
GenSlave host (SSH'd to the Pi Zero)¶
cd /opt/genslave
# View logs
docker compose logs --tail=100 genslave
# Restart slave
docker compose restart genslave
# Pull new image
docker compose pull && docker compose up -d
# Check relay GPIO state directly (bypass API)
gpioget gpiochip0 16
From GenMaster, addressing the slave¶
# Test heartbeat reachability
curl -H "X-API-Key: $SLAVE_API_SECRET" http://genslave.local:8001/api/health
# Force relay OFF (bypasses normal arming flow)
curl -X POST -H "X-API-Key: $SLAVE_API_SECRET" \
http://genslave.local:8001/api/relay/off \
-d '{"force": true}'
Backup / restore¶
Creating a backup¶
GenMaster includes a one-click backup at Settings → Environment → Download Full Backup (gated behind the Danger Zone confirmation). The backup is a tar.gz containing:
- The Postgres database dump.
- The current
.envfile (sensitive — store securely). - The current
nginx.confand any custom Access Control rules. - A
restore.shscript that walks the operator through restoration.
Backups are timestamped: genmaster_full_backup_YYYY-MM-DDTHH-MM-SS.tar.gz.
You can also trigger a database-only backup from the host:
docker compose exec -T genmaster_db pg_dump -U genmaster -F c genmaster > genmaster_$(date +%Y%m%d).dump
Restoring¶
For a full system restore from a backup archive:
# 1. Stop the stack
cd /root/pizero_generator_control/genmaster
docker compose down
# 2. Extract backup
tar -xzf genmaster_full_backup_YYYY-MM-DD.tar.gz -C /tmp/restore
# 3. Run the included restore.sh (it walks you through DB + .env + nginx.conf restore)
sudo bash /tmp/restore/restore.sh
# 4. Start the stack
docker compose up -d
For a database-only restore:
docker compose exec -T genmaster_db psql -U genmaster -d genmaster -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"
docker compose exec -T genmaster_db pg_restore -U genmaster -d genmaster < genmaster_20260115.dump
docker compose restart genmaster
Recovery from unbootable web UI¶
If you've broken the web UI (e.g. typo in .env, bad nginx config) and can no longer reach /, here's the recovery flow. SSH access is required.
# 1. SSH to the GenMaster host
ssh user@genmaster.local # or its Tailscale name
# 2. Navigate to the install directory
cd /root/pizero_generator_control/genmaster
# 3. Identify what's broken
docker compose ps # which containers are unhealthy?
docker compose logs --tail=100 genmaster
docker compose logs --tail=100 genmaster_nginx
# 4. If .env was the problem, restore from your last backup:
ls /var/lib/docker/volumes/genmaster_backups/_data/
cp /var/lib/docker/volumes/genmaster_backups/_data/genmaster_full_backup_<timestamp>.tar.gz /tmp/
tar -xzf /tmp/genmaster_full_backup_<timestamp>.tar.gz -C /tmp/restore
cp /tmp/restore/.env /root/pizero_generator_control/genmaster/.env
# 5. Restart
docker compose down && docker compose up -d
Performance tuning¶
When GenMaster is sluggish¶
| Symptom | Tuning |
|---|---|
| Web UI slow to load | Check System → Host Resources — if CPU >80% sustained, restart genmaster. |
| Frequent timeouts | Default Heartbeat Interval is 10s (failsafe at 30s). Raise it if you're seeing network noise; lower (e.g. 5s) for faster failure detection. Failsafe scales as 3× the interval. |
| Database slow | VACUUM FULL rarely needed but can help: docker compose exec genmaster_db psql -U genmaster -d genmaster -c 'VACUUM FULL ANALYZE;' |
| Disk filling up | Old run history accumulates. Either purge from the DB or increase disk. The run-history table is the largest contributor. |
Tuning the Pi Zero 2W (GenSlave)¶
The Pi Zero 2W has only 416MB usable RAM. Watch for:
- Memory above 80% for sustained periods → reboot (or add a swap file).
- WiFi signal below -75 dBm → relocate or add an antenna.
- CPU temp above 70°C → improve airflow / add a small heatsink.
The slave's stat panel on GenSlave shows all of these live.
Glossary¶
| Term | Definition |
|---|---|
| Apprise | Notification library supporting 80+ services via URL strings. See Apprise wiki. |
| Armed / Disarmed | Whether GenMaster will respond to automation triggers. Disarmed = read-only / monitoring mode. |
| APScheduler | Python scheduling library used for the cron-driven run scheduler. |
| ATS | Automatic Transfer Switch — the device that switches loads between grid/generator. Outside GenMaster's scope. |
| Cerbo GX | Victron Energy's central monitoring/control device for off-grid solar systems. Provides the GPIO signal that asks GenMaster to start the generator. |
| Cooldown | A short post-stop period before the state machine will accept a new start command, preventing rapid cycling. Default 60s. |
| Failsafe | Independent watchdog on GenSlave that forces the relay OFF if it stops hearing from GenMaster for a configured timeout. |
| GenMaster | The Raspberry Pi 5 running the FastAPI backend, web UI, scheduler, and Victron GPIO listener. The "brain". |
| GenSlave | The Raspberry Pi Zero 2W running the relay controller and failsafe. The "muscle". |
| GPIO17 | The Pi 5 pin (physical pin 11) that listens for the Victron Cerbo GX relay signal. |
| Heartbeat | Periodic message GenMaster sends to GenSlave to confirm liveness and sync arming state. Default interval 10s; GenSlave's failsafe trips at 3× this (30s by default). |
| HMAC | Hash-based message authentication code; used to sign webhook payloads so receivers can verify they came from GenMaster. |
| HAT (Pimoroni Automation Hat Mini) | The add-on board on GenSlave that provides the physical relay and small LCD. |
| Manual Override | Mode where GenMaster ignores the Victron GPIO signal completely. Use during maintenance or when Victron is misreporting. |
| mock GPIO | Development mode where GenMaster simulates GPIO signals via API endpoints (no real Pi hardware needed). |
| Run | A single instance of the generator being on, from start command to stop. Recorded in Run History. |
| SOC | State of Charge — battery percentage. Cerbo GX uses SOC thresholds to decide when to ask for the generator. |
| State machine | The backend logic that transitions the system through idle → starting → running → stopping → cooldown → idle. |
| Tailscale | Mesh VPN used to give GenMaster, GenSlave, and your phone secure access to each other from anywhere. |
| Trigger | What caused a run to start: Victron Auto-Start, Scheduled Run, Manual Start, Exercise Run. |
| WAL (Write-Ahead Log) | Postgres's crash-safety mechanism. Don't disable it. |
| WiFi Watchdog | Host service on GenMaster that pings a known target and bounces the WiFi interface on connectivity loss. |
Security flag index¶
The following pages contain screenshots or fields with sensitive values you may want to mask before sharing externally:
| Page | What to mask |
|---|---|
| GenSlave | LAN IP, Tailscale IP, MAC address, WiFi SSID, API secret, Apprise URLs. |
| Generator Control | Generator serial number (some manufacturers use it as a service-portal credential). |
| Notifications → Channels (expanded) | Apprise URLs always contain bot tokens / webhook secrets. SMTP credentials in Email channels. To/From addresses. |
| System → Network | All IPs, MAC addresses, SSIDs. |
| System → SSL Certificates | Domain name (not strictly secret, but identifies your deployment). |
| Settings → Access Control | External IP CIDRs (your home/office public IP). |
| Settings → Environment | Database password, API secrets, Cloudflare tunnel token, Tailscale auth key, webhook URLs. |
| Settings → Account | Username (less sensitive but identifies your account). |
| Containers → Logs | Logs frequently include IPs, request paths, occasionally tokens. |
If you share screenshots externally, blur:
- Any IP address ending in numbers other than
.0/.255. - Any string starting with
tskey-,eyJh,tgram://,slack://,discord://,twilio://,mailto://,https://*/webhook. - Email addresses other than your own.
- Generator serial numbers.
- Hostnames that identify your deployment (e.g.
mymachine.example.com).
API reference (selected endpoints)¶
GenMaster's full OpenAPI spec is available at https://your-domain/docs (Swagger) or /redoc (ReDoc). Key endpoints:
Generator control¶
GET /api/status Current state, runtime, last heartbeat
GET /api/generator/state Just the state (lighter weight)
POST /api/generator/start {"trigger": "manual"} | {"trigger": "exercise"}
POST /api/generator/stop
POST /api/generator/emergency-stop
System / arming¶
GET /api/system/arm Returns {armed: bool, armed_at, armed_by, slave_connection}
POST /api/system/arm {"source": "api"|"ui"|"webhook"}
POST /api/system/disarm
GET /api/system/health
GET /api/system/slave GenSlave heartbeat status
POST /api/system/host/reboot Requires admin
POST /api/system/host/shutdown Requires admin
Schedules¶
GET /api/schedule
POST /api/schedule {name, start_time, duration_minutes, days_of_week[], enabled}
PATCH /api/schedule/{id}
DELETE /api/schedule/{id}
Run history¶
Notifications¶
GET /api/notifications/channels
POST /api/notifications/channels
PATCH /api/notifications/channels/{id}
DELETE /api/notifications/channels/{id}
POST /api/notifications/channels/{id}/test
GET /api/notifications/groups
GET /api/notifications/rules
GET /api/notifications/history
Containers¶
GET /api/containers
POST /api/containers/{name}/start
POST /api/containers/{name}/stop
POST /api/containers/{name}/restart
GET /api/containers/{name}/logs?lines=200&since=
GET /api/containers/{name}/inspect
Settings¶
GET /api/settings All settings (filtered by role)
PATCH /api/settings/security
PATCH /api/settings/access-control
PATCH /api/settings/environment Requires admin + danger-zone confirmation
PATCH /api/settings/account
Development (mock GPIO mode only)¶
GET /api/dev/status
GET /api/dev/gpio/state
POST /api/dev/gpio/victron-signal {"active": true|false}
POST /api/dev/gpio/toggle
POST /api/dev/webhook/test
Hardware switches (EPO + HOA)¶
Added with the optional hardware-switches feature. See Hardware Switches for the operator-facing guide.
GenMaster side:
GET /api/system/hoa Returns HOAStatus (state, raw contacts, boot-delay
flag, pin assignments, last state-change time)
GET /api/system/quiet-override Returns {active, expires_at, seconds_remaining}
POST /api/system/quiet-override {duration_minutes: 1..1440} start a Quiet override
DELETE /api/system/quiet-override Cancel an active override (idempotent)
GET /api/system/gpio-assignments Current .env pins + running pins + pending_restart
POST /api/system/gpio-assignments {victron_gpio_pin, hoa_gpio_quiet, hoa_gpio_run}
validates BCM 0-27 + distinct; writes .env
POST /api/generator/start 409 response when EPO is engaged:
{"detail": "Cannot start - GenSlave hardware safety
interlock (EPO) is engaged. Release the E-stop at the
generator to allow operation."}
The slave_health block embedded in /api/system/status gains a physical_safety_engaged: bool field. /api/system/status also gains a top-level hoa: HOAStatus object.
GenSlave side:
GET /api/safety HardwareSafetyStatus (engaged, engaged_at,
released_at, engagement_count, raw_input,
epo_monitor_running, available, enabled)
GET /api/health Adds physical_safety_engaged: bool to the public
no-auth payload
GET /api/relay/state Adds physical_safety_engaged: bool to RelayState
GET /api/failsafe Adds physical_safety_engaged: bool to FailsafeStatus
POST /api/heartbeat Reply body adds physical_safety_engaged: bool —
how GenMaster learns the EPO state without a
separate poll
All authenticated endpoints require either:
- A session cookie (after web login), or
- An
Authorization: Bearer <jwt>header (for programmatic access), or - An
X-API-Key: <secret>header (for the slave-side endpoints).
Hardware compatibility¶
Tested generator types¶
| Type | Notes |
|---|---|
| LPG (propane) | Most common in off-grid. Use 2-wire start input. |
| Natural Gas | Same wiring as LPG. |
| Diesel | Glow-plug delay may be needed — set Run Time Limits min run time to ≥ 5 min so the engine stabilizes before any auto-stop. |
| Gasoline | Less common in off-grid; works with same 2-wire interface. Choke automation is generator-side. |
Tested Cerbo signal sources¶
| Source | Wiring |
|---|---|
| Cerbo GX Relay 1 or Relay 2 | NO contact → GPIO17, COM → Pi GND. |
| 24V dry contact (other source) | Use an opto-coupler module if voltage isn't 0/3.3V. |
| External PLC | Same — opto-isolate to protect the Pi GPIO. |
Failure scenarios + expected behavior¶
| Scenario | Expected behavior |
|---|---|
| GenMaster reboots while generator running | On boot: state reset to safe (disarmed, generator_running=false), orphaned run closed with stop_reason=power_loss. Generator may still be physically running until GenSlave's failsafe trips (default 30s after last heartbeat — calculated as 3× the heartbeat interval). |
| GenSlave reboots while generator running | On boot: relay forced OFF (hardware safety). Generator stops. Run record on GenMaster gets stop_reason slave_lost after heartbeat timeout. |
| Network partition between master and slave | Heartbeats fail. After the failsafe timeout (default 30s = 3× the 10s heartbeat interval) the slave triggers failsafe and forces relay OFF, sends Apprise alert. |
| Postgres dies | API errors. Web UI shows toast + degraded badges. Generator state retained in-memory until restart. Recover by restarting genmaster_db. |
| Disk full | Logs fail to write. Backups fail. Run history may stop persisting. Web UI may degrade. Free space immediately. |
| Cert expires | HTTPS access fails. Force renew via System → SSL Certificates or docker compose exec genmaster_certbot certbot renew --force-renewal. |
| Tailscale auth key expires | Tailscale-routed access fails. Re-auth via Tailscale admin console or generate a new auth key and update .env. |
| Cloudflare tunnel down | Public URL fails. LAN/Tailscale access still works. Restart genmaster_cloudflared. |
Related docs¶
- Architecture overview — how the master + slave fit together at the system level.
- Generator Controls (install guide) — original install-side reference.
- Scheduling (install guide) — deeper background on the scheduler.
- Victron Integration — Cerbo GX wiring and behavior.
- Notifications (install guide) — Apprise setup details.
- GenSlave Setup — slave Pi Zero install.
- Tailscale VPN — mesh VPN setup.
- Cloudflare Tunnel — public access setup.
- Troubleshooting — extended troubleshooting reference.
Getting help¶
- GitHub Issues: github.com/rjsears/pizero_generator_control/issues — bug reports, feature requests.
- GitHub Discussions: github.com/rjsears/pizero_generator_control/discussions — community Q&A.
- In-app Help: the [?] icon in the header opens the Help & Documentation dialog with quick links to API docs, this manual, and the repo.