Wiring a GemeOpen MQTT smart plug into Home Assistant in 10 minutes
Most "smart" plugs assume you want an app. I don't want an app. I want a device that connects to the broker I already run, publishes JSON I can read, and never phones home.
This is a walkthrough for the GemeOpen GSPM1B-UK (a UK Type-G plug with energy metering, ESP8266 inside), from unboxing to a working Home Assistant switch + 4 sensors. Everything below is real config I copied out of my own configuration.yaml.
If you've ever flashed Tasmota just to escape a walled garden, this is the same outcome with less swearing — the firmware is already open.
TL;DR — what the device actually speaks
- Protocols: MQTT, TCP, HTTP (no gateway, no hub)
- Payload: plain JSON, one object per command
- Turn the relay on:
{ "key": 1, "type": "event" } - It reports back: voltage, current, power and cumulative kWh on an interval you set (5s to 24h)
- Response time: sub-50ms on a local broker
- Cloud: optional and entirely yours to skip
What you need
- The plug (mine is the UK model,
GSPM1B-UK, firmware 2.3.5) - A 2.4 GHz WiFi network — not 5 GHz, this trips people up constantly
- A broker: Mosquitto, EMQX, HiveMQ, whatever you run. Mine is Mosquitto in Docker on a Pi.
- Home Assistant with the MQTT integration installed
Step 1 — Get it on WiFi
The device doesn't need their app to join your network:
- Power it on, hold the button ~6 seconds until the red LED blinks twice
- Join the hotspot it broadcasts:
GemeOpen-xxxxxxxx, passwordAa123456 - A captive page pops up (or browse to
192.168.4.1) - Pick your 2.4 GHz SSID, enter the password, save
Note the MAC address on the sticker — you'll want it, because it's the device's clientId and the unique part of every topic.
Step 2 — Point it at your own broker
Out of the box the device talks to the vendor's test broker. You redirect it with a single MQTT message — ironically, you configure the broker through the old broker:
{ "type": "custom", "protocol": "mqtt", "server": "192.168.1.10", "port": "1883", "clientId": "8cce4e513b73", "username": "ha", "password": "yourpassword", "publish": "/home/plug1/report", "subscribe": "/home/plug1/cmd" } Publish that JSON to the device's current command topic (the one you can read with info-protocol, see Step 3), then:
⚠️ Reboot the device. Custom MQTT settings only take effect after a power cycle or a restart command. Saving and walking away does nothing — this is the single most common "it doesn't work" report, and I hit it too.
You can also restart it remotely with:
{ "system": "restart", "type": "setting" } A naming trap worth knowing: the device's publish field is the topic the device publishes to (your server's inbox), and subscribe is where it listens. But in the info-protocol response from older firmware, the two labels appear swapped. If your messages vanish, try swapping the two topics — the vendor's own FAQ lists this as cause #1.
Also: on firmware below 2.3.8 the response field is spelled subcribe (missing the "s"). Yes, really. Check your version with {"type":"info"}.
Step 3 — Find your topics
Ask the device what it's configured with:
{ "messageId": "1", "type": "protocol" } The response gives you server, port, clientId, publish and subscribe. From here my setup is:
| Direction | Topic |
|---|---|
| HA → device (commands) | /home/plug1/cmd |
| device → HA (state + telemetry) | /home/plug1/report |
Step 4 — First contact
# watch everything the plug says mosquitto_sub -h 192.168.1.10 -t '/home/plug1/report' -v # turn it on mosquitto_pub -h 192.168.1.10 -t '/home/plug1/cmd' \ -m '{"key":1,"type":"event"}' You should get back:
{ "commandName": "controller-event", "key": 1, "mac": "8cce4e513b73", "onState": 1, "signal": -47, "ssid": "home", "timerEnable": 1, "version": "2.3.5" } Relay clicked, state confirmed. That's the whole protocol — no handshake, no token refresh, no OAuth dance.
Step 5 — Actually wire it into Home Assistant
The device doesn't do MQTT Discovery, so this is manual YAML. Add to configuration.yaml:
mqtt: switch: - name: "Office Plug" unique_id: gemeopen_office_plug state_topic: "/home/plug1/report" command_topic: "/home/plug1/cmd" payload_on: '{"key":1,"type":"event"}' payload_off: '{"key":0,"type":"event"}' state_on: 1 state_off: 0 value_template: "{{ value_json.key }}" optimistic: false sensor: - name: "Office Plug Power" unique_id: gemeopen_office_power state_topic: "/home/plug1/report" value_template: "{{ value_json.power if value_json.power is defined else this.state }}" unit_of_measurement: "W" device_class: power state_class: measurement - name: "Office Plug Voltage" unique_id: gemeopen_office_voltage state_topic: "/home/plug1/report" value_template: "{{ value_json.voltage if value_json.voltage is defined else this.state }}" unit_of_measurement: "V" device_class: voltage state_class: measurement - name: "Office Plug Current" unique_id: gemeopen_office_current state_topic: "/home/plug1/report" value_template: "{{ value_json.current if value_json.current is defined else this.state }}" unit_of_measurement: "A" device_class: current state_class: measurement - name: "Office Plug Energy" unique_id: gemeopen_office_energy state_topic: "/home/plug1/report" value_template: "{{ value_json.energy if value_json.energy is defined else this.state }}" unit_of_measurement: "kWh" device_class: energy state_class: total_increasing Why those is defined guards: the same topic carries two different payloads. controller-event (a click or command ack) has key but no electrical data; device-timer-task (the periodic report) has voltage/current/power/energy but messageId empty. Without the guard, HA logs a template warning every time you toggle the switch.
Restart HA. You now have a switch and four entities.
Step 6 — Set the reporting interval
Out of the box the plug reports every 15 seconds. For an energy dashboard, 30–60s is plenty and keeps your recorder database small:
{ "messageId": "1", "timerEnable": 1, "timerInterval": 60, "type": "setting" } Acceptable range is 5 to 86400 seconds. Set timerEnable: 0 to silence it entirely and only poll on demand:
{ "messageId": "2", "type": "statistic" } Sample the returned payload:
{ "commandName": "device-timer-task", "voltage": 233.695, "current": 0.005, "power": 0.613, "energy": 0, "key": 0 } Real numbers, three decimals, cumulative energy survives power loss (only energy-clear resets it).
Step 7 — The automation you'll actually want
Phantom load killer: turn off anything drawing less than 2W for 10 minutes. Perfect for the TV, the printer, the monitor that "sleeps" at 8W forever.
automation: - alias: "Cut phantom load on office plug" trigger: - platform: numeric_state entity_id: sensor.office_plug_power below: 2 for: "00:10:00" condition: - condition: state entity_id: switch.office_plug state: "on" action: - service: switch.turn_off target: entity_id: switch.office_plug Wire sensor.office_plug_energy into the Energy Dashboard and you get per-device cost tracking with zero cloud involvement.
Gotchas I hit so you don't have to
| Symptom | Cause | Fix |
|---|---|---|
| Config saved, nothing happens | Custom MQTT needs a reboot | Power cycle or send {"system":"restart","type":"setting"} |
mosquitto_sub shows nothing | Publish/subscribe topics are swapped (firmware quirk) | Swap the two topics in the config |
| Command acknowledged, no state change | key sent as string "1" instead of int 1 | Keep it an integer |
| Topic mismatch on old firmware | Field is subcribe, not subscribe | Firmware below 2.3.8 |
| HA logs template errors on every toggle | Event payload has no power field | Use the is defined guards above |
| Device shows offline in the vendor console | Expected — custom MQTT disconnects it from their broker | Ignore it, that's the point |
| Can't reach it from HA | Device on 5GHz or a VLAN that blocks 1883 | 2.4GHz only; check ACLs |
Honest caveats
- No MQTT over TLS yet.
mqttssupport was "in progress" when I set this up. Fine inside a trusted LAN, worth knowing if you're crossing the internet — tunnel it or use a VPN. - The vendor console is a test tool, not a production cloud. Their own docs say so. Don't build a commercial product on it; run your own broker.
- No MQTT Discovery, so you're writing YAML. Tedious, but it also means no surprise entity renaming.
- Shelly/Tasmota have bigger plugin ecosystems. What this device has instead is energy metering, a genuinely simple JSON protocol, and no firmware flashing step.
Where this fits
I've been replacing consumer plugs that require an account to switch a relay. This one takes 10 minutes, three JSON messages, and then it's just... a device on my network that does what I tell it. No app, no login, no telemetry leaving the house.
If you want to read the full command reference before buying anything, everything is published openly — no email wall:
Docs & command reference: https://www.smart-bird.cn/doc
Device page: https://www.smart-bird.cn/product/info/GSPM1B-UK.html
Happy to answer questions in the comments — especially if you've got a different broker setup (EMQX ACLs, HiveMQ Cloud, or Home Assistant's Mosquitto add-on).
Disclosure: this is written by the GemeOpen team — we build these devices. The config above is what we and our users actually run, and every gotcha in the table came from real support threads, not a brainstorm. Push back in the comments if something behaves differently on your setup.
