Skip to content

Add GAS_COOKTOP support - #491

Open
carles2m wants to merge 1 commit into
simbaja:masterfrom
carles2m:gas-cooktop
Open

Add GAS_COOKTOP support#491
carles2m wants to merge 1 commit into
simbaja:masterfrom
carles2m:gas-cooktop

Conversation

@carles2m

@carles2m carles2m commented Apr 19, 2026

Copy link
Copy Markdown

Ready for review. simbaja/gehome#111 (adds GeAppliance.get_raw_erd_value()) merged 2026-05-17 and shipped in gehomesdk 2026.5.0. manifest.json now requires gehomesdk>=2026.5.0.

Problem

ErdApplianceType.GAS_COOKTOP = "0D" has existed in gehomesdk since 2021 but has never been mapped to a device handler in devices/__init__.py's known_types dict. Standalone gas cooktops authenticate against GE's cloud, appear in the appliance list, and receive ERD updates — but get_appliance_api_type() returns the inert ApplianceApi base and zero entities get created.

Sibling reports, still open:

  • #305 — F&P cooktop unmapped (maintainer declined pending full implementation).
  • #482 — Café gas range cooktop sensors stuck off.

Why this appliance type is tricky

Standalone gas cooktops use the DEVICE_GATEWAY_V1_BLE_ADVERTISE_ONLY_SENSOR feature flag (BLE-to-cloud gateway rather than native WiFi). In practice they implement a reduced ERD surface and reuse familiar hex codes with different byte semantics:

Hex Upstream registration Meaning on gas cooktop (observed)
0x5020 HOOD_TIMER Kitchen timer alarm byte 0
0x5105 UPPER_OVEN_KITCHEN_TIMER Kitchen timer minutes remaining (uint16)
0x5520 COOKTOP_STATUS Cooktop-on aggregate byte 0
0x5900 (unregistered) Lock state enum
0x5902 (unregistered) Cooking minutes (on-time)

For the registered codes, the existing converter decodes the raw hex into a typed Python object (timedelta, CooktopStatus, ...) that's meaningless on a gas cooktop. The new GeAppliance.get_raw_erd_value() from simbaja/gehome#111 is the escape hatch — we read the raw bytes and decode per the gas-cooktop schema.

Fix

Adds devices/gas_cooktop.py with GasCooktopApi and its entity classes, plus a one-line addition to the known_types dispatcher.

Entities (reverse-engineered from a Monogram ZGU36ESLSS by toggling each feature in the SmartHQ app and diffing publish#erd events):

  • Cooktop Onbinary_sensor, POWER class, 0x5520 byte 0 (00 all off, 01 any on).
  • Lockedbinary_sensor, LOCK class, 0x5900 (01=unlocked, 02=transitioning, 03=locked). Read-only; see "Not included" below.
  • Kitchen Timernumber, 0–599 min, step 1, NumberMode.BOX, uom=min. Writable — tested end-to-end via number.set_value service against live appliance.
  • Kitchen Timer Alarmbinary_sensor, SOUND class, 0x5020 byte 0 (01=beeping, auto-clears on user ack).
  • Cooking Minutessensor, uom=min, state_class=TOTAL_INCREASING, 0x5902. Ticks up once per minute while any burner is on, resets to 0 when all burners turn off; SmartHQ's 1-hour "cooktop still on" alert fires when this reaches 60.

Kitchen timer writes bypass the SDK encoder because UPPER_OVEN_KITCHEN_TIMER's upstream encoder expects a timedelta in seconds, not raw big-endian minutes. We call appliance.client.async_set_erd_value() directly with a hand-encoded 2-byte hex string.

Not included

Writable lock. Brillion rejects gehomesdk's writes to 0x5900 with 400 "erd is not writable" — even though the SmartHQ app can successfully lock the cooktop. Investigation with DEBUG logging confirmed:

  • SmartHQ's lock action flips 0x5900 directly (no separate command ERD), visible via publish#erd: 01 → 02 → 03.
  • Our write to the same endpoint with the same body shape is rejected.
  • Brillion therefore enforces per-OAuth-client-id ERD writability — SmartHQ's client_id is whitelisted for this ERD, gehomesdk's isn't.

Lock stays a read-only BinarySensor. Matches SmartHQ's own UI, which is one-way too (lock yes, remote unlock no) for safety.

Testing

Local backport of this change has been running against a live Monogram ZGU36ESLSS for over a month with no issues. All five entities verified:

  • Binary sensors flip correctly in response to physical toggles (burner ignition, control-panel lock, kitchen-timer alarm).
  • Kitchen timer writes via number.set_value service: physical display mirrors the written value within ~6s; 0 clears it.
  • Cooking Minutes validated across a session where its value correlated with burner-on time and reset when burners turned off.

Open questions for cross-model robustness

ErdApplianceType.GAS_COOKTOP = "0D" has existed in gehomesdk since
2021 but has never been mapped to a device handler. Result: standalone
gas cooktops authenticate, appear in the appliance list, and receive
ERD updates, but fall through to the inert ApplianceApi base and
produce zero entities.

Standalone gas cooktops use the feature flag
DEVICE_GATEWAY_V1_BLE_ADVERTISE_ONLY_SENSOR (BLE-to-cloud gateway
rather than native WiFi), implement a reduced ERD surface (no
per-burner detail, no COOKTOP_STATUS_EXT), and reuse familiar hex
codes with different byte semantics. Three of the five ERDs we need
(0x5020, 0x5105, 0x5520) are registered in gehomesdk's ErdCode enum
with converters that produce oven/hood-shaped objects meaningless on
this appliance. We read their raw bytes via
appliance.get_raw_erd_value() and decode per the gas-cooktop schema.

Entities exposed (reverse-engineered from a Monogram ZGU36ESLSS):
- Cooktop On (binary_sensor, 0x5520 byte 0)
- Locked (binary_sensor, LOCK class, 0x5900; read-only, see below)
- Kitchen Timer (number, writable 0-599 min, 0x5105)
- Kitchen Timer Alarm (binary_sensor, SOUND class, 0x5020 byte 0)
- Cooking Minutes (sensor, total_increasing, min uom, 0x5902)

NOT implemented: writable lock. Brillion rejects gehomesdk's writes to
0x5900 with 400 "erd is not writable" even though the SmartHQ app can
lock. Per-OAuth-client-id writability policy; lock stays a read-only
BinarySensor. SmartHQ's UI is also one-way (can lock, can't remotely
unlock) for safety.

Requires gehomesdk>=2026.5.0, which adds GeAppliance.get_raw_erd_value()
(simbaja/gehome#111, merged 2026-05-17 and released in gehomesdk 2026.5.0).
manifest.json is bumped accordingly.
@carles2m carles2m changed the title Add GAS_COOKTOP support (depends on simbaja/gehome#111) Add GAS_COOKTOP support May 23, 2026
@carles2m
carles2m marked this pull request as ready for review May 23, 2026 18:37
@carles2m

carles2m commented May 23, 2026

Copy link
Copy Markdown
Author

Updated and ready for review. gehomesdk #111 (get_raw_erd_value()) merged and released in gehomesdk 2026.5.0, so I force-pushed the branch to bump manifest.json to gehomesdk>=2026.5.0 and dropped the draft. No code changes since the draft — the GasCooktopApi already used get_raw_erd_value(). Also refreshed the testing note in the description: the local backport has now been running against a live Monogram ZGU36ESLSS for over a month with no issues.

@simbaja

simbaja commented May 26, 2026

Copy link
Copy Markdown
Owner

I went in a different direction for this, I want to avoid having raw ERD manipulation in the integration itself. I did integrate the ability to get the raw values though, so that you can continue using your fork if you want to do so. Instead of the changes you propose here, I've done the following:

  • The cooktop status (0x5520) was actually pulling the overall status correctly; however, the fact that the burners weren't defined properly essentially overrode this status. I've revised the logic to hopefully not populate burners that don't exist, which should enable the status to be reported properly.
  • The kitchen timer (0x5105) in the SDK should be correct (it specifies its UoM as minutes), so direct read/write shouldn't be necessary. Instead, I've a) made sure that it gets added to cooktop entities if found and b) added a number entity to control input (it was previously settable via a service call, but I think most people didn't use this, this is better anyway). You can use the UoM setting in Home Assistant to control how the timespans are rendered on the main sensor as well (the number entity is in minutes).
  • Cooking minutes (0x5902) was an easy SDK add, so I just added it there. Interestingly enough, this one seems to be completely undocumented...
  • Locked (0x5900), implemented this in the SDK as well and also implemented 0x5901 as its counterpart which is what actually controls the lock request. Basically, you need to send a "1" to 0x5901 to request it to be locked, 0x5900 can only read the lock state (which you saw through your testing)
  • Timer Alarm (0x5020) is the only one where I didn't make a change yet. Based on the GE documentation, your interpretation is probably correct; however, people with a hood seemed to rely on it as the actual timer. I didn't want to change it yet, hopefully you can create a template sensor to replicate the functionality.

The changes are in the latest pre-release 2026.5.0-dev0 or in the 2026.5.0-working branch, would love for your feedback on the implementation and for any further enhancements to support your device.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants