Docs

Install, configure, survive.

Everything you need to run a gateway on a Raspberry Pi and keep it running. Source for both containers lives at github.com/Encrypted-Energy/gateway.

Install.

Three steps. Ten minutes including the image pull.

1. Sign up and create a gateway. Create an account, then go to /settings/org/gateways and click Add gateway. Give it a name you'll recognize in logs ("Garage Pi", "Cabin"). We mint an API token on creation and show it exactly once. Copy it now or you'll have to mint another.
2. Add the EE community app store to your Umbrel. In umbrelOS: App Store, Community App Stores, Add app store. Paste the store URL:
https://github.com/Encrypted-Energy/umbrel-community-app-store
Encrypted Energy will appear in the store. Click Install. The image pull takes about two minutes on a Pi 5 with a typical connection.
3. Paste your credentials. Open the app at http://umbrel.local:8080 or whatever your Umbrel hostname is. Paste your ee_org_… and ee_live_…, then click Save and start gateway. The dashboard flips from Starting up to Running once the worker authenticates and reaches the EE API.

Configure.

The gateway needs exactly two values. They live on your gateway's page on encryptedenergy.com.

Organization ID Format: ee_org_ followed by 22 characters. Stable, never rotates. Identifies your account on EE; never leaves our backend.
API token Format: ee_live_ followed by 48 hexadecimal characters. Per-gateway, revocable, shown exactly once at creation. If you lose the plaintext, mint a new token from your gateway's page; the old one stays valid until you click Revoke.
Rotating a token On the gateway's page, click Mint a new token. Paste the new value into the Umbrel app's setup wizard (Reconfigure link in the footer of the dashboard) and save. Within one ingest cycle (about five seconds) the worker's using the new token. Revoke the old one when you confirm the new one works.

Hardware.

The right Pi is the cheap part. The right BLE antenna is the part most people underestimate. GPS is optional today and mandatory soon.

Raspberry Pi 5 (recommended) or Pi 4 Either works. The gateway uses about 2 watts idle. Pi 5 has better thermals if you plan to add a USB BLE dongle that pulls non-trivial current. An x86 mini-PC running Umbrel works too; BLE just has to be reachable through BlueZ.
USB BLE dongle (optional, recommended) The Pi's built-in BLE radio works but has a small internal antenna. For real range, add one of:
  • Sena UD100 (about $45). Class 1, +20 dBm TX, external SMA antenna. The safe pick.
  • Nordic nRF52840 USB dongle (about $10). Modern, programmable, no power amplifier. Best for tinkerers.
Antenna gain matters more than transmit power for a passive scanner. A 5 to 7 dBi external SMA antenna in a window will outperform a higher-TX dongle with a stock stub almost every time.
USB GPS dongle (optional today, mandatory soon) Without GPS, your gateway forwards packets stamped with a placeholder coordinate (90.0, 0.0, the north pole, by SDK convention). Packets still get upstream; their positioning utility is degraded.
  • GlobalSat BU-353-S4 (about $25). u-blox 7 chipset, plug-and-play under gpsd, the default safe pick.
  • Any other u-blox-based USB GPS works.
Place the GPS dongle near a window. Indoor GPS reception's spotty; an external puck antenna on a 5-meter cable is the easy fix.

Troubleshoot.

What each dashboard state means and how to recover.

Waiting for credentials The worker can't read its config file. Usually because you haven't finished the setup wizard yet. Paste your org ID and API token, click Save and start gateway. If it persists, SSH into umbrelOS and check that /home/umbrel/umbrel/app-data/encryptedenergy-ee-gateway/data/config.json exists and is readable by uid 1000.
Authentication failed EE rejected your token. Either it was mistyped, revoked, or belongs to a different organization. Open your gateway page, mint a fresh token, paste it into the wizard, save.
Bluetooth scan error The worker tried to scan and BlueZ rejected the request. Common causes: no Bluetooth radio present (e.g. running on Docker Desktop or OrbStack for testing), bluetoothd not running, or another process holding the radio exclusively. On a Pi: sudo systemctl status bluetooth and confirm it's active.
Starting up (forever) The worker's in a crash-restart loop. Most likely cause is a BLE radio that isn't present or isn't responding. Check the worker container's logs:
sudo docker logs --tail 50 encryptedenergy-ee-gateway_worker_1
Dashboard shows "Active" but no packets The worker's reaching EE (heartbeat's fine) but the BLE radio isn't hearing any compatible devices. Either none are in range, or your antenna placement's the problem. Move the antenna toward a window, or add a USB dongle with an external antenna (see Hardware above).

API reference.

For people who want to write their own worker, integrate from another platform, or audit what the official worker is sending. Two endpoints, one bearer token, JSON in, JSON out.

Authentication Every request carries an Authorization: Bearer ee_live_… header. The token's gateway and organization are looked up server-side; the client never sends them explicitly.
Authorization: Bearer ee_live_acb94316b93a6dd637bfb8e59645c25a474af69cd0a19707
Content-Type: application/json
Accept: application/json
POST /api/v1/gateways/heartbeat Periodic liveness ping. Updates the gateway's last_seen_at. Body fields are all optional; send an empty {} if you have nothing to report.
{
  "last_packet_at": "2026-06-08T22:31:00Z",
  "last_known_position_at": "2026-06-08T22:30:55Z"
}
Returns 200 with the gateway's current state, or 401 if the token's invalid or revoked.
POST /api/v1/gateways/packets Forward a batch of BLE packets to the upstream network. EE proxies each packet using its wholesale relationship there. You never need to hold upstream credentials.
{
  "packets": [
    {
      "payload_b64": "BLE-payload-as-base64",
      "rssi": -53,
      "timestamp": 1717900000,
      "latitude": 47.6062,
      "longitude": -122.3321
    }
  ]
}
Returns:
  • 200: all packets accepted upstream. Drop them from your queue.
  • 401: token invalid or revoked. Stop sending until you have a new one.
  • 422: upstream rejected the packet shape (4xx). Drop it; retrying won't help.
  • 502: upstream unreachable or returned 5xx. Leave the packet pending; retry on the next pass.

Read it. Then plug it in.