Skip to main content

TP-Link Kasa

Local control of TP-Link Kasa smart plugs and power strips (HS-series, KP-series) over the device's own LAN API. No Kasa cloud account and no hub sit in the middle — GEM talks straight to the device's IP address on port 9999, and no username or password is required.

This is an on/off power switch integration. A Kasa outlet either passes power or it doesn't; the driver does not dim, and it does not read the energy metering that some strips report. Use it to switch lights, appliances, and other loads, to power-cycle gear, or — wired to a momentary trigger — to pulse a gate or garage operator.

The standout feature is auto-discovery: when you add a multi-outlet Kasa device and enable it, GEM reads the strip's outlet list and creates one zone per outlet automatically, under the Power subsystem. You normally do not add zones by hand.

One device, many zones

One Kasa device in GEM is one physical unit (a plug or a strip). On a multi-outlet strip — HS300, KP303, KP400, EP40 — each outlet becomes its own zone, so a 6-outlet HS300 gives you six independent on/off zones.

Prerequisites​

  • Pair the Kasa device in the Kasa mobile app first and put it on the same LAN the GEM controller can reach.
  • Give the device a static IP or a DHCP reservation. The integration addresses the device by IP, so a moving lease takes it offline.
  • Name each outlet in the Kasa app before you add it to GEM (e.g. "Patio Lights", "Christmas Tree"). GEM uses each outlet's Kasa alias as the new zone's label, so naming them first saves you renaming zones afterward.
  • Confirm the unit still exposes its local LAN API. Some 2024-and-newer Kasa and Tapo firmware silently disables the legacy local API in favor of a cloud-only protocol — see Troubleshooting.

Setup​

  1. Open Devices and add a new device. Pick the TP-Link Kasa driver.
  2. In Kasa IP Address enter the device's LAN IP (e.g. 192.168.1.50). No credentials are needed.
  3. Enable the device. On connect, the driver reads the strip's outlet list and creates one zone per outlet under the Power subsystem, named after the outlet aliases you set in the Kasa app.
  4. Open Zones to confirm the new zones appeared. Each one is a Light Switch-style power control with on/off. Rename, re-home to a different subsystem, or assign them to UIs as you would any other zone.
Single-outlet plugs aren't auto-provisioned

The driver discovers outlets from the device's child-outlet list, which only multi-outlet strips report. A single-outlet plug (HS100/HS103/HS110, KP105/KP115, EP10, and similar) has no child list, so no zone is created and the plug can't be controlled through this driver. Use a multi-outlet Kasa device, or switch that single load through a different relay/plug integration.

How outlets become zones​

Each auto-created zone carries an address equal to the outlet's Kasa child id — a long hexadecimal string the driver fills in for you. You don't type it; the address field's hint ("Kasa child outlet id (auto-populated on discovery)") reflects that it's populated during discovery.

The zone name comes from the outlet's alias. If another zone already has that name (two strips that both have an outlet called "Outlet 1", for example), the new zone's name gets the outlet id added to it, and its label stays as the alias.

The outlet list is read only at connect time. If you add or re-map outlets, or upgrade firmware, reload the device so the driver re-enumerates and binds any new outlets — see Troubleshooting.

Subsystem and control type​

New zones land on the Power subsystem with a standard on/off power control. That's the right home for switched lights and appliances. The driver also suggests Lights and Garage as subsystems if a particular outlet fits better there:

  • A switched light or appliance — leave it on Power (or move it to Lights). on / off energize and de-energize the outlet.
  • A gate or garage operator wired to a Kasa outlet's trigger — move the zone to the Garage (or Gates) subsystem and mark it momentary so open/close become a pulse. See Momentary and garage outlets.

There is no dimmer control type for Kasa — these are on/off outlets. A level command is treated as on/off (any level above 0 turns the outlet on, 0 turns it off).

State polling​

While the device is enabled, the driver polls each of its zones in turn and writes the result back to the zone's state (on / off). Outlets are queried about 500 ms apart so a multi-outlet strip isn't hit all at once, and the whole sweep repeats on the device's Status Poll Interval (status_interval, default 1000 ms). If a busy device or network struggles, raise status_interval.

If the device stops answering, the sweep stops at the first outlet that times out (all outlets on a strip share one IP, so the rest would time out the same way). After three sweeps in a row that can't reach it, the device is marked disconnected and the sweep slows down, doubling each time up to once a minute. The first sweep that reaches it again marks it connected and returns to the normal interval. The failure is logged once, not on every sweep. A device that answers with an error code is not counted as unreachable.

If the device can't be reached when GEM first connects to it, the device is marked disconnected and the connection is retried after 30 seconds, then at doubling intervals up to every 5 minutes, until it answers. You don't need to reload the device once it comes back.

A zone can also mirror another zone's state instead of polling its own outlet: set the zone's status_zone attribute to another zone's id and it follows that zone's state. This is the same status-mirroring pattern used elsewhere in GEM (for example, a relay zone that reports position from a separate sensor zone).

Power-cycling and momentary outlets​

The driver turns two real-world actions into outlet sequences:

  • Reboot (power-cycle) — reboot turns the outlet off, waits, then turns it back on. The default gap is 5000 ms. Use it to hard-restart a modem, AP, or other load that's hung. Pass a delay arg (in ms) to change the off-time; raise it for loads sensitive to fast cycling.
  • Momentary pulse — a pulse turns the outlet on, waits, then turns it back off. The default pulse is 1000 ms. This is what a gate or garage operator's trigger input expects.

Momentary and garage outlets​

If a zone is marked momentary — or, when the zone doesn't say either way, the subsystem it's on is — the driver rewrites open and close commands into a pulse automatically — one press fires the operator and the outlet returns to off. To override the pulse length for a specific command, pass a delay arg (ms); the per-zone Pulse Delay (delay) attribute records the intended momentary pulse length for the outlet.

Momentary is read most specific first: the zone's own momentary, then its own subsystem's. A zone set to momentary: false never pulses, even on a momentary subsystem. A zone on some other subsystem does not pulse just because the Garage subsystem is momentary. If a gate stopped pulsing after an update for that reason, the log says so once — set momentary on the gate zone or on the Gates subsystem.

Because a switched outlet can't tell you whether the door actually opened, point the outlet zone's status_zone attribute at a separate input zone wired to a reed/limit switch so the zone reports real open/closed position.

Attributes​

Add these in the Attribute editor for the device or zone; the labeled ones also have fields in the device/zone forms.

Device​

AttributeTypeRequiredDefaultDescription
ipstringyes—LAN IP of the Kasa plug or strip. Shown as Kasa IP Address.
status_intervalintno1000Status Poll Interval (ms) — how often the full outlet sweep repeats.

Zone​

AttributeTypeRequiredDefaultDescription
addressstringyesautoKasa child outlet id. Auto-populated on discovery — you don't normally type it.
delayintno—Pulse Delay (ms) — intended pulse length for a momentary/garage outlet.
status_zoneintno—Id of another zone whose state this zone should mirror instead of polling its own outlet.

Commands​

These are the commands the driver writes and keeps current, so they appear automatically on the device's Commands page and can be tested there.

CommandArgsWhat it does
onaddressTurn the outlet on.
offaddressTurn the outlet off.
levellevel, addressOn/off only — any level above 0 turns the outlet on, 0 turns it off. Kasa outlets don't dim.
rebootdelay, addressPower-cycle: turn the outlet off, wait delay ms (default 5000), then on.
get_stateaddressRead the outlet's current state now and reconcile the zone.
Driver-managed commands

The rows above are rewritten by the driver every time the system starts. Add your own commands if you need them, but don't hand-edit the templates or args of these — your changes are overwritten on the next restart.

On a momentary zone (its own flag, or its subsystem's), open and close are converted to a pulse (on → wait → off, default 1000 ms) before they run — see Momentary and garage outlets.

Troubleshooting​

SymptomCheck
Device never connects; log shows tplink kasa missing ipThe Kasa IP Address (ip) attribute is blank. Set it to the device's LAN IP.
Device shows disconnected and the log shows tplink kasa connect error or tplink kasa unreachableGEM couldn't reach the device on port 9999. It keeps retrying on its own (see State polling); check power, the IP address, and the network path.
Connect timeout on a known-good IPThe unit's firmware may have migrated to the cloud-only Tapo protocol and dropped the local LAN API. Test from the host with a Kasa LAN tool (e.g. kasa --host <ip>). If the local API is gone, downgrade the firmware or replace the unit.
No zones appeared after enablingIt's a single-outlet plug (no child-outlet list) — see the note under Setup — or the device never connected. Confirm the IP is reachable and that it's a multi-outlet strip.
Some outlets on a strip are missingThe outlet list is enumerated only at connect time. After firmware upgrades or outlet changes, reload the device so the driver re-enumerates the outlets.
A command returns invalid address / invalid plug addressThe zone's address doesn't match a discovered outlet. Reload the device to re-bind; don't hand-edit the auto-populated child id.
Outlet cycles too fast for a sensitive load on rebootPass a larger delay (ms) on the reboot command, or raise it on the zone.
  • Devices — add the Kasa device and set its IP.
  • Zones — the per-outlet zones the driver auto-creates.
  • Subsystems — Power (default), Lights, or Garage/Gates; set momentary for a gate/garage outlet.
  • Commands — where on / off / reboot / level / get_state appear and can be tested.
  • Relay semantics — how on/off and open/closed states map across subsystems.