Skip to main content

KEF Wireless Speakers

Local-LAN integration for KEF active wireless speaker pairs — LS50 Wireless II, LSX II, LS60 Wireless, and the LS50 Wireless II Plus — via the on-board KEF Stream HTTP API. Each GEM device represents one speaker pair (the left/right pair behaves as a single network host).

Common in high-end residential installs where the integrator places a KEF pair in a media room or main listening space and wants to expose it through the GEM control surface alongside lighting, shades, and the rest of the AV stack.

Prerequisites

  • A KEF wireless speaker pair (LS50 II / LSX II / LS60 / LS50 II Plus) on modern firmware. LS50 II / LSX II require firmware P6.3001 or later (older firmware used a different protocol on TCP 50001 and is not supported by this driver). LS60 ships with the API enabled out of the box.
  • The speaker has a stable IP address on the LAN. DHCP reservation is strongly recommended.
  • Initial KEF Connect mobile-app setup has been completed so the speaker is on the network and configured.
  • No KEF account is required. The local API on port 80 is open to anything on the same LAN — no token, no pairing.

Setup steps

  1. Complete first-time KEF Connect mobile-app setup so the speaker joins your network and is reachable.
  2. Reserve the speaker's IP on the DHCP server (router or DHCP service).
  3. In GEM, go to System → Devices → Add Device and add a device with driver KEF Wireless Speakers (kef_wireless):
    • ip — the speaker's LAN IP.
    • port — leave at 80 unless the speaker has been put behind a port-mapping rule.
  4. Create one zone for the speaker pair and bind it to this device. Set its Subsystem to AV — the zone editor pre-selects AV for you, because the driver files its speakers under that subsystem. zone.address is optional — use default or leave unset.

Open Devices

The driver does not create the zone for you, and it only writes state onto a zone that is bound to this KEF device. Once that zone exists, the status loop polls source / volume / mute / power / now-playing every status_interval ms (default 5 s) and writes the results back to the zone.

Attribute reference

Device attributes

NameTypeRequiredDescription
ipstringyesSpeaker LAN IP.
portintnoHTTP port. Default 80.
status_intervalintnoPoll interval in ms. Default 5000 (range 1000–600000).
volume_incrementintnoVolume change applied by each volume_up / volume_down. Default 3 (range 1–50).

Zone attributes (populated by the status loop)

NameTypeDescription
volumeintVolume 0–100.
mute_statestringmute_on or mute_off.
sourcestringOne of wifi, bluetooth, tv, optic, coaxial, analog, usb.
power_statestringpowerOn or standby.
statestringDerived: on or off.
track_titlestringNow-playing title (wifi sources only).
track_artiststringNow-playing artist (wifi sources only).
track_albumstringNow-playing album (wifi sources only).

The driver writes these names onto the zone as it polls. They are not pre-registered in GEM's attribute catalog, so they will not appear in the Attribute editor's name picker — when you build a trigger or widget against one (for example a "mute on" trigger on mute_state), type the name exactly as shown above.

Zone address format

One zone per KEF pair. The address is optional — use default or leave unset. The left/right pair is a single network host, so every command acts on the whole pair: the address argument is accepted on each command but is not used to select a target, and there is nothing per-zone to address.

The address only affects where polled state is written back. If exactly one zone is bound to the device, state lands there. If you somehow create several zones on the same device, state is written only to the one literally named default — any other extra zones get no updates until you consolidate down to a single zone (or name one default).

Commands

CommandArgsNotes
onaddressWake from standby.
offaddressStandby.
volumeaddress, level0–100.
volume_up / volume_downaddressSteps by volume_increment (device attribute, default 3).
mute_on / mute_off / mute_toggleaddress
inputaddress, sourcesourcewifi, bluetooth, tv, optic, coaxial, analog, usb.
play / pause / next_track / previous_trackaddressTransport — wifi sources only.
get_statusaddressRead everything in one shot.

Known limitations / not yet supported

  • No multi-room / group control. KEF's app supports multi-room grouping across multiple pairs; the driver controls one pair at a time. Group-aware support would require modeling each pair as a peer and adding a join/leave layer.
  • No EQ / room correction exposed. Bass extension, room compensation, treble/bass trims, and the per-source delay setting in KEF Connect are not surfaced. Add them as per-zone attributes if needed.
  • No firmware update / reboot. Reboot and firmware update endpoints exist on the speaker but are deliberately out of scope here.
  • Now-playing metadata is wifi-only. Bluetooth and physical inputs do not expose track info to the API.
  • Older firmware (pre-P6.3001 on LS50 II / LSX II) used a binary TCP protocol on port 50001 — this driver does not support that path. Update the speaker firmware first.

Troubleshooting

  • connect probe error repeated every retry — the IP is unreachable, the speaker is on old firmware, or port 80 is firewalled. Verify with curl http://<ip>/api/getData?path=settings:/kef/host/speakerStatus&roles=value — a healthy speaker returns a JSON document. An empty response or 404 means the firmware path is wrong.
  • Volume writes silently clamp — KEF Connect has a per-speaker "maximum volume" setting that caps writes. Raise it in the app if you want the full 0–100 range.
  • Now-playing fields stay empty — only populated when streaming via Wi-Fi (AirPlay, Spotify Connect, Roon, UPnP). Physical inputs and Bluetooth do not surface metadata.
  • input command rejected — the source value must exactly match one of the documented enum strings (case-sensitive). Surfacing the picker via arg_options on the command should make this obvious in the GEM admin UI.

References

KEF does not publish the local API officially. The wire format used here mirrors the KEF Connect mobile app and the community Home Assistant integrations (aiohomekit-kef, pykefcontrol, etc.). If a future firmware revision changes the schema, this driver will need to track those changes.

  • Zones — create and bind the zone that surfaces the speaker pair.
  • Subsystems — the AV subsystem this device files its zone under.
  • Devices — add and manage the KEF device.
  • Commands — where the speaker's commands appear and can be tested.
  • AV Zones — expose the speaker on a touchpanel as an AV zone.