Ikea Styrbar Force OTA if on V1.0.024

I think it worked now, thanks

So went trough the whole update process and still on 1.0.024. Saw the update in the log till 100%. Must be doing something wrong.

2023-03-11 17:41:35.343 DEBUG (MainThread) [zigpy.zcl] [0xABBB:1:0x0019] OTA upgrade_end handler for 'IKEA of Sweden Remote Control N2': status=Status.SUCCESS, manufacturer_id=4476, image_type=4555, file_version=581

2023-03-11 17:41:35.344 DEBUG (MainThread) [zigpy.zcl] [0xABBB:1:0x0019] Sending reply header: ZCLHeader(frame_control=FrameControl(frame_type=<FrameType.CLUSTER_COMMAND: 1>, is_manufacturer_specific=False, direction=<Direction.Client_to_Server: 1>, disable_default_response=1, reserved=0, *is_cluster=True, *is_general=False, *is_reply=True), tsn=1, command_id=7, *direction=<Direction.Client_to_Server: 1>, *is_reply=True)

2023-03-11 17:41:35.344 DEBUG (MainThread) [zigpy.zcl] [0xABBB:1:0x0019] Sending reply: upgrade_end_response(manufacturer_code=4476, image_type=4555, file_version=581, current_time=0, upgrade_time=0)

file_version=581 is this right?

1 Like

I had to re-pair my device after update ':slight_smile: try that

Also follow this post afterwards to fix the battery showing as above 100%

Do we still need to apply this manual quirk workaround as of 2023.4 ?

Good question. My N2’s are now reporting 128% battery level. And the custom quirk is reporting exceptions. :rofl:

Logger: zhaquirks
Source: custom_zha_quirks/fourbtnremote.py:44
First occurred: 25 April 2023 at 08:23:49 (1 occurrences)
Last logged: 25 April 2023 at 08:23:49

Unexpected exception importing custom quirk 'fourbtnremote'
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/zhaquirks/__init__.py", line 454, in setup
    importer.find_module(modname).load_module(modname)
  File "<frozen importlib._bootstrap_external>", line 548, in _check_name_wrapper
  File "<frozen importlib._bootstrap_external>", line 1063, in load_module
  File "<frozen importlib._bootstrap_external>", line 888, in load_module
  File "<frozen importlib._bootstrap>", line 290, in _load_module_shim
  File "<frozen importlib._bootstrap>", line 719, in _load
  File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 883, in exec_module
  File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
  File "/config/custom_zha_quirks/fourbtnremote.py", line 44, in <module>
    from zhaquirks.ikea import (
ImportError: cannot import name 'PowerConfiguration2AAACluster' from 'zhaquirks.ikea' (/usr/local/lib/python3.10/site-packages/zhaquirks/ikea/__init__.py)

I fixed the 128% battery level and quirk exception issues by changing fourbtnremote.py, replacing all occurrences of “PowerConfiguration2AAACluster” with “DoublingPowerConfig2AAACluster” and restarting HA.

The modified custom_zha_quirks\fourbtnremote.py file is as follows:

"""Device handler for IKEA of Sweden TRADFRI remote control."""
from zigpy.profiles import zha
from zigpy.quirks import CustomDevice
from zigpy.zcl.clusters.general import (
    Basic,
    Identify,
    LevelControl,
    OnOff,
    Ota,
    PollControl,
    PowerConfiguration,
)
from zigpy.zcl.clusters.lightlink import LightLink

from zhaquirks.const import (
    CLUSTER_ID,
    COMMAND,
    COMMAND_HOLD,
    COMMAND_MOVE,
    COMMAND_MOVE_ON_OFF,
    COMMAND_OFF,
    COMMAND_ON,
    COMMAND_PRESS,
    COMMAND_STOP,
    COMMAND_STOP_ON_OFF,
    DEVICE_TYPE,
    DIM_DOWN,
    DIM_UP,
    ENDPOINT_ID,
    ENDPOINTS,
    INPUT_CLUSTERS,
    LEFT,
    LONG_PRESS,
    LONG_RELEASE,
    MODELS_INFO,
    OUTPUT_CLUSTERS,
    PARAMS,
    PROFILE_ID,
    RIGHT,
    SHORT_PRESS,
    TURN_OFF,
    TURN_ON,
)
from zhaquirks.ikea import (
    IKEA,
    IKEA_CLUSTER_ID,
    WWAH_CLUSTER_ID,
    DoublingPowerConfig2AAACluster,
    ScenesCluster,
)

from zhaquirks import DoublingPowerConfigurationCluster

class DoublingPowerConfig2AAAClusterSTYRBAR_2_4_5(DoublingPowerConfigurationCluster):
    """Updating Power attributes 2 AAA."""
    """And for STYRBAR V2.4.5 as it scales battery voltage between 0-255."""

    BATTERY_SIZES = 0x0031
    BATTERY_QUANTITY = 0x0033
    BATTERY_RATED_VOLTAGE = 0x0034
    
    BATTERY_PERCENTAGE_REMAINING  = 0x0021

    _CONSTANT_ATTRIBUTES = {
        BATTERY_SIZES: 4,
        BATTERY_QUANTITY: 2,
        BATTERY_RATED_VOLTAGE: 15,
    }

    def _update_attribute(self, attrid, value):
        if attrid == self.BATTERY_PERCENTAGE_REMAINING:
            value = (value / 255) * 100
        super()._update_attribute(attrid, value)


class IkeaTradfriRemoteV1(CustomDevice):
    """Custom device representing IKEA of Sweden TRADFRI remote control V1.0.024."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=820
        # device_version=1
        # input_clusters=[0, 1, 3, 32, 4096, 64599]
        # output_clusters=[3, 6, 8, 25, 4096]>
        MODELS_INFO: [(IKEA, "Remote Control N2")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.NON_COLOR_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    LightLink.cluster_id,
                    WWAH_CLUSTER_ID,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    OnOff.cluster_id,
                    LevelControl.cluster_id,
                    Ota.cluster_id,
                    LightLink.cluster_id,
                ],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.NON_COLOR_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DoublingPowerConfig2AAACluster,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    LightLink.cluster_id,
                    WWAH_CLUSTER_ID,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    ScenesCluster,
                    OnOff.cluster_id,
                    LevelControl.cluster_id,
                    Ota.cluster_id,
                    LightLink.cluster_id,
                ],
            }
        }
    }

    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,
        },
        (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,
        },
        (SHORT_PRESS, LEFT): {
            COMMAND: COMMAND_PRESS,
            CLUSTER_ID: 5,
            ENDPOINT_ID: 1,
            PARAMS: {
                "param1": 257,
                "param2": 13,
                "param3": 0,
            },
        },
        (LONG_PRESS, LEFT): {
            COMMAND: COMMAND_HOLD,
            CLUSTER_ID: 5,
            ENDPOINT_ID: 1,
            PARAMS: {
                "param1": 3329,
                "param2": 0,
            },
        },
        (SHORT_PRESS, RIGHT): {
            COMMAND: COMMAND_PRESS,
            CLUSTER_ID: 5,
            ENDPOINT_ID: 1,
            PARAMS: {
                "param1": 256,
                "param2": 13,
                "param3": 0,
            },
        },
        (LONG_PRESS, RIGHT): {
            COMMAND: COMMAND_HOLD,
            CLUSTER_ID: 5,
            ENDPOINT_ID: 1,
            PARAMS: {
                "param1": 3328,
                "param2": 0,
            },
        },
    }


class IkeaTradfriRemoteV2(CustomDevice):
    """Custom device representing IKEA of Sweden TRADFRI remote control Version 2.4.5."""

    signature = {
        # <SimpleDescriptor endpoint=1 profile=260 device_type=820
        # device_version=1
        # input_clusters=[0, 1, 3, 32, 4096, 64599, 64636]
        # output_clusters=[3, 5, 6, 8, 25, 4096]>
        MODELS_INFO: [(IKEA, "Remote Control N2")],
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.NON_COLOR_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    PowerConfiguration.cluster_id,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    LightLink.cluster_id,
                    WWAH_CLUSTER_ID,
                    IKEA_CLUSTER_ID,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    ScenesCluster.cluster_id,
                    OnOff.cluster_id,
                    LevelControl.cluster_id,
                    Ota.cluster_id,
                    LightLink.cluster_id,
                ],
            }
        },
    }

    replacement = {
        ENDPOINTS: {
            1: {
                PROFILE_ID: zha.PROFILE_ID,
                DEVICE_TYPE: zha.DeviceType.NON_COLOR_CONTROLLER,
                INPUT_CLUSTERS: [
                    Basic.cluster_id,
                    DoublingPowerConfig2AAAClusterSTYRBAR_2_4_5,
                    Identify.cluster_id,
                    PollControl.cluster_id,
                    LightLink.cluster_id,
                    WWAH_CLUSTER_ID,
                    IKEA_CLUSTER_ID,
                ],
                OUTPUT_CLUSTERS: [
                    Identify.cluster_id,
                    ScenesCluster,
                    OnOff.cluster_id,
                    LevelControl.cluster_id,
                    Ota.cluster_id,
                    LightLink.cluster_id,
                ],
            }
        }
    }

    device_automation_triggers = IkeaTradfriRemoteV1.device_automation_triggers.copy()

Hey there,
How did you manage to fix this error?
I’ve got the same problem, but waking up the remote from sleep before issuing the command isn’t working for me.

Managed to finally fix it through trial and error.
I think taking the batteries out of the remote and putting them back in made the remote accept the OTA, almost like a hard reset.
If for some reason the first attempt after putting the batteries in failed or abruptly pauses during the update, then I had to take the batteries out and put them back in again, otherwise I’d just get that error over and over.