Docs
Install, configure, survive.
Everything you need to run a gateway on a Raspberry Pi or an iPhone and keep it running. Source for the Pi containers lives at github.com/Encrypted-Energy/gateway.
Install.
Three steps. Ten minutes including the image pull.
apps.umbrel.com/app/ee-gateway
The image pull takes about two minutes on a Pi 5 with a typical connection. Prefer the community channel? Add https://github.com/Encrypted-Energy/umbrel-community-app-store under App Store, Community App Stores, Add app store. Same software, faster updates for testing builds.Configure.
The gateway needs exactly two values. They live on your gateway's page on encryptedenergy.com.
Hardware.
The right Pi is the cheap part. The right BLE antenna is the part most people underestimate. Location is set in the setup wizard, no GPS hardware needed for a stationary gateway. Running on an iPhone? Skip this whole section — the phone's radio and GPS do the work.
Troubleshoot.
What each dashboard state means and how to recover.
sudo docker logs --tail 50 encryptedenergy-ee-gateway_worker_1
API reference.
For people who want to write their own worker, integrate from another platform, or audit what the official worker is sending. Three gateway endpoints, one bearer token, JSON in, JSON out. Base URL: https://encryptedenergy.com. There's also an org API below for provisioning gateways from scripts.
Authorization: Bearer ee_live_acb94316b93a6dd637bfb8e59645c25a474af69cd0a19707 Content-Type: application/json Accept: application/json
{
"ok": true,
"gateway": {
"name": "Garage Pi",
"public_id": "ee_gw_…",
"organization_id": "ee_org_…",
"organization_name": "My Org"
}
}
{
"last_packet_at": "2026-06-08T22:31:00Z",
"last_known_position_at": "2026-06-08T22:30:55Z",
"gps_status": "fix",
"platform": "umbrel",
"os_version": "umbrelOS 1.4"
}
gps_status is one of
fix, no_fix,
dongle_missing.
platform is one of
umbrel, ios,
android, linux —
it drives platform-specific guidance on your gateway's dashboard
page. The official worker also reports packet counters as deltas
(packets_forwarded_delta and friends);
send those only if you reset your local counter on a 2xx response,
so a crash never double-counts.
Returns 200 with the gateway's
current state (uuid, status, last_seen_at, gps_status, packet
totals), or 401 if the token's
invalid or revoked.
Cadence: the official worker heartbeats every 60 seconds. Keep
yours under 15 minutes; gateways silent longer than that are
marked down and the operator gets an alert email.
{
"packets": [
{
"payload_b64": "BLE-payload-as-base64",
"eid": "a1b2c3d4e5f6",
"rssi": -53,
"timestamp": 1717900000,
"latitude": 47.6062,
"longitude": -122.3321,
"position_at": 1717899995,
"accuracy_m": 8.5
}
]
}
eid is the device identifier the
worker decodes from the BLE payload (hex string). Required: a
batch with a missing eid gets a 422, and bounties are keyed off
it. timestamp and
position_at are unix seconds
(when the packet was heard, when the GPS fix was captured).
position_at and
accuracy_m are optional.
Coordinates must be in range and not (0, 0); that's the unset
fixed-location tell and the batch gets a 422.
Returns:
- 200: batch accepted upstream. Drop it from your queue.
- 401: token invalid or revoked. Stop sending until you have a new one.
- 413: over 500 packets. Split the batch and resend.
- 422: malformed batch, or upstream rejected it (4xx). Drop it; retrying won't help. The body's invalid_reasons array says which packet and why.
- 502: upstream unreachable or returned 5xx. Leave the batch pending; retry on the next pass.
GET /api/v1/org/gateways list your gateways
POST /api/v1/org/gateways create one: {"name": "Garage Pi"}
GET /api/v1/org/gateways/:uuid one gateway plus its tokens (masked)
POST /api/v1/org/gateways/:uuid/tokens mint another token
DELETE /api/v1/org/gateways/:uuid/tokens/:id revoke a token
Create returns 201 with the
gateway and its first token.
token.key is the plaintext, shown
exactly once, same contract as the dashboard:
{
"ok": true,
"gateway": { "uuid": "…", "public_id": "ee_gw_…", "name": "Garage Pi", "status": "pending" },
"token": { "id": 42, "name": "Garage Pi initial token", "key": "ee_live_…" }
}
Feed that key straight to the worker's config and you've
provisioned a gateway without opening a browser.
:uuid accepts the bare uuid or the
ee_gw_… form. Errors:
400 missing name,
404 not your gateway,
422 validation failed.