Repository: zigpy/zha-device-handlers

Issue:
[BUG] New yooksmart D10110 inverted with quirk
**Describe the bug**
I purchased a new yooksmart D10110 cover and paired with home assistant. The controls
seemed inverted and I had to move the bar twice in order to get it to move. I read reports
in the past with the suggestion to unpair and pair again, tried multiple times with no luck.
So I disabled the quirk (apologies for the brute force: moved the file to a different directory
and reloaded) and it works now. For completeness:
Before:
- buttons up and down wouldn't work
- available button would be inverted (e.g.: cover was all the way down and the down button was enabled)
- in order to control the cover I'd move the progress bar all the way to 0 or to 100 then the opposite in order to work
After:
- buttons up and down work
- enabled button matches the direction of the cover: if open, it shows down button enabled

**To Reproduce**
Behavior is consistent across multiple pair/unpair cycles and full home assistant instance restarts

**Additional context**
Something that is possible, since the cover is new, is that they corrected the behavior in their firmware
and the quirk isn't needed anymore.
This device has:  Firmware: 0x10013001

I can provide any debugging necessary. I'm using homeassistant official virtual machine image and keeping
it up to date.

Editted: formatting


Discussion:
I'm about to buy these and was wondering: how did you disable the quirk? Can you write the steps for a beginner?

Also, are [these](https://www.amazon.com/Yoolax-Motorized-Free-Stop-Cordless-Rechargeable/dp/B07QZDXJBQ?th=1) the right kind? I'm confused about the naming `yooksmart D10110` vs the `Yoolax` on Amazon. But when following the amazon.com link on the [blakadder device database](https://zigbee.blakadder.com/Yookee_D10110.html) it leads to the Yoolax ones on Amazon. Given the `yoo` part is the same I assume that's the same motors?
That one should work as well, I picked [this](https://www.amazon.com/gp/product/B07QP5M7YC) one, but it seems
the only change is the style. Pick the P440-US motor that can connect directly through zigbee.

As noted on my initial comment, the way I did is ugly and will be reverted by a future upgrade. These are the
steps:
```
1) Get a shell in the system (I use the kvm image, so virsh console <virtual machine name>):
    homeassistant login: root
    Last login: Tue Jan 25 14:50:00 UTC 2022 on ttyS0
    Last login: Mon Feb  7 14:51:33 on ttyS0
    Welcome to Home Assistant OS.

    Use `ha` to access the Home Assistant CLI.
    # 
2) Move the file to a backup directory:
    # for i in $(find / -name D10110blinds.py); do dir=$(dirname $i); mkdir $dir/.backup; mv $i $dir/.backup/; done
3) Restart homeassistant
```
The correct way would be changing the quirk to not load on this firmware version but since I
just have this one, I can't confirm the ones that need the quirk have a different firmware version.

Awesome thank you so much for the detailed description! Since you recently bought and I’m about to buy I think I’d get the same firmware version where I have to circumvent this quirk.
I work for yooksmart which is known as the selling brand Yoolax. We have confirmed the issue and will publish new firmware. So you guys need no bother. By the way, the issue is located due to the script of Smartthings which can choose whether or not to invert the direction. we learned the wrong logic obviously.
Cool! How can we update the firmware?
Also, since you work for them: they frequently disconnect for me and reconnecting them always takes a long time of trial and error. Is there any trick to it?
I was having the same issue, and solved it in a similar fashion.

@JeremeLau, I presume you mean firmware inside the shade. Is that field upgradable? Is there a way to find out what firmware is in the shade? I'm about to purchase six more shades, but I'm concerned I'll end up with shades that behave differently from each other.

I'm not sure if it's relevant, but the shade I installed has the motor/charging port on the left side.
> Cool! How can we update the firmware? Also, since you work for them: they frequently disconnect for me and reconnecting them always takes a long time of trial and error. Is there any trick to it?

Sorry for the inconvenience. We noticed maybe the paring trigger action is too complex and not easy to make it right every time. We're reconsidering a new paring way, wish can reduce the frequency.
For the new firmware, since we add more interesting funs, it's still under test.
> I was having the same issue, and solved it in a similar fashion.
> 
> @JeremeLau, I presume you mean firmware inside the shade. Is that field upgradable? Is there a way to find out what firmware is in the shade? I'm about to purchase six more shades, but I'm concerned I'll end up with shades that behave differently from each other.
> 
> I'm not sure if it's relevant, but the shade I installed has the motor/charging port on the left side.

Yes, indeed. The new firmware I mean is the motor firmware itself. Our motor does have the ability to be upgraded over the air or over the USB port. As I mentioned above, it's still under test. If you don't need them urgently, we suggest you can wait until it's ready. 
Of course, if you would like to test the beta firmware, we'll be appreciated and will guide you to do so. 
@JeremeLau I’m interested in testing the beta firmware! I have lots of these shades and am really interested in getting it right!
> @JeremeLau I’m interested in testing the beta firmware! I have lots of these shades and am really interested in getting it right!

I'm so sorry, the BOSS rejected the application of spread of beta firmware before fully self-test. Pls, be patient. I'll handle this ASAP.
Just FYI: I purchased eight shades. One as a trial about six weeks ago and then seven more. The seven arrived last week, and I mounted them over the weekend. They all have Firmware: 0x12013001 incl. the first one that came a few weeks ago, and all suffer from the same issue.

@aristeu : Is the removal of the quirk a one-time thing before registering them, or will I have to remove it with every update to HA?

I assume the firmware update would be the best option for me as my Conbee Stick is in the garage, and the blinds are mounted now. Re-registering would mean I have to take them all off again, would it not?

Until the firmware is available, I have created templates in Homeassistant for each shade that correct the problem.

```
platform: template
covers:
  ingo_office_shades_status:
    device_class: blind
    friendly_name: "Ingo Office Shades Status"
    position_template: >
      {{100 - state_attr('cover.ingo_office_shades','current_position')|int(100)}}
    value_template: >
      {{ (100 - state_attr('cover.ingo_office_shades','current_position') | int(100)) > 95 }}
    set_cover_position:
      service: cover.set_cover_position
      data_template:
        entity_id: cover.ingo_office_shades
        postion: >
          {{ 100 - position }}
    open_cover:
      service: cover.open_cover
      data: {}
      target:
        entity_id: cover.ingo_office_shades
    close_cover:
      service: cover.close_cover
      data: {}
      target:
        entity_id: cover.ingo_office_shades
    stop_cover:
      service: cover.stop_cover
      data: {}
      target:
        entity_id: cover.ingo_office_shades
    icon_template: >
      {% if is_state('cover.ingo_office_shades', 'closed') %}
         mdi:blinds-open
      {% else %}
         mdi:blinds
      {% endif %}
```
> @aristeu : Is the removal of the quirk a one-time thing before registering them, or will I have to remove it with every update to HA?

Unfortunately an update can overwrite it. Unless we can pinpoint firmware version in order to update the quirk to only apply to
firmwares that need it, I think the only way would be adding an option to disable the quirk manually. At least it'd live through
updates.
I vote for `rm -r zhaquirks/yooksmart`. I just ordered another set of the [Graywind blinds on Amazon](https://a.co/d/iiD27N4) and they came with a new motor and a new firmware. They have the same device identifier `("yooksmart", "D10110")`. But again the motors report the correct percentage and no quirk is needed. I now think this quirk was added in error in the first place and actually more people need to remove the quirk than need the quirk.

My current workaround is to mount an empty `yooksmart` directory via my HA docker compose file like so
```
    volumes:
      - ./deps/zhaquirks/yooksmart:/usr/local/lib/python3.10/site-packages/zhaquirks/yooksmart
```
which seems like an unnecessary workaround.

I have a set of old Yooksmart Zigbee motors that have firmware `0x11013001` and a set of new Yooksmart Zigbee motors that have firmware `0x11206780`.

@JeremeLau are there any instructions how I can upgrade my old firmware motors to the new one?

Resolving patch:
diff --git a/zhaquirks/yooksmart/D10110blinds.py b/zhaquirks/yooksmart/D10110blinds.py
deleted file mode 100644
--- a/zhaquirks/yooksmart/D10110blinds.py
+++ /dev/null
@@ -1,87 +0,0 @@
-"""Device handler for Yooksmart D10110 roller blinds."""
-from zigpy.profiles import zha
-from zigpy.quirks import CustomCluster, CustomDevice
-from zigpy.zcl.clusters.closures import WindowCovering
-from zigpy.zcl.clusters.general import (
-    Basic,
-    Groups,
-    Identify,
-    Ota,
-    PollControl,
-    PowerConfiguration,
-    Scenes,
-)
-
-from zhaquirks.const import (
-    DEVICE_TYPE,
-    ENDPOINTS,
-    INPUT_CLUSTERS,
-    MODELS_INFO,
-    OUTPUT_CLUSTERS,
-    PROFILE_ID,
-)
-
-
-class InvertedWindowCoveringCluster(CustomCluster, WindowCovering):
-    """WindowCovering cluster implementation.
-
-    This implementation inverts the reported covering percent for non standard
-    devices that don't follow the reporting spec.
-    """
-
-    cluster_id = WindowCovering.cluster_id
-    CURRENT_POSITION_LIFT_PERCENTAGE = 0x0008
-
-    def _update_attribute(self, attrid, value):
-        if attrid == self.CURRENT_POSITION_LIFT_PERCENTAGE:
-            value = 100 - value
-        super()._update_attribute(attrid, value)
-
-
-class D10110Blinds(CustomDevice):
-    """Custom device representing Yooksmart D10110 roller blinds."""
-
-    signature = {
-        # <SimpleDescriptor endpoint=1 profile=260 device_type=514
-        # device_version=1
-        # input_clusters=[0, 1, 3, 4, 5, 32, 258]
-        # output_clusters=[3, 25]>
-        MODELS_INFO: [
-            ("yooksmart", "D10110"),
-        ],
-        ENDPOINTS: {
-            1: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
-                INPUT_CLUSTERS: [
-                    Basic.cluster_id,
-                    PowerConfiguration.cluster_id,
-                    Identify.cluster_id,
-                    Groups.cluster_id,
-                    Scenes.cluster_id,
-                    PollControl.cluster_id,
-                    WindowCovering.cluster_id,
-                ],
-                OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
-            }
-        },
-    }
-
-    replacement = {
-        ENDPOINTS: {
-            1: {
-                PROFILE_ID: zha.PROFILE_ID,
-                DEVICE_TYPE: zha.DeviceType.WINDOW_COVERING_DEVICE,
-                INPUT_CLUSTERS: [
-                    Basic.cluster_id,
-                    PowerConfiguration.cluster_id,
-                    Identify.cluster_id,
-                    Groups.cluster_id,
-                    Scenes.cluster_id,
-                    PollControl.cluster_id,
-                    InvertedWindowCoveringCluster,
-                ],
-                OUTPUT_CLUSTERS: [Identify.cluster_id, Ota.cluster_id],
-            }
-        }
-    }
diff --git a/zhaquirks/yooksmart/__init__.py b/zhaquirks/yooksmart/__init__.py
deleted file mode 100644
--- a/zhaquirks/yooksmart/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""Yooksmart module for custom device handlers."""


Test patch: