Skip to content

Repository files navigation

MMFP Govee

MMFP Govee Webhook listener and General Govee tool — turn GoSlimStratum (GSS) and GSS Miners (GSSM) notification webhooks into Govee light effects. Flash the ceiling fan light green/gold five times when a block is found, hold a lamp red while a miner is offline, switch it back when it recovers.

An MMFP Solutions product. Open source under GPLv3 (see LICENSE).

How it works

GSS / GSSM ── generic webhook (POST /hook, X-MMFP-Token) ──▶ MMFP Govee ──▶ Govee cloud API ──▶ lights

Two listeners:

Listener Port Purpose
Web app 3008 Devices, event mappings, tokens, activity, settings
Webhook 8787 Receives GSS / GSSM generic-webhook events

The webhook endpoint routes on the event type in the body (event_type from GSSM, type from GSS), so one URL serves every event a channel sends. Effects run asynchronously — the webhook is acknowledged immediately, effects are serialized per device, and a per-mapping cooldown collapses event storms.

Quick start

  1. Run it (Docker):

    docker run -d -p 3008:3008 -p 8787:8787 -v ./config:/app/config \
      ghcr.io/mmfpsolutions/mmfp-govee:latest

    Or locally: go build ./cmd/mmfp-govee && ./mmfp-govee (config is created on first run).

  2. Add your Govee API key — open http://localhost:3008, you'll land on Settings. Get a key in the Govee Home app (Profile → Settings → Apply for API Key). The key is stored encrypted at rest.

  3. Create a token on the Tokens page — the dialog shows the secret once, with copy-paste GSS/GSSM setup values.

  4. Point GSS or GSSM at it — add a generic webhook channel:

    • GSSM (its webhook form only takes a URL): http://<this-machine>:8787/hook?token=<your secret>
    • Callers that support custom headers: URL http://<this-machine>:8787/hook + header X-MMFP-Token: <your secret> (keeps the token out of URLs and logs). GSSM's backend supports a headers map too, but only via hand-editing notifications.json.

    Use the sender's Test button — it returns 200 and shows up on the Activity page. Note the Test buttons emit fixed events (GSS: startup, GSSM: test), not your mapped events — they prove the wiring, not the mapping. To preview a mapping's effect, use its own Test button in MMFP Govee, or force the event: curl "http://<host>:8787/hook/<event>?token=<secret>".

  5. Create a mapping on the Mappings page: pick the token, the event(s) (e.g. block_found), the device(s), and an effect (presets included: Celebrate, Alert, All clear, Off). Hit its Test button to see the lights fire.

Webhook endpoint

POST /hook              event type read from the JSON body (GSSM event_type / GSS type)
POST /hook/{event}      forced-event mode (body optional)
GET  /hook/{event}      same, curl-friendly

Auth: X-MMFP-Token header or ?token= query param. Responses: 202 queued / no mapping, 200 test events, 400 no event type, 403 bad token.

Configuration

config/config.json — see config.example.json. Managed from the UI; ports require a restart. Secrets (goveeApiKey, token secrets) are encrypted at rest automatically (ENC: prefix); plaintext values are migrated on first load.

Optional login: authentication is off by default. To enable it, set "disableAuthentication": false and create in the config directory:

  • access.json — {"<username>": "<sha256-hex-of-password>"}
  • jsonWebTokenKey.json — {"jsonWebTokenKey": "<random-secret>", "expiresIn": "1h"}

Quiet hours: suppress effects inside a time window (webhooks are still received and logged).

The window is evaluated against the app's own clock, which in Docker is the container's timezone — not your laptop's. A container defaulting to UTC will evaluate a 22:00–07:00 window several hours off and fire alerts in the early morning. Either set TZ on the container (TZ=America/New_York, as docker-compose.yml does) or pin it in config so it cannot drift:

"quietHours": { "enabled": true, "start": "22:00", "end": "07:00", "timezone": "America/New_York" }

The Settings page shows the app's current clock and whether it is suppressing right now — check there first if quiet hours misbehaves. Startup logs the effective window too.

LAN Control (optional, faster)

Govee devices with LAN Control enabled in the Govee Home app can be driven directly over your network instead of the cloud API — roughly 10× faster, no API budget, and they keep working with the internet down. It's per-device and automatic: anything without it falls back to the cloud, so you can adopt it one lamp at a time. The LAN Control column on the Devices page shows a green check for devices currently served over LAN.

Scenes always use the cloud API (the LAN protocol has no scene command), so an effect that ends on a scene still costs one cloud call — versus a dozen for the flash itself.

Defaults are on; the block is optional:

"lan": { "enabled": true }

Linux hosts need nothing else, but LAN discovery is UDP multicast, so the container must share the host's network — network_mode: host (already set in docker-compose.yml). Leave devices empty: discovery finds everything and proves each device is really answering.

Docker Desktop for Mac / Windows can't do multicast discovery (containers run in a VM, so host mode shares the VM's network, not yours) — but unicast to a known IP works fine. Give each device a DHCP reservation, list them, and use the Mac service:

"lan": {
    "enabled": true,
    "devices": [
        { "device": "34:FD:CC:44:A9:3A:60:AC", "sku": "H607C", "ip": "192.168.7.75" }
    ]
}
docker compose up -d mmfp-govee-mac    # bridge networking + publishes 4002/udp

Device IDs and models come from the Devices page. Only list devices with reserved IPs — a static entry pointing at a drifted address silently does nothing (the app notices and falls back to cloud, but you lose the speed-up without an obvious reason). Static entries are ignored wherever discovery finds the device anyway, so they're harmless to leave in a shared config.

Build

./build-local.sh        # compiles Tailwind CSS + builds the Docker image (no cache)
go test ./...           # unit tests

Events

Any event type the sender emits can be mapped. Known types are offered in the mapping editor:

  • GSS: block_found, block_matured, block_orphaned, payment_*, node_*, miner_connect, miner_disconnect, best_share, notable_share, rejected_shares, network_difficulty_*, startup, shutdown, cleanup
  • GSSM: miner_offline, miner_online, miner_failover, miner_zero_hashrate, miner_temp_high, miner_temp_normal, pool_offline, pool_online, node_offline, node_online, system_startup, system_shutdown, test

Packages

Contributors

Languages