Kef lsx ii lt using restful API

I just got my speakers and didn’t want to use the remote to change the volume and the official kef integration wasn’t working for me so I made a script myself. I tried a bunch of searching and couldn’t find a complete solution. I figured I’d post this so someone else can build off of it.

First step is to add the restful API for your speakers to home assistant. You’ll need to make a DHCP reservation for your speakers and add this line to your configuration.yaml (replace 192.168.1.78 with your reservation IP - you may need to reboot your speakers if you chose a different IP than the one it currently has.)

rest_command:
  kef_office:
    url: "http://192.168.1.78/api/{{cmd}}"
    method: GET
    verify_ssl: false

After this, you need to restart home assistant.

Once it’s back up and running, you can test this works by going to home assistant->developer tools → actions. For the action, pick the name you put above (‘kef_office’) as the action and use this for Action data:

  cmd: getData?path=player:volume&roles=value

Press “Perform Action” and you should get output like:

content:
  - type: i32_
    i32_: 80
status: 200
headers:
  Date: Thu, 27 Nov 2025 03:17:16 GMT
  X-Robots-Tag: noindex
  Transfer-Encoding: chunked
  Content-Type: application/json

The 80 above is the current volume. Now we can write a script that increases or decreases the volume from that value.

I added an “input number” helper named kef_office_cur_vol that holds the current volume and created a new script (named kef_office - set volume) with the below yaml:

sequence:
  - action: rest_command.kef_office
    response_variable: getvol_response
    data:
      content-type: application/json
      cmd: getData?path=player:volume&roles=value
  - action: input_number.set_value
    metadata: {}
    data:
      value: >-
        {{ ((getvol_response.content | string).rsplit(":",1)[-1].split('}')[0] |
        int)+rotate_amount  }}
    target:
      entity_id: input_number.kef_office_cur_vol
  - action: rest_command.kef_office
    data:
      cmd: >-
        setData?path=player:volume&roles=value&value={"type":"i32_","i32_":
        {{states.input_number.kef_office_cur_vol.state}} }
alias: kef_office - set volume
description: ""
fields:
  rotate_amount:
    selector:
      text: null
    name: rotate_amount
    required: true

It takes one number parameter (named rotate_amount) that represents a signed integer for how much to change the volume. I use my stream deck to supply the rotate_amount.

There are three steps to the script:

  1. Like the first test, we grab the the current volume using the restful command and store the response in the var named ‘getvol_reseponse’. This will hold the ‘content’ section in the test response above.
  2. We then parse the output by grabbing the substring after the last ‘:’ (i.e. the 80), add the input parameter value (rotate_amount) and assign that to the input helper you created earlier (mine was kef_office_cur_vol).
  3. Finally, we make another restful API request, but this time we set the volume to the new amount. This cmd string is slightly different - it uses setData instead of getData and the ‘value’ we supply is a json string with the actual values.

You can hook this script up to a button or control you have, or run automations like decrease the volume when you leave the room, etc. Like I said earlier, I hooked it up to my stream deck so I can use the knobs on it to control the volume.

The operation isn’t immediate - I’d say there’s around a 0.5 to 1s latency between turning the dial and the volume changing.

There are APIs to control other aspects of the speakers, you can look at pykefcontrol/pykefcontrol/kef_connector.py at 3769677b0e2d74de3235f35a7e49f8bfee421756 · N0ciple/pykefcontrol · GitHub to hookup additional functionality.

1 Like