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:

  1. Power it on, hold the button ~6 seconds until the red LED blinks twice
  2. Join the hotspot it broadcasts: GemeOpen-xxxxxxxx, password Aa123456
  3. A captive page pops up (or browse to 192.168.4.1)
  4. 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. mqtts support 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.