Skip to content

rjsears/pizero_generator_control

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

54 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

RPi Generator Control

RPi Generator Control

Documentation Latest Release Last Commit License: MIT Issues Pull Requests

Docker Build Lint Stars Forks

Python FastAPI Pydantic SQLAlchemy

Vue.js Pinia Tailwind CSS Vite Chart.js

PostgreSQL Redis Docker Nginx

Cloudflare Tailscale Let's Encrypt Apprise Raspberry Pi

View Full Documentation

A working (in production in my system), distributed generator control system designed for off-grid solar installations with Victron energy systems. Built on a master-slave architecture using Raspberry Pi devices, it provides automated generator management with manual override capabilities, scheduling, and real-time monitoring through a modern web interface.

While designed around Victron integration, the architecture is universal—any two-wire trigger source (home automation, PLC, manual switch, or relay output) can signal GenMaster, and GenSlave can control any device with a two-wire start input (generators, pumps, HVAC, irrigation, industrial equipment). With optional Tailscale VPN and Cloudflare Tunnel support, your trigger source and controlled device can operate anywhere in the world—same building or different continents, wherever there's internet access.


Watch the demo video


Table of Contents


Overview

The RPi Generator Control system automates generator management for off-grid solar installations. When your Victron Cerbo GX determines that battery levels are low and generator power is needed, it sends a signal to GenMaster, which coordinates with GenSlave to physically start the generator.

System Overview


Features

Automated Control

Feature Description
Victron Integration Monitors GPIO signal from Cerbo GX relay for automated start/stop
Scheduled Runs APScheduler-based scheduling with cron expressions
Manual Override Force start/stop from web UI regardless of Victron signal
State Machine Comprehensive state tracking (idle, starting, running, stopping, cooldown)

Reliability & Safety

Feature Description
Automation Arming Explicit arm/disarm prevents accidental operations during startup or maintenance
Heartbeat System Continuous health monitoring between GenMaster and GenSlave
Independent Failsafe GenSlave automatically stops generator if communication lost for 30s
State Persistence PostgreSQL database survives reboots and power failures
Webhook Notifications Real-time alerts to n8n, Home Assistant, or any webhook receiver

Modern Web Interface

Feature Description
Real-time Dashboard Live status updates via WebSocket
Dark Mode Full dark/light theme support
Mobile Responsive Works on any device
Container Management Portainer integration for Docker control

Generator Information & Fuel Tracking

Feature Description
Generator Profile Store manufacturer, model number, and serial number
Fuel Configuration Configure fuel type (LPG, Natural Gas, Diesel) and expected load
Consumption Rates Set fuel consumption rates at 50% and 100% load
Per-Run Tracking Automatically track fuel usage for each generator run
Fuel History View estimated fuel consumed in run history

Exercise Scheduling

Feature Description
Automated Exercise Schedule regular generator runs for maintenance
Configurable Frequency Set exercise interval (weekly, bi-weekly, monthly, or custom)
Time Selection Choose start time for exercise runs
Duration Control Set how long each exercise run should last
Run Now Manually trigger an exercise run on demand

Operational Excellence

Feature Description
Run History Complete log of all generator runs with duration, trigger, and fuel usage
Statistics Daily, monthly, and all-time runtime tracking
System Health CPU, memory, disk, and temperature monitoring
Backup/Restore Database backup with one-click restore

System and Network Architecture

System Architecture

Component Overview

Component Technology Purpose
GenMaster Backend FastAPI + Python 3.11 REST API, state machine, scheduler
GenMaster Frontend Vue.js 3 + Tailwind CSS Reactive web interface
Database PostgreSQL 16 State persistence, run history, configuration
Cache Redis Session storage, real-time data
Reverse Proxy Nginx HTTPS termination, rate limiting, security headers
GenSlave Backend FastAPI (Docker) Relay control, heartbeat responder
HAT Pimoroni Automation Hat Mini Physical relay + LCD status display

Hardware Requirements

GenMaster

Component Specification
Computer Raspberry Pi 5 (8GB RAM)
Storage 128GB NVMe SSD via PCIe adapter
Power 5V 5A USB-C supply (27W recommended)
GPIO Pin 11 (GPIO17) for Victron input
Network WiFi or Ethernet

GenSlave

Component Specification
Computer Raspberry Pi Zero 2W
HAT Pimoroni Automation Hat Mini
Storage Quality SD card or USB SSD
Power 5V 2.5A supply
Relay Built-in 24V @ 2A max (GPIO16)
Display Built-in 0.96" 160x80 LCD

Victron Connection

  • 2-wire normally-open contact from Cerbo GX MK2 Relay
  • Connected to GPIO17 (Pin 11) and Ground (Pin 9)
  • Internal pull-up resistor enabled

Tested Deployment

This is what I've actually verified in my own off-grid setup — not just what the design supports on paper. Other hardware combinations (different Pi models, alternative relay HATs, other battery monitors) may work fine but have not been field-tested here.

Area Tested configuration
GenMaster Raspberry Pi 5, 8GB, Raspberry Pi OS 64-bit
GenSlave Raspberry Pi Zero 2 W
Relay HAT Pimoroni Automation HAT Mini
Trigger source Victron Cerbo GX MK2 relay
Network LAN baseline (same-network operation works with no VPN). Tailscale optional — required for remote administration or when GenMaster and GenSlave are on different networks. Cloudflare Tunnel optional — used to expose the GenMaster web UI publicly.
Boot policies tested fail_safe and preserve_state (both verified across real reboots)
Failure tests run GenMaster reboot mid-operation, GenSlave reboot mid-operation, network loss between master and slave, heartbeat loss triggering GenSlave's independent failsafe, relay forced OFF on failsafe trigger

Known Limitations

A handful of architectural and operational realities to be aware of before deploying this in your own setup:

  • Fuel usage is estimated, not measured. The fuel-tracking number is calculated from runtime × your configured consumption-rate values (fuel_consumption_50 / fuel_consumption_100) — there is no actual fuel-flow sensor. Accuracy depends on how well your rate values match real-world performance.

  • Network and security configuration is non-trivial. This project has many moving parts (nginx reverse proxy, cloudflared tunnel, Tailscale, per-route auth, IP allowlists). Read docs/SECURITY.md end-to-end before exposing GenMaster beyond your LAN.

  • GenSlave needs privileged GPIO access. It runs as a privileged container with host networking so the Pimoroni Automation Hat Mini can drive GPIO. That's a deliberate trade-off — if you compromise the GenSlave container, you have effective root on the Pi Zero. See docs/SECURITY.md#container-privilege-model.

  • Tested with my specific hardware setup; other generators may need wiring/config changes. Generators differ in start-contact polarity, voltage tolerance, dry-vs-wet contacts, hold-time requirements, etc. The relay control logic itself is generator-agnostic, but the physical wiring between GenSlave's relay and your generator's start input is your responsibility to verify.


Quick Start

Prerequisites

  • Raspberry Pi 5 with Raspberry Pi OS (64-bit)
  • Docker and Docker Compose installed
  • Network connectivity between GenMaster and GenSlave

One-Command Install

curl -fsSL https://raw.githubusercontent.com/rjsears/pizero_generator_control/main/genmaster/install.sh | sudo bash

Manual Installation

# Clone repository
git clone https://github.com/rjsears/pizero_generator_control.git
cd pizero_generator_control/genmaster

# Run interactive setup
./setup.sh

The setup wizard will:

  1. Detect environment - Raspberry Pi, LXC container, or standard Linux
  2. LXC Warning - Show Proxmox configuration requirements if running in LXC
  3. Hardware detection - Enable mock GPIO mode if not on Raspberry Pi
  4. System checks - Verify memory, disk, ports, network connectivity
  5. Install Docker if needed (with platform-specific guidance for macOS/WSL)
  6. Domain validation - DNS resolution, IP matching, connectivity tests
  7. Configure GenSlave - IP address, API secret (prominently displayed for copying)
  8. Connection validation - Retries 3 times with 10-second delays if GenSlave is starting
  9. Configure timezone - Default America/Phoenix with host sync option
  10. Configure generator info - Optional manufacturer, model, fuel type, consumption rates
  11. Optional services - Tailscale VPN, Cloudflare Tunnel, Portainer
  12. Generate configs - .env, docker-compose.yml, nginx.conf
  13. Deploy stack - Start all containers

Setup Command Line Options

# Interactive setup
./setup.sh

# Show help
./setup.sh --help

# Use pre-configuration file
./setup.sh --config myconfig.conf

# Validate GenSlave connection (run after GenSlave is set up)
./setup.sh --genslave

# Update GenSlave IP/URL address
./setup.sh --genslaveip

# Show version
./setup.sh --version

Pre-configuring Generator Information

To pre-populate generator information during setup, create a gen_info.json file:

# Copy the template
cp genmaster/setup/gen_info.json.template genmaster/setup/gen_info.json

# Edit with your generator details
nano genmaster/setup/gen_info.json

Template contents:

{
  "manufacturer": "Generac",
  "model_number": "7043",
  "serial_number": "ABC123456",
  "fuel_type": "lpg",
  "load_expected": 50,
  "fuel_consumption_50": 1.6,
  "fuel_consumption_100": 2.8
}

The setup wizard will detect this file and offer to use these values. Fuel type options: lpg, natural_gas, diesel. Load options: 50 or 100.

Verify Installation

# Check container status
docker compose ps

# View logs
docker compose logs -f genmaster

# Access web interface
# https://your-domain.com or https://genmaster (via Tailscale)

GenSlave Installation (Pi Zero 2W)

GenSlave runs as a Docker container on the Pi Zero 2W:

# SSH into your Pi Zero
ssh pi@genslave.local

# Download and run the setup script
curl -fsSL https://raw.githubusercontent.com/rjsears/pizero_generator_control/main/genslave/setup.sh -o setup.sh
chmod +x setup.sh
sudo ./setup.sh

The GenSlave setup will:

  1. Install Docker - From Debian repositories (optimized for Pi Zero)
  2. Install Docker Compose - For container orchestration
  3. Prompt for API secret - Must match GenMaster's SLAVE_API_SECRET
  4. Configure notifications - Optional Apprise URLs for failsafe alerts
  5. Pull Docker image - Pre-built ARM image from Docker Hub
  6. Create systemd service - Auto-start container on boot
  7. Configure Tailscale - Optional VPN for GenMaster connectivity
  8. Start container - Begin listening on port 8001

Verify GenSlave

# Check container status
cd /opt/genslave
docker-compose ps

# View logs
docker-compose logs -f

# Test API (requires API key)
curl -H "X-API-Key: your-api-secret" http://localhost:8001/api/health

Configuration

Environment Variables

Configuration is managed through .env file. Key settings:

# Domain Configuration
DOMAIN=genmaster.example.com

# Application
APP_ENV=production
APP_DEBUG=false
APP_SECRET_KEY=<generated-secret>

# Database
DATABASE_USER=genmaster
DATABASE_PASSWORD=<generated-password>
DATABASE_NAME=genmaster

# GenSlave Communication
GENSLAVE_ENABLED=true
SLAVE_API_URL=http://genslave.local:8001
SLAVE_API_SECRET=<shared-secret>

# Heartbeat
HEARTBEAT_INTERVAL_SECONDS=10
HEARTBEAT_FAILURE_THRESHOLD=3

# Webhooks (Optional)
WEBHOOK_BASE_URL=https://n8n.example.com/webhook/xxx
WEBHOOK_SECRET=<webhook-secret>

# Generator Information (Optional - can be configured via UI)
GEN_INFO_MANUFACTURER=Generac
GEN_INFO_MODEL_NUMBER=7043
GEN_INFO_SERIAL_NUMBER=ABC123456
GEN_INFO_FUEL_TYPE=lpg           # lpg, natural_gas, or diesel
GEN_INFO_LOAD_EXPECTED=50        # 50 or 100
GEN_INFO_FUEL_CONSUMPTION_50=1.6 # gal/hr at 50% load
GEN_INFO_FUEL_CONSUMPTION_100=2.8 # gal/hr at 100% load

# Cloudflare Tunnel
CLOUDFLARE_TUNNEL_TOKEN=<tunnel-token>

# Tailscale (Optional)
TAILSCALE_AUTHKEY=<auth-key>
TAILSCALE_HOSTNAME=genmaster

Docker Profiles

Enable optional services using profiles:

# Basic stack (GenMaster, PostgreSQL, Nginx)
docker compose up -d

# With Tailscale VPN
docker compose --profile tailscale up -d

# With Cloudflare Tunnel
docker compose --profile cloudflare up -d

# With Portainer
docker compose --profile portainer up -d

# All optional services
docker compose --profile tailscale --profile cloudflare --profile portainer up -d

Web Interface

Dashboard

The dashboard provides at-a-glance status of:

  • Generator State - Current status with color-coded indicator
  • GenSlave Status - Online/offline with last heartbeat time
  • Victron Signal - Active/inactive GPIO17 state
  • System Health - CPU, memory, disk usage

Quick Actions

  • Start Generator - Manual start (requires GenSlave online)
  • Stop Generator - Manual stop
  • View Schedule - Manage scheduled runs
  • View History - Browse run history with fuel consumption data

Generator Tab

  • Generator Information - View and edit manufacturer, model, serial number
  • Fuel Configuration - Set fuel type, expected load, and consumption rates
  • Exercise Schedule - Configure automated maintenance runs
    • Enable/disable exercise scheduling
    • Set frequency (weekly, bi-weekly, monthly, or custom days)
    • Configure start time and duration
    • Run exercise immediately with "Run Now" button

Settings

  • Webhook Configuration - URL, secret, event toggles
  • GenSlave Settings - API URL and secret
  • Backup/Restore - Database backup management
  • System - Timezone, logging level

API Reference

Generator Control

# Get current status
GET /api/status

# Start generator manually
POST /api/generator/start
Content-Type: application/json
{"trigger": "manual"}

# Stop generator
POST /api/generator/stop

Schedule Management

# List schedules
GET /api/schedule

# Create schedule
POST /api/schedule
Content-Type: application/json
{
  "name": "Morning Run",
  "cron_expression": "0 6 * * *",
  "duration_minutes": 60,
  "enabled": true
}

# Delete schedule
DELETE /api/schedule/{id}

Generator Information

# Get generator info
GET /api/generator-info

# Response
{
  "manufacturer": "Generac",
  "model_number": "7043",
  "serial_number": "ABC123456",
  "fuel_type": "lpg",
  "load_expected": 50,
  "fuel_consumption_50": 1.6,
  "fuel_consumption_100": 2.8
}

# Update generator info (partial update)
PATCH /api/generator-info
Content-Type: application/json
{
  "manufacturer": "Generac",
  "fuel_type": "lpg",
  "load_expected": 50
}

Exercise Schedule

# Get exercise schedule
GET /api/exercise

# Response
{
  "enabled": true,
  "frequency_days": 7,
  "start_time": "10:00",
  "duration_minutes": 15,
  "last_exercise_date": "2026-01-12",
  "next_exercise_date": "2026-01-19"
}

# Update exercise schedule
PATCH /api/exercise
Content-Type: application/json
{
  "enabled": true,
  "frequency_days": 14,
  "start_time": "09:00",
  "duration_minutes": 30
}

# Run exercise now (manual trigger)
POST /api/exercise/run-now

System

# Health check
GET /api/health

# System metrics
GET /api/system/health

# GenSlave status
GET /api/system/slave

GenSlave API (Port 8001)

# Health check
GET /api/health

# Relay control
GET  /api/relay/state    # Get current relay state
POST /api/relay/on       # Turn relay ON (requires armed)
POST /api/relay/off      # Turn relay OFF

# Arming
GET  /api/relay/arm      # Get arm status
POST /api/relay/arm      # Arm automation
POST /api/relay/disarm   # Disarm automation

# Heartbeat (from GenMaster)
POST /api/heartbeat      # Receive heartbeat with command

# System info
GET  /api/system         # CPU, RAM, temperature
GET  /api/failsafe       # Failsafe monitor status

Automation Arming

# Get arm status
GET /api/system/arm

# Arm automation (enables all automated actions)
POST /api/system/arm
Content-Type: application/json
{"source": "api"}

# Disarm automation (blocks all automated actions)
POST /api/system/disarm
Content-Type: application/json
{"source": "api"}

Automation Arming System

The arming system prevents accidental generator operations during startup, maintenance, or testing. Automation is disarmed by default and must be explicitly armed before any automated actions can occur.

Why Arming?

  • Startup Safety: Prevents race conditions when GenMaster/GenSlave boot at different times
  • Maintenance Mode: Disarm before working on the generator or electrical systems
  • Testing: Safely test configurations without triggering the generator
  • Power Loss Recovery: Operator-configurable boot policy controls whether armed state survives across reboots (default: disarm and require re-arming)

Power Loss / Reboot Behavior

GenMaster's boot behavior is controlled by an operator-selectable Boot Arming Policy, configured in the UI under Generator → Boot Arming Policy. The setting is stored in the database and persists across reboots. GenSlave's behavior is the same regardless of GenMaster's policy.

Boot Arming Policy options on GenMaster:

Policy Behavior on GenMaster boot Use case
fail_safe (default) Disarms the relay if it was armed pre-boot. Sets manual_disarm_active = True. Fires the boot_disarmed_failsafe notification. Operator must re-arm via the UI. Default. Required if your installation should NOT auto-resume after a power event.
preserve_state Keeps the prior armed state across the reboot. The system can resume operation automatically after an outage. Only when your installation is safe to auto-resume (proper ATS, weatherproofing, fuel/CO safety, etc.). Switching to this mode requires confirming a UI warning.

On GenMaster boot (regardless of policy):

  1. slave_connection_status = "unknown", missed_heartbeat_count = 0
  2. If generator_running was True, reset to False; close orphaned run with stop_reason = "error"
  3. Apply boot arming policy:
    • fail_safe: slave_relay_armed = False, manual_disarm_active = True, fire boot_disarmed_failsafe notification
    • preserve_state: leave slave_relay_armed unchanged
  4. Reconcile with GenSlave once it's reachable
  5. Log SYSTEM_BOOT_RESET event with boot_arming_policy and relay_disarmed_by_policy fields

On GenSlave boot (always, no policy choice):

  1. Relay is immediately set to OFF (hardware-default and software-enforced)
  2. Internal _armed = False
  3. Failsafe monitor starts waiting for heartbeats
  4. First heartbeat from GenMaster syncs both armed state and relay state — within ~1 heartbeat cycle (~10s default), GenSlave matches whatever GenMaster says

Important under fail_safe (default): The generator will NOT auto-start after a power loss, even if the Victron signal is active. An operator must explicitly re-arm the system first. The boot_disarmed_failsafe notification (configurable in Notifications → Configure → Generator Events) tells you when this happens.

Important under preserve_state: The generator may automatically restart after an outage if your battery monitor is still calling for power when the system returns. Use only when your installation can safely auto-resume.

Arming Behavior

State Victron Signals Scheduled Runs Manual Start
Disarmed Logged but ignored Skipped (logged) Blocked
Armed Trigger start/stop Execute normally Allowed

Arming Workflow

1. Boot GenMaster and GenSlave
2. Verify GenSlave connection (should show "connected")
3. Review system status in web UI
4. Click "Arm Automation" in dashboard
5. System now responds to Victron signals and schedules

Disarming Notes

  • Running Generator: Disarming does NOT stop a running generator
  • Manual Stop: Use manual stop to halt generator before disarming
  • Maintenance: Always disarm before physical work on generator

API Examples

# Check arm status
curl https://genmaster.example.com/api/system/arm

# Response
{
  "armed": false,
  "armed_at": null,
  "armed_by": null,
  "slave_connection": "connected"
}

# Arm the system
curl -X POST https://genmaster.example.com/api/system/arm \
     -H "Content-Type: application/json" \
     -d '{"source": "api"}'

# Response
{
  "success": true,
  "armed": true,
  "message": "Automation armed successfully",
  "armed_at": 1736985600,
  "warnings": []
}

CI/CD & Docker Images

Automated Docker Builds

Docker images are automatically built and pushed to Docker Hub when code is merged to main:

Image Platforms Trigger Path
rjsears/genmaster:latest amd64, arm64 genmaster/**
rjsears/pizero_generator_control:genslave arm/v6 genslave/**

Manual builds can be triggered from the GitHub Actions tab with target selection.

Raspberry Pi 5 GPIO Access

GenMaster requires privileged container access for GPIO on Raspberry Pi 5:

# In docker-compose.yaml
genmaster:
  privileged: true
  user: root

This is required because Pi 5 uses a different GPIO architecture (/dev/gpiochip0, /dev/gpiomem4) than earlier models.


Development & Testing

LXC Container Testing

GenMaster can run in LXC containers for development without GPIO hardware:

# Clone and setup
git clone https://github.com/rjsears/pizero_generator_control.git
cd pizero_generator_control/genmaster

# Run setup (auto-detects mock GPIO mode)
./setup.sh

# Or manually with docker compose
docker compose up -d

Mock GPIO Mode

When not running on a Raspberry Pi, GenMaster automatically:

  • Detects missing GPIO hardware
  • Falls back to mock GPIO mode
  • Enables development API at /api/dev/*

Simulating Victron Signal

# Signal ON (generator wanted)
curl -X POST http://localhost:8000/api/dev/gpio/victron-signal \
     -H "Content-Type: application/json" \
     -d '{"active": true}'

# Signal OFF (generator not wanted)
curl -X POST http://localhost:8000/api/dev/gpio/victron-signal \
     -H "Content-Type: application/json" \
     -d '{"active": false}'

# Get current state
curl http://localhost:8000/api/dev/gpio/state

# Toggle signal
curl -X POST http://localhost:8000/api/dev/gpio/toggle

UI-Only Testing

To test the web interface without GenSlave:

# Set in .env
GENSLAVE_ENABLED=false

This disables heartbeat service and suppresses slave offline warnings.


Troubleshooting

Common Issues

Issue Solution
GenSlave shows offline Run ./setup.sh --genslave to validate connection
GenSlave IP changed Run ./setup.sh --genslaveip to update the URL
Generator won't start Verify GenSlave is online, check for active override
Victron signal not detected Check GPIO17 wiring, verify signal in /api/dev/gpio/state
Container won't start Run docker compose logs <container> for details
Database connection failed Check DATABASE_PASSWORD matches in both services
LXC Docker issues Ensure lxc.apparmor.profile: unconfined is set in Proxmox
API key mismatch Update GenSlave's .env then run docker-compose up -d --force-recreate genslave

GenSlave Connection Management

# Validate GenSlave connection (tests DNS, ping, port, API health)
./setup.sh --genslave

# Update GenSlave URL/IP (with optional health checks and restart)
./setup.sh --genslaveip

The --genslave option performs comprehensive validation:

  • DNS resolution / IP address verification
  • Ping connectivity test
  • TCP port availability check
  • API health endpoint test with API key authentication
  • Automatic retry: If GenSlave doesn't respond, retries 3 times with 10-second delays (allows time for container restart)

Useful Commands

# View all container logs
docker compose logs -f

# Restart specific container
docker compose restart genmaster

# Check database
docker compose exec db psql -U genmaster -d genmaster -c "SELECT * FROM system_state;"

# Test GenSlave connection manually
curl -X GET http://genslave.local:8000/api/health

# Check GPIO state (mock mode)
curl http://localhost:8000/api/dev/gpio/state

Log Locations

Log Location
GenMaster docker compose logs genmaster
Nginx docker compose logs nginx
PostgreSQL docker compose logs db
Application /app/logs/ inside container

Security

Network Security

  • Tailscale VPN - Encrypted WireGuard mesh network
  • Cloudflare Tunnel - No exposed ports, DDoS protection
  • Nginx Rate Limiting - API: 30r/s, Auth: 5r/m

Application Security

  • JWT Authentication - Token-based API access
  • HTTPS Only - No HTTP traffic accepted
  • HMAC Webhooks - Signed webhook payloads
  • API Secrets - Shared secrets for GenSlave communication

Access Control

  • Nginx Geo Module - IP-based allowlist gating the entire 443 interface (UI, API, websocket, health, Portainer). Clients outside the allowlist receive HTTP 403. Manage entries via Settings → Access Control.
  • Tailscale ACLs - Tag-based access control
  • Cloudflare Access - Optional additional authentication layer

Port Reference

Service Internal Port External Access Notes
Nginx 443 Yes (HTTPS only) Main entry point
FastAPI 8000 No (internal) Backend API
PostgreSQL 5432 No (internal) Database
Redis 6379 No (internal) Cache
Portainer 9000 /portainer/ path Optional
GenSlave API 8001 Tailscale only Pi Zero 2W

License

This project is licensed under the MIT License - see the LICENSE file for details.


Acknowledgments

Support


Special Thanks

  • My amazing and loving family! My family puts up with all my coding and automation projects and encourages me in everything. Without them, my projects would not be possible.
  • My brother James, who is a continual source of inspiration to me and others. Everyone should have a brother as awesome as mine!

Author

Richard J. Sears


Welcome to the off-grid community

About

Two-Pi distributed dry-contact relay controller. Master handles logic, web UI, scheduling, notifications; remote slave drives the relay with an independent failsafe. Generic 2-wire input/output works for generator start/stop, pumps, valves, fans, irrigation, anything switched by a relay.

Topics

Resources

License

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors