DEV Community

GemeOpen
GemeOpen

Posted on

Wiring a GemeOpen MQTT smart plug into Home Assistant in 10 minutes

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" }
Enter fullscreen mode Exit fullscreen mode
  • 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"
}
Enter fullscreen mode Exit fullscreen mode

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" }
Enter fullscreen mode Exit fullscreen mode

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" }
Enter fullscreen mode Exit fullscreen mode

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"}'
Enter fullscreen mode Exit fullscreen mode

You should get back:

{
  "commandName": "controller-event",
  "key": 1,
  "mac": "8cce4e513b73",
  "onState": 1,
  "signal": -47,
  "ssid": "home",
  "timerEnable": 1,
  "version": "2.3.5"
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

Acceptable range is 5 to 86400 seconds. Set timerEnable: 0 to silence it entirely and only poll on demand:

{ "messageId": "2", "type": "statistic" }
Enter fullscreen mode Exit fullscreen mode

Sample the returned payload:

{
  "commandName": "device-timer-task",
  "voltage": 233.695,
  "current": 0.005,
  "power": 0.613,
  "energy": 0,
  "key": 0
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)