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.
Top comments (0)