Leviton Load Center (LWHEM / LDATA)
GEM driver for Leviton's smart electrical panel platform: the Whole Home Energy Monitor (LWHEM-2 / LWHEM-2R data hub) and the earlier LDATA hub, both reached through the MyLeviton (my.leviton.com) cloud REST API. It reads per-breaker electrical telemetry out of a Leviton Load Center and, on 2nd-generation smart breakers, switches circuits on and off.
Feature coverage:
- Discovery of panels (
get_panels), breakers (get_breakers) and whole-panel CT channels (get_cts) - Per-breaker polling → zone
state,instant_power_w,rms_current_a,rms_voltage_v,consumed_energy_wh,produced_energy_wh,operational_state - Panel rollup on the device →
total_power_w,breaker_count,rms_voltage_a/rms_voltage_b,panel_model,panel_status, andct1_power_w…ct3_power_wfor installed current transformers - Remote
on/off/toggleon 2nd-gen smart breakers, plusblink_ledto physically locate a breaker in the panel refreshto ask the hub for an immediate cloud upload instead of waiting for the next scheduled one
This is not the same integration as Leviton Decora Smart. That driver controls Decora Smart Wi-Fi switches and dimmers; it shares the MyLeviton cloud and nothing else. A site with both products needs both devices configured.
Prerequisites
- A commissioned load center. The LWHEM or LDATA hub must be installed in the Leviton Load Center, joined to Wi-Fi, and showing live data in the My Leviton mobile app. If the app shows no energy data, GEM will not either — the driver reads exactly what the hub has uploaded.
- A MyLeviton account with 2FA disabled. The login endpoint rejects credentials on a two-factor account with an
InsufficientDataerror and there is no inline way to answer the challenge. Use a dedicated automation account with the residence shared to it rather than embedding the homeowner's personal credentials in a controller. - 2nd-gen smart breakers for control. Monitoring works on any breaker the hub can see. Remote switching requires Leviton's 2nd-generation smart breakers, which report
canRemoteOn: true. 1st-gen breakers and bare CT channels are read-only. - Outbound HTTPS. The controller needs to reach
my.leviton.comon 443. There is no documented local API on the hub.
Setup steps
- Add the device. Devices → New Device, driver
leviton_lwhem. Enter:- MyLeviton Account Email — the account the load center is enrolled under.
- MyLeviton Account Password — stored encrypted.
- Confirm the panel is visible. From the Script Console, run the
get_panelscommand on the device. You should get one entry per hub, each carrying anid, amodel, andtype(whemfor LWHEM,ldatafor the older hub). An empty list usually means the hub is enrolled under a different residence — runget_residencesand set Residence ID. - Enumerate breakers. Run
get_breakers. Each row pairs a numericidwith the breaker'spositionin the panel, itscurrent_rating, andcan_remote_on. Print this list before you start creating zones — panel position is what lets you match an id to a physical circuit. - Create a zone per circuit. For each breaker you want in the UI, create a zone in the power (or energy) subsystem with the device set to this controller and Address set to the numeric breaker id.
- Pin the panel if needed. On a site with more than one load center, set Panel ID so the device-level rollup attributes describe one panel rather than mixing two. Add a second GEM device for the second panel.
- Verify a control action. On a 2nd-gen breaker, run
blink_ledwithstate=1and confirm the right breaker's locator LED starts flashing before you ever sendoffto it.
off physically trips a live circuit. Confirm which breaker an address maps to with blink_led before wiring off into a macro, and never put a life-safety, sump, refrigeration, or network-infrastructure circuit on an automated trip.
Attribute reference
Device attributes
| Attribute | Required | Type | Purpose |
|---|---|---|---|
email | yes | string | MyLeviton account email. |
password | yes | string (encrypted) | MyLeviton account password. Used only to mint session tokens. |
api_base | no | string | API endpoint. Defaults to https://my.leviton.com/api. |
residence_id | no | string | Pin to one residence on a multi-home account. Blank = every residence the account can see. |
panel_id | no | string | Pin to one load center. Blank = all discovered panels; the first supplies the device rollup. |
status_interval | no | int | Poll period in ms. Default 60000, floor 15000. |
power_scale | no | float | Multiplier applied to raw power before storing as watts. Default 1. |
energy_scale | no | float | Multiplier applied to raw energy counters before storing as watt-hours. Default 1. |
request_timeout | no | int | HTTP timeout in ms. Default 15000. |
The scale factors exist because Leviton does not publish the units on the breaker telemetry fields. The driver stores them unscaled and assumes watts and watt-hours. If the panel and the My Leviton app disagree with GEM by a constant factor, correct it here rather than editing the driver.
Attributes the driver writes
Device (panel rollup, from the pinned or first-discovered panel):
| Attribute | Unit | Meaning |
|---|---|---|
total_power_w | W | Sum of instantaneous power across every breaker on the panel. |
breaker_count | — | Number of breakers the hub reports. |
rms_voltage_a / rms_voltage_b | V | Line voltage per leg. |
panel_model | — | Hub model code as reported by the cloud. |
panel_status | — | online, offline, or the hub's own status string. |
ct1_power_w … ct3_power_w | W | Active power per installed CT pair (LWHEM only — up to three pairs). |
Zone (one per breaker):
| Attribute | Unit | Meaning |
|---|---|---|
state | — | on or off. |
instant_power_w | W | Live real power, both poles summed. |
rms_current_a | A | Live current, both poles summed. |
rms_voltage_v | V | Line voltage at the breaker. |
consumed_energy_wh | Wh | Cumulative consumption counter. |
produced_energy_wh | Wh | Cumulative backfeed counter — non-zero only on circuits that push power back into the panel, such as a solar or generator feed. |
operational_state | — | Raw vendor state string, which is where a trip shows up. |
Telemetry is rounded before it is stored (1 W, 0.1 A, 0.1 V, 1 Wh) so that meter jitter does not flood attribute history with movement that isn't real, and a reading the hub does not supply — a breaker reporting no voltage, for example — is skipped rather than stored as an empty value.
Zone address format
The zone address is the numeric MyLeviton breaker id — an opaque cloud id, not the panel position:
482913
Run get_breakers to map ids to positions and labels. Ids are stable for the life of the enrollment but are reassigned if a breaker is removed and re-paired, so re-run get_breakers after any panel work.
Which breakers a user may operate
Every addressed command from a UI, the REST API, or voice — including blink_led, which skips the
driver's own breaker lookup entirely — is confined to breakers that have a zone on this device.
The rule is enforced centrally at the command dispatch layer, so no per-command list in this driver
can miss a verb. A breaker id with no matching zone returns
not authorized: address is not mapped to a zone on this device.
The driver's breaker lookup scans every panel across every residence the MyLeviton account can
see, which is a much wider set than the breakers a site exposed as zones. The unmapped ones are the
ones that must not be user-switchable — the alarm panel, the network rack, the controller. Leviton's
canRemoteOn flag describes the breaker's hardware generation, not who GEM allows.
Administrators are unaffected, and so are macros, triggers, schedules and other drivers.
Known limitations
- Cloud-only. Leviton publishes no local API for the LWHEM hub. A WAN outage stops telemetry and control; the controller cannot fall back to the LAN.
- Minute-scale resolution. The hub uploads roughly once a minute. Polling faster costs API quota without gaining resolution, which is why the floor is 15 s and the default is 60 s.
- Two-factor accounts are unusable. There is no inline TOTP path.
- Breaker state strings are unverified. Leviton does not document the
currentStatevocabulary. The driver mapson/closed→onandoff/open/anything containingtrip→off, and deliberately leaves the zone state unchanged (logging once) on a value it does not recognize rather than guessing whether a breaker is live. - Trips surface in
operational_state, notstate. Zone state stayson/offso power-subsystem controls stay predictable; useoperational_statein a condition if you want to alarm on a trip. - No scheduling or load-shedding passthrough. Leviton's own breaker schedules and load-shed rules live in the app and are not read or written here. Build those as GEM macros instead.
- CT usage types are surfaced but not interpreted.
get_ctsreturns each channel'susage_typeverbatim; the driver does not try to decide which CT is the mains. - Not yet in the metric registry. The zone attribute names deliberately match the SPAN panel driver's (
instant_power_w,consumed_energy_wh,produced_energy_wh) so the Power dashboard picks them up as soon as registry rows carryingmetric_roleexist for theleviton_lwhemcontext. Until then the values are stored and trended but not aggregated into the energy-flow view.
Troubleshooting
| Symptom | Check |
|---|---|
Login fails immediately, error mentions InsufficientData or two factor | 2FA is enabled on the account. Disable it, or move the residence to a dedicated automation account. |
get_panels returns [] | The hub is on a residence the driver isn't looking at. Run get_residences, then set residence_id. |
| Breakers list, but every telemetry field is null | The hub has not uploaded yet (wait two poll cycles), or those circuits have no CT installed. Confirm the My Leviton app shows data for the same breaker. |
on / off returns breaker does not support remote control | The breaker reports canRemoteOn: false — it is a 1st-gen breaker. Monitoring still works. |
not authorized: address is not mapped to a zone on this device | The breaker has no zone on this device. Create one, or run the command as an administrator. See Which breakers a user may operate. |
| Connect fails with a certificate error | my.leviton.com is verified against the public CA set — a failure here means something is intercepting the connection (a TLS-inspecting firewall or proxy). The account email, password and session token ride these calls, so the driver will not fall back to an unverified connection. |
on / off returns 200 but nothing happens | The hub is offline or the breaker was tripped mechanically. A mechanically tripped breaker must be reset by hand at the panel; remoteOn will not re-close it. |
Repeated http 401 in the log | The session token expired and re-login is failing. Confirm the password still works in the app; run refresh_token to force a fresh login. |
http 429 | Too many calls. Raise status_interval — one panel of 20 breakers at 60 s is already several thousand calls a day. |
| Device shows connected but values are frozen | The cloud is serving a stale cache. Run refresh, which sends the hub a bandwidth nudge and re-polls. |
| Unrecognized breaker state warnings in the log | Report the exact string. It means Leviton uses a currentState value the mapping doesn't cover; the driver is holding the last known state rather than guessing. |