Skip to content

Conversation

@iamjoshk
Copy link

@iamjoshk iamjoshk commented Dec 31, 2025

Proposed change

This quirk v2 adds device automation triggers for the new Bilresa 2 button remote:
press on, hold on, hold on released, press off, hold off, hold off released.

To pair in ZHA

  1. In ZHA, add new device
  2. On remote, press the center pairing button 4 times
  3. Wait for light to blink rapidly
  4. Press pairing button 8 times

Additional information

Device diagnostics

zha-cf326f00bf27144eb946b7dd7295081c-IKEA of Sweden 09B9-e0c5b8bbd566112fe1966cf6aed0a09f.json

Checklist

  • The changes are tested and work correctly
  • pre-commit checks pass / the code has been formatted using Black
  • Tests have been added to verify that the new code works
  • Device diagnostics data has been attached

@codecov
Copy link

codecov bot commented Dec 31, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 92.29%. Comparing base (35d1fc1) to head (2c3e9ea).

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #4612      +/-   ##
==========================================
+ Coverage   92.28%   92.29%   +0.01%     
==========================================
  Files         371      372       +1     
  Lines       12158    12176      +18     
==========================================
+ Hits        11220    11238      +18     
  Misses        938      938              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@MattWestb
Copy link
Contributor

Great work done !!

First what not working that is implemented:
The (LONG_RELEASE, DIM_DOWN): { is never being triggered then the device is sending:

  endpoint_id: 1
  cluster_id: 8
  command: stop_with_on_off
  args: []
  params: {}

so must being COMMAND: COMMAND_STOP_ON_OFF = release from log up = normal IKEA and is always triggering the release up then its first in the list.

Its possible "saving" the last long press and using it for tagging the release with it like is being done in the Open/Close control.

We just want to keep track of direction, to associate it with the stop command.
"""
cmd_name = self.server_commands[hdr.command_id].name
if cmd_name == COMMAND_OPEN:
self._is_closing = False
elif cmd_name == COMMAND_CLOSE:
self._is_closing = True
elif cmd_name == COMMAND_STOP:
action = COMMAND_STOP_CLOSING if self._is_closing else COMMAND_STOP_OPENING
self.listener_event(ZHA_SEND_EVENT, action, [])

I was looking before Christmas and was not doing one quirk then its looks like the DA for move is broken also for all existing device so i was doing one bug report for getting it fixed and then can implementing the DA for the new device. #4605

Now to the not implemented parts:
Im not 110% sure but its looks we need fixing the batters reporting then it shall being reported 1/2 % and IKEA is normally (but fixed in 3 gen controllers).

And the device is sending IKEAs scene commands on double press so need putting it in (copy from Styrbar).

Adding this imports:

from zigpy.zcl import ClusterType
from zhaquirks.ikea import IKEA, DoublingPowerConfig2AAACluster, ScenesCluster

and need some more commands imported:

    DOUBLE_PRESS,
    COMMAND_PRESS,

And then replace PowerConfig and scene cluster with the imported ones_

    .replaces(DoublingPowerConfig2AAACluster)  # will only double for old firmware
    .replaces(ScenesCluster, cluster_type=ClusterType.Client)

Now we can adding the DA for scene changes:

            (DOUBLE_PRESS, DIM_UP): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 256,
                    "param2": 13,
                    "param3": 0,
                },
            },
            (DOUBLE_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 257,
                    "param2": 13,
                    "param3": 0,
                },
            },

Then the move command DA is fixed we only have one problem left and its naming of the button. Its not OK haveing 2 diferent named of one button (On/dim up / Off/dim down) it shall being the same name and only changing the command / function that is being triggered. So On/off , Dim Up/Down or Upper/Lower button.

I was having one forbutton / styrbar modded quirk working but have copy yours and all is working OK (move not) and looks nice but this device is not good as light controller then its not honer group and device bindings in Zigbee mode and only sending commands to IKEA scene groups so if having more lights is sending commands to all and cant being changed what i knowing (can being more digging is needed but wireshark is showing the remote is acking the bind command but not using it and delete all bindings) but still baseball for doing automation with but better with matter over thread (that have not implemented binding cluster and its not sending light commands = no go for lights if like have god functionality).

One more time great work done !!!

@mkz212
Copy link

mkz212 commented Dec 31, 2025

Just press the button 8 times. You don't need to press 4 times first.

The rule for new Ikea Matter devices, if you want to use them in Zigbee, is that you do 2 times more than for regular Zigbee devices.

Examples:

  • Zigbee bulb (Tradfri) you do 6 cycles (12 clicks) to add to Zigbee. For Matter bulb (Kajplats) you do 12 cycles (24 clicks) to add to Zigbee.
  • Zigbee button (Rodret) you press button 4 times to add to Zigbee. For Matter button (Bilresa) you press button 8 times to add to Zigbee.

@MattWestb
Copy link
Contributor

MattWestb commented Dec 31, 2025

All working except move DAs that is broken in zigpy and dim down long release triggering long up release:

"""IKEA Bilresa 2 button remote control."""

from zigpy.quirks.v2 import QuirkBuilder
from zigpy.zcl import ClusterType

from zhaquirks.const import (
    CLUSTER_ID,
    COMMAND,
    COMMAND_MOVE,
    COMMAND_MOVE_ON_OFF,
    COMMAND_OFF,
    COMMAND_ON,
    COMMAND_PRESS,
    COMMAND_STOP,
    COMMAND_STOP_ON_OFF,
    DIM_DOWN,
    DIM_UP,
    DOUBLE_PRESS,
    ENDPOINT_ID,
    LONG_PRESS,
    LONG_RELEASE,
    PARAMS,
    SHORT_PRESS,
    TURN_OFF,
    TURN_ON,
)
from zhaquirks.ikea import IKEA, DoublingPowerConfig2AAACluster, ScenesCluster

(
    QuirkBuilder(IKEA, "09B9")
    .applies_to(IKEA, "09BA")
    .replaces(DoublingPowerConfig2AAACluster)  # will only double for old firmware
    .replaces(ScenesCluster, cluster_type=ClusterType.Client)
    .device_automation_triggers(
        {
            (SHORT_PRESS, TURN_ON): {
                COMMAND: COMMAND_ON,
                CLUSTER_ID: 6,
                ENDPOINT_ID: 1,
            },
            (LONG_PRESS, DIM_UP): {
                COMMAND: COMMAND_MOVE_ON_OFF,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 0},
            },
            (LONG_RELEASE, DIM_UP): {
                COMMAND: COMMAND_STOP_ON_OFF,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_UP): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 256,
                    "param2": 13,
                    "param3": 0,
                },
            },
            (SHORT_PRESS, TURN_OFF): {
                COMMAND: COMMAND_OFF,
                CLUSTER_ID: 6,
                ENDPOINT_ID: 1,
            },
            (LONG_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 1},
            },
            (LONG_RELEASE, DIM_DOWN): {
                COMMAND: COMMAND_STOP_ON_OFF,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 257,
                    "param2": 13,
                    "param3": 0,
                },
            },
        }
    )
    .add_to_registry()
)

PS: Bilresa scroll weal is also in the quirk for test only for getting the scene commands OK but no DA is implemented for it (double and tipple press).

@MattWestb
Copy link
Contributor

Very true @mkz212 and i hope its working for all lights and upcoming plugs but we will see in the future. IKEA have not implemented OTA cluster (and stripped other tings 2 like manufacture name and so on) on the devise i have looking on but updates looks working OK from Matter for the device that is having new firmware released.
I have testing all "interesting" new devices i can getting and only the Bilresorna (of the new controllers) is activating normal Zigbee paring verified by sniffing zigbee channel 11 for beacon requests (default ZLL paring channel) and can see if the device is looking for open network it can pairing with.
Myggstick and Myggspray i cant getting in pairing mode and i have not testing Timmerflotte and Alpstuga (and Klipbok) then i have only one of them and is in production on Matter (with 0.01°C reporting / 5 minutes) and looks being no deal getting them on Zigbee then working well on thread and Matter multi admin.

@iamjoshk
Copy link
Author

This is interesting.

This is doubling the battery for me to 200%
> .replaces(DoublingPowerConfig2AAACluster) # will only double for old firmware

This is not working for me:

        (LONG_PRESS, DIM_UP): {
            COMMAND: COMMAND_MOVE_ON_OFF,
            CLUSTER_ID: 8,
            ENDPOINT_ID: 1,
            PARAMS: {"move_mode": 0},
        },

though the corresponding DIM_DOWN is working. The zha_event is fired for DIM_UP but the device automation trigger does not trigger. And I am pretty sure it was working for me previously.

I swear last night that the long press release for up and down were both working, but I might have just been looking at one trigger fire at a time. It was late. 😄

Double clicks are working! 👍 👍

I am going to dig into this a bit more.

All working except move DAs that is broken in zigpy and dim down long release triggering long up release:

"""IKEA Bilresa 2 button remote control."""

from zigpy.quirks.v2 import QuirkBuilder
from zigpy.zcl import ClusterType

from zhaquirks.const import (
    CLUSTER_ID,
    COMMAND,
    COMMAND_MOVE,
    COMMAND_MOVE_ON_OFF,
    COMMAND_OFF,
    COMMAND_ON,
    COMMAND_PRESS,
    COMMAND_STOP,
    COMMAND_STOP_ON_OFF,
    DIM_DOWN,
    DIM_UP,
    DOUBLE_PRESS,
    ENDPOINT_ID,
    LONG_PRESS,
    LONG_RELEASE,
    PARAMS,
    SHORT_PRESS,
    TURN_OFF,
    TURN_ON,
)
from zhaquirks.ikea import IKEA, DoublingPowerConfig2AAACluster, ScenesCluster

(
    QuirkBuilder(IKEA, "09B9")
    .applies_to(IKEA, "09BA")
    .replaces(DoublingPowerConfig2AAACluster)  # will only double for old firmware
    .replaces(ScenesCluster, cluster_type=ClusterType.Client)
    .device_automation_triggers(
        {
            (SHORT_PRESS, TURN_ON): {
                COMMAND: COMMAND_ON,
                CLUSTER_ID: 6,
                ENDPOINT_ID: 1,
            },
            (LONG_PRESS, DIM_UP): {
                COMMAND: COMMAND_MOVE_ON_OFF,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 0},
            },
            (LONG_RELEASE, DIM_UP): {
                COMMAND: COMMAND_STOP_ON_OFF,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_UP): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 256,
                    "param2": 13,
                    "param3": 0,
                },
            },
            (SHORT_PRESS, TURN_OFF): {
                COMMAND: COMMAND_OFF,
                CLUSTER_ID: 6,
                ENDPOINT_ID: 1,
            },
            (LONG_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 1},
            },
            (LONG_RELEASE, DIM_DOWN): {
                COMMAND: COMMAND_STOP_ON_OFF,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 257,
                    "param2": 13,
                    "param3": 0,
                },
            },
        }
    )
    .add_to_registry()
)

PS: Bilresa scroll weal is also in the quirk for test only for getting the scene commands OK but no DA is implemented for it (double and tipple press).

@MattWestb
Copy link
Contributor

Was testing some "native" IKEA Zigbee controllers that use "IKEA scene" and all is sending the same events but the DA is broken for all (move with and without off) and TS004F is using step and also looks broken.
Then the bug is fixed we have all in !!!

The battery remaining im not 100% if its reporting 100 for full or true Zigbee = 200 for full and 256 for NA and displaying it *0.5 but i think its more bad implemented hard / software then the readings looks the same then connected with Matter.

If you are good with coding implementing the function from Open/Close that "remember" the last up/down long pressed and tagging the release with it its only some line of code but im not one code worrier so cant doing it.

You are correct i was doing the normal copy/past thing.

Up:

  endpoint_id: 1
  cluster_id: 8
  command: move
  args:
    - 0
    - 83
  params:
    move_mode: 0
    rate: 83
    options_mask: null
    options_override: null

Down:

  endpoint_id: 1
  cluster_id: 8
  command: move
  args:
    - 1
    - 83
  params:
    move_mode: 1
    rate: 83
    options_mask: null
    options_override: null

And cant testing it then the DA for move is not working.

@iamjoshk
Copy link
Author

I removed the device, restarted HA again, then re-paired the device again.

Removing this fixes the battery percentage doubling.

     .replaces(DoublingPowerConfig2AAACluster)  # will only double for old firmware 

These are all working for me (except for long press dim down release for the reason you noted):

    .device_automation_triggers(
        {
            (SHORT_PRESS, TURN_ON): {
                COMMAND: COMMAND_ON,
                CLUSTER_ID: 6,
                ENDPOINT_ID: 1,
            },
            (LONG_PRESS, DIM_UP): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 0},
            },
            (LONG_RELEASE, DIM_UP): {
                COMMAND: COMMAND_STOP_ON_OFF,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_UP): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 256,
                    "param2": 13,
                    "param3": 0,
                },
            },
            (SHORT_PRESS, TURN_OFF): {
                COMMAND: COMMAND_OFF,
                CLUSTER_ID: 6,
                ENDPOINT_ID: 1,
            },
            (LONG_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 1},
            },
            (LONG_RELEASE, DIM_DOWN): {
                COMMAND: COMMAND_STOP,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 257,
                    "param2": 13,
                    "param3": 0,
                },
            },
        }
    )

I will look into the code that remembers the last long press.

@MattWestb
Copy link
Contributor

Was fixing the long press up with only move and restarting HA and adding one automation for it and its working with notification being triggered so all is in now !!!
So the DA for move is not being logged as all other DAs but it working OK so i shall closing my bug report on it.
The batters % is up to you and the maintainers how they like to do it i only observing what is happening.

Only think i dont like turn On/Off / DimUp/Down for the same button (the name of it that is showing up in the automation).

@iamjoshk
Copy link
Author

iamjoshk commented Dec 31, 2025

Thanks for the hint about remembering the move command that started the long press.

"""IKEA Bilresa 2 button remote control."""
from typing import Any, Optional, Union

from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import QuirkBuilder, CustomDeviceV2
import zigpy.types as t
from zigpy.zcl import ClusterType, foundation
from zigpy.zcl.clusters.general import LevelControl

from zhaquirks.ikea import IKEA, ScenesCluster

from zhaquirks.const import (
    CLUSTER_ID,
    COMMAND,
    COMMAND_MOVE,
    COMMAND_OFF,
    COMMAND_ON,
    COMMAND_PRESS,
    DOUBLE_PRESS,
    DIM_DOWN,
    DIM_UP,
    ENDPOINT_ID,
    LONG_PRESS,
    LONG_RELEASE,
    PARAMS,
    SHORT_PRESS,
    TURN_OFF,
    TURN_ON,
    ZHA_SEND_EVENT,
)


class IkeaBilresaLevelControl(CustomCluster, LevelControl):
    """Custom LevelControl cluster for Bilresa remote to track direction."""

    def __init__(self, *args, **kwargs):
        """Initialize instance."""
        super().__init__(*args, **kwargs)
        self._last_move_direction = None

    def handle_cluster_request(
        self,
        hdr: foundation.ZCLHeader,
        args: list[Any],
        *,
        dst_addressing: Optional[
            Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
        ] = None,
    ) -> None:
        """Handle cluster specific commands.
        
        Track move commands to remember direction for stop commands"""
        if hdr.command_id == 0x01:
            move_mode = args[0]
            self._last_move_direction = move_mode
        elif hdr.command_id == 0x05:
            move_mode = args[0]
            self._last_move_direction = move_mode
        elif hdr.command_id in (0x03, 0x07):
            if self._last_move_direction == 0:
                self.listener_event(ZHA_SEND_EVENT, "move_up_release", [])
            elif self._last_move_direction == 1:
                self.listener_event(ZHA_SEND_EVENT, "move_down_release", [])

class IkeaBilresa2ButtonRemote(CustomDeviceV2):
    """Custom device for IKEA Bilresa 2 button remote."""

(
    QuirkBuilder(IKEA, "09B9")
    .replaces(ScenesCluster, cluster_type=ClusterType.Client)
    .replace_cluster_occurrences(IkeaBilresaLevelControl)
    .device_automation_triggers(
        {
            (SHORT_PRESS, TURN_ON): {COMMAND: COMMAND_ON, CLUSTER_ID: 6, ENDPOINT_ID: 1},
            (LONG_PRESS, DIM_UP): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 0},
            },
            (LONG_RELEASE, DIM_UP): {
                COMMAND: "move_up_release",
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (SHORT_PRESS, TURN_OFF): {COMMAND: COMMAND_OFF, CLUSTER_ID: 6, ENDPOINT_ID: 1},
            (LONG_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 1},
            },
            (LONG_RELEASE, DIM_DOWN): {
                COMMAND: "move_down_release",
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_UP): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 256,
                    "param2": 13,
                    "param3": 0,
                },
            },
            (DOUBLE_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 257,
                    "param2": 13,
                    "param3": 0,
                },
            },
        } 
    )
    .add_to_registry()
)

This should be working for the long press releases. 👍

I removed the battery adjustment because it is definitely doubling it for me. Maybe there needs to be some other adjustment made to how it's calculated; I am not sure.

EDIT: pasted wrong quirk version

@MattWestb
Copy link
Contributor

Was adding the double and restarting HA and doing DA for long press up and down and all is working great !!!!

Was looking more on the scroll weal but we is missing move to level command that need being added in the consts so not easy testing then must patching little and only fir getting not good working functionality so no go for the moment.

@MattWestb
Copy link
Contributor

MattWestb commented Dec 31, 2025

One question.
Can you move the new class IkeaBilresaLevelControl(CustomCluster, LevelControl): down to IKEA init so we can using it for more devices like normal 2 button dimer and Rodret and dont need writing your working code in more places ???
We have don the same with the "extended scene" and shortcust button functionality then its used for more devices.

@iamjoshk
Copy link
Author

One question. Can you move the new class IkeaBilresaLevelControl(CustomCluster, LevelControl): down to IKEA init so we can using it for more devices like normal 2 button dimer and Rodret and dont need writing your working code in more places ??? We have don the same with the "extended scene" and shortcust button functionality then its used for more devices.

I can do that, but to be clear, that means the quirk in this PR can't be used until the PR is (hopefully) merged, correct? If people want to use a custom quirk for this before it is merged then they'd need to use a version with the level control in the quirk.

@MattWestb
Copy link
Contributor

That shall not being any problem if they is using the last version you posted it have it inside so working as "standalone".
I have not the knowledge doing more advance coding then copy / paste but if i understand how its working then i do it for the other devices that getting better functionality.

@iamjoshk
Copy link
Author

Here is a working standalone quirk until this is (hopefully) merged:

"""IKEA Bilresa 2 button remote control."""
from typing import Any, Optional, Union

from zigpy.quirks import CustomCluster
from zigpy.quirks.v2 import QuirkBuilder, CustomDeviceV2
import zigpy.types as t
from zigpy.zcl import ClusterType, foundation
from zigpy.zcl.clusters.general import LevelControl

from zhaquirks.ikea import IKEA, ScenesCluster

from zhaquirks.const import (
    CLUSTER_ID,
    COMMAND,
    COMMAND_MOVE,
    COMMAND_OFF,
    COMMAND_ON,
    COMMAND_PRESS,
    DOUBLE_PRESS,
    DIM_DOWN,
    DIM_UP,
    ENDPOINT_ID,
    LONG_PRESS,
    LONG_RELEASE,
    PARAMS,
    SHORT_PRESS,
    TURN_OFF,
    TURN_ON,
    ZHA_SEND_EVENT,
)

class IkeaBilresaLevelControl(CustomCluster, LevelControl):
    """Custom LevelControl cluster for IKEA remotes to track direction."""

    def __init__(self, *args, **kwargs):
        """Initialize instance."""
        super().__init__(*args, **kwargs)
        self._last_move_direction = None

    def handle_cluster_request(
        self,
        hdr: foundation.ZCLHeader,
        args: list[Any],
        *,
        dst_addressing: Optional[
            Union[t.Addressing.Group, t.Addressing.IEEE, t.Addressing.NWK]
        ] = None,
    ) -> None:
        """Handle cluster specific commands.

        Track move commands to remember direction for stop commands
        """
        if hdr.command_id in (0x01, 0x05):
            move_mode = args[0]
            self._last_move_direction = move_mode
        elif hdr.command_id in (0x03, 0x07) and self._last_move_direction is not None:
            event = (
                "move_up_release"
                if self._last_move_direction == 0
                else "move_down_release"
            )
            self.listener_event(ZHA_SEND_EVENT, event, [])

class IkeaBilresa2ButtonRemote(CustomDeviceV2):
    """Custom device for IKEA Bilresa 2 button remote."""

(
    QuirkBuilder(IKEA, "09B9")
    .replaces(ScenesCluster, cluster_type=ClusterType.Client)
    .replace_cluster_occurrences(IkeaBilresaLevelControl)
    .device_automation_triggers(
        {
            (SHORT_PRESS, TURN_ON): {
                COMMAND: COMMAND_ON, 
                CLUSTER_ID: 6, 
                ENDPOINT_ID: 1
            },
            (LONG_PRESS, DIM_UP): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 0},
            },
            (LONG_RELEASE, DIM_UP): {
                COMMAND: "move_up_release",
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (SHORT_PRESS, TURN_OFF): {
                COMMAND: COMMAND_OFF, 
                CLUSTER_ID: 6, 
                ENDPOINT_ID: 1
            },
            (LONG_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_MOVE,
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
                PARAMS: {"move_mode": 1},
            },
            (LONG_RELEASE, DIM_DOWN): {
                COMMAND: "move_down_release",
                CLUSTER_ID: 8,
                ENDPOINT_ID: 1,
            },
            (DOUBLE_PRESS, DIM_UP): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 256,
                    "param2": 13,
                    "param3": 0,
                },
            },
            (DOUBLE_PRESS, DIM_DOWN): {
                COMMAND: COMMAND_PRESS,
                CLUSTER_ID: 5,
                ENDPOINT_ID: 1,
                PARAMS: {
                    "param1": 257,
                    "param2": 13,
                    "param3": 0,
                },
            },
        } 
    )
    .add_to_registry()
)

@MattWestb
Copy link
Contributor

Great work done !!!

and large thanks for getting all working well.
and happy new year !!!!

@iamjoshk
Copy link
Author

Thanks for your help!
Happy New Year!

Copy link
Contributor

@MattWestb MattWestb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good done and large thanks for making the "remember last long pressed" in IKEA init so we can using it for other devices that dont have it implemented.

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.

3 participants