Commissioning a 25 A MQTT contactor: from unboxing to Home Assistant to long-term maintenance

2026-11-08来源 dev.toEnglish

Commissioning a 25 A MQTT contactor: from unboxing to Home Assistant to long-term maintenance

A 10 A smart plug is easy to reason about. This article is about the other end of the range: a 25 A, 6000 W contactor — the kind of circuit that runs an immersion heater, a workshop compressor, or an EV charger. Getting it wrong is not "the lamp stays on", it's a trip and a phone call to an electrician.

I'll cover commissioning it onto your own broker, wiring it into Home Assistant, and the maintenance commands that matter once it's been in a cabinet for a year.

The device is the GemeOpen GSCW1M2P (Smart Contactor 25A-S2 Plus-WiFi). Disclosure up front: I work on these. The config below is what I run on my own bench, and the caveats are the ones our support threads actually generate.

What this device is, and what it isn't

Spec Value
Model GSCW1M2P
Rated current 25 A working
Max load 6000 W resistive
Input voltage 110–260 V AC, wide range
Channels 1
Standby draw under 4 W
Comms 2.4 GHz WiFi, ESP8266
Protocols MQTT, TCP, HTTP
Housing 50 × 110 × 32 mm, V0 flame-retardant PC/ABS
Rated life 5,000,000 mechanical / 50,000 electrical operations

What it is: a contactor you add to an existing distribution board, downstream of your normal overcurrent protection, so a high-power circuit becomes MQTT-controllable without replacing the consumer unit. That's the install pattern in the vendor's own documentation — added into the box, existing breaker stays.

What it is not: a breaker. It has no overcurrent or earth-leakage protection of its own. It switches a circuit; it does not protect one. Keep your MCB/RCBO upstream, and have a qualified electrician do the wiring. I'm not going to pretend this is a plug-in accessory — at 25 A the installation is the project.

Also note the load rating is specified for resistive loads. Motors and transformers have inrush and a worse power factor, so derate accordingly and check the manual before you put a compressor on it.

Commissioning

Step 1 — Get it on the network

Same provisioning flow as the rest of the range: power it up, hold the button about 6 seconds until the LED blinks, join the GemeOpen-xxxx hotspot, and set your 2.4 GHz SSID on the captive page (192.168.4.1). No app account.

2.4 GHz only. A 5 GHz-only network or an IoT VLAN with client isolation will break this.

Step 2 — Point it at your broker

Out of the box it talks to the vendor's test broker. You redirect it with one message, sent through that broker:

{ "type": "custom", "protocol": "mqtt", "server": "192.168.1.10", "port": "1883", "clientId": "ca2b96693fe2", "username": "ha", "password": "yourpassword", "publish": "/workshop/cw1/report", "subcribe": "/workshop/cw1/cmd" } 

Then power cycle it. Custom MQTT only takes effect after a restart — saving and walking away does nothing. This is the number one support question about this device, and I have hit it myself at 11pm, so: it's real.

Field-name trap, and it matters more on this device. The examples in this product's own documentation use subcribe — missing the "s" — because the documented firmware is 2.2.0. On firmware 2.3.8 and later the field is spelled subscribe. If your messages vanish into the void, that's the first thing to check. Ask the device what it's running:

{ "type": "info" } 

The reply includes version and type. Note the version — you'll want it later.

Step 3 — The setting that actually matters for a contactor

Before you wire anything to it, set the power-on default state:

{ "onState": 1, "type": "setting" } 

Three values:

  • 0 — memory: restores the state from before the power cut
  • 1 — off: comes back up de-energised
  • 2 — on: comes back up energised

For a 6 kW circuit, set onState: 1. A power cut at 14:00 should not mean your water heater or your compressor restarts at 14:02 while nobody is home. The docs flag onState: 2 as a safety risk for exactly this reason, and they're right. If you specifically want memory behaviour for, say, a lighting circuit, 0 is there — but not for a high-power load.

Step 4 — Lock it down

Two locks, and for a device sitting in a shared electrical closet both are worth turning on:

{ "keyLock": 1, "messageId": "1", "type": "setting" } { "type": "setting", "wifiLock": 1 } 

keyLock disables the physical button — the contactor can then only be driven over MQTT/TCP. wifiLock disables long-press re-provisioning, so nobody can walk up to the cabinet and re-point the device at their own network. Both are reversible over the protocol, which is the point: you keep control, they don't get a button.

The command surface

Everything is plain JSON on two topics. Here's the whole thing:

Command Payload you send What comes back
Switch on/off {"key":1,"type":"event"} Full state snapshot, no messageId echo
Set report interval {"timerEnable":1,"timerInterval":60,"type":"setting"} Echoes the two fields
Read live stats {"type":"statistic"} current, voltage, power, energy, key, mac
Read device info {"type":"info"} IP, MAC, firmware, SSID, signal, locks, timer config
Read protocol config {"type":"protocol"} server, port, clientId, topics
Power-on default {"onState":1,"type":"setting"} Full state snapshot
Key lock {"keyLock":1,"messageId":"1","type":"setting"} Full state snapshot + messageId
WiFi lock {"type":"setting","wifiLock":1} Full state snapshot
Custom MQTT {"type":"custom",...} Echoes the config
Custom TCP {"type":"custom","protocol":"tcp",...} Echoes the config
Clear energy {"system":"energy-clear","type":"setting"} {"commandName":"energy-clear","success":true,...}
Restart {"system":"restart","type":"setting"} Echoes
Factory reset {"type":"setting","system":"reset"} Echoes

Two parser gotchas that will bite you:

  1. The telemetry payload has no commandName. The periodic report is just {"current":15.027,"energy":25.047,"key":0,"mac":"ca2b96693fe2","messageId":"timing","power":2921.511,"voltage":226.024} — no command name, and messageId is the literal string "timing", not an echo of anything you sent. If your code dispatches on commandName, it will silently drop every telemetry message.
  2. messageId correlation is inconsistent. Command acks for switching and settings return a full state snapshot without echoing your messageId; energy-clear does echo it. Treat the report topic as a state stream, not as an RPC response channel.

First contact:

mosquitto_sub -h 192.168.1.10 -t '/workshop/cw1/report' -v mosquitto_pub -h 192.168.1.10 -t '/workshop/cw1/cmd' \ -m '{"key":1,"type":"event"}' 

One message, relay pulls in. That's the entire control protocol.

Application: an off-peak water heater, done properly

This is the use case I'd actually recommend for a 25 A contactor, because it's the one where "the cloud service shut down" stops being an inconvenience.

Circuit: a 3 kW immersion heater on its own RCBO, contactor in series, downstream. Set the reporting interval to something sane — 60 seconds is plenty and keeps the recorder database small:

{ "timerEnable": 1, "timerInterval": 60, "type": "setting" } 

Range is 5 to 86400 seconds. Home Assistant config — one switch, four sensors:

mqtt: switch: - name: "Immersion Heater" unique_id: gemeopen_immersion state_topic: "/workshop/cw1/report" command_topic: "/workshop/cw1/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 qos: 1 sensor: - name: "Immersion Heater Power" unique_id: gemeopen_immersion_power state_topic: "/workshop/cw1/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: "Immersion Heater Current" unique_id: gemeopen_immersion_current state_topic: "/workshop/cw1/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: "Immersion Heater Energy" unique_id: gemeopen_immersion_energy state_topic: "/workshop/cw1/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 

The is defined guard on every sensor is not optional here. The report topic carries both the switch acks (which have key but no electrical data) and the telemetry (which has electrical data but no commandName). Without the guard, HA logs a template warning on every toggle.

Now the automations. Off-peak window with a manual enable, plus a current guard:

automation: - alias: "Immersion heater on off-peak" trigger: - platform: time at: "00:30:00" condition: - condition: state entity_id: input_boolean.immersion_enabled state: "on" action: - service: switch.turn_on target: entity_id: switch.immersion_heater - alias: "Immersion heater off at peak" trigger: - platform: time at: "07:00:00" action: - service: switch.turn_off target: entity_id: switch.immersion_heater - alias: "Contactor current guard" trigger: - platform: numeric_state entity_id: sensor.immersion_heater_current above: 20 for: "00:00:30" action: - service: switch.turn_off target: entity_id: switch.immersion_heater - service: notify.persistent_notification.create data: message: "Immersion circuit over 20 A for 30 s - contactor opened" 

That last automation is a convenience guard, not a protection function. It reacts in seconds; an MCB reacts in milliseconds. If your upstream protection is correctly rated, it should never fire. If it fires regularly, you have a wiring or load problem, not an automation problem.

Cumulative energy survives power loss — only an explicit clear resets it. Feed sensor.immersion_heater_energy into the Energy Dashboard and you get per-circuit cost tracking with nothing leaving the house.

Maintenance

The commands you'll actually use once it's been in a cabinet for a while.

Restart after any config change. Changing broker, topics, static IP or WiFi credentials requires a restart:

{ "system": "restart", "type": "setting" } 

The device reconnects to the network and your saved config is retained. The IP address may change — so put a DHCP reservation on it keyed to the MAC, or you'll be re-reading info-all every time it moves.

Clear the energy counter. Irreversible, and it only clears the counter:

{ "system": "energy-clear", "type": "setting" } 

Snapshot your long-term data before you run this if you care about history.

Factory reset — the one that costs you a site visit:

{ "type": "setting", "system": "reset" } 

This wipes WiFi credentials and custom MQTT. The device goes back to the vendor's test broker, which means the only ways back are: go through the vendor broker with a fresh custom message, or physically long-press it back into provisioning mode. If the device is inside a closed cabinet, factory reset is a ladder-and-screwdriver job. Don't run it casually from an automation.

Do the lifetime math before you deploy. 50,000 electrical operations is the rated figure. At 4 cycles a day that's roughly 34 years. At 100 cycles a day — a compressor cycling on pressure — it's about 16 months. If your application switches frequently, either pick a different device class or plan the replacement.

Budget the standby power. Under 4 W, always on. That's about 35 kWh a year — roughly £10 on a UK tariff, so factor it in when the circuit it controls only runs a few hours a day. For a water heater on a timer it pays for itself immediately; for something you switch twice a week it might not.

Check the firmware occasionally with {"type":"info"} and note the version. Two things have changed across versions that affect you: the subcribe/subscribe field spelling at 2.3.8, and TLS support (see below).

Thermals. 6000 W resistive in a 50 × 110 × 32 mm V0 housing is fine for the device, but the cabinet is your problem. If it's going in a sealed enclosure with other heat-generating gear, derate the load or add ventilation. A contactor that cooks itself is a fire risk, not a bug report.

Honest limitations

  • No MQTT over TLS yet. mqtts support is in development. Inside a trusted LAN, fine. Crossing the internet, tunnel it or use a VPN — and don't put credentials in a plaintext topic on a public broker.
  • No MQTT Discovery. Manual YAML. Tedious, but nothing gets renamed out from under you.
  • No gateway needed, and no app account. If you want one, this is the wrong product.
  • Won't join Mi Home, HiLink or Tuya — that's a design choice, not a gap. It targets your own broker and platforms like Home Assistant, ThingsBoard, or the major cloud IoT services.
  • 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.
  • 6000 W is the resistive rating. Motors, transformers and anything with inrush need derating.

Where this fits

If you already run a broker, this is a boring, reliable component: it turns one high-power circuit into a JSON-controllable switch with metering attached, and the data goes to your disk and nowhere else. Commissioning takes about 40 minutes, most of which is the reboot requirement.

If you were hoping for a consumer product with an app, buy something else.

Full command reference, published openly with no sign-up:
https://www.smart-bird.cn/doc/product/GSCW/device/GSCW1M2P/command

Device page: https://www.smart-bird.cn/product/info/GSCW1M2P.html

Questions welcome in the comments — especially if you're running this on EMQX with ACLs, or driving it from Node-RED instead of Home Assistant.

Disclosure: written by the GemeOpen team — we build these devices. Every gotcha above comes from real support threads and my own bench, not a brainstorm. If something behaves differently on your unit, tell me and I'll find out why.

原文:https://www.a8q9.cn/en/article/commissioning-a-25-a-mqtt-contactor-from-unboxing-to-home-assistant-to-long-term-0391a4.html

相关文章