Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for QUAD-ZIG-SW from smarthjemmet.dk #3400

Merged
merged 25 commits into from
Feb 6, 2025

Conversation

mortenmoulder
Copy link
Contributor

@mortenmoulder mortenmoulder commented Oct 6, 2024

Proposed change

Add support for smarthjemmet.dk's QUAD-ZIG-SW device.

Additional information

Works with V1 and V2 firmware.

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

Copy link

codecov bot commented Oct 6, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 90.92%. Comparing base (8b3560e) to head (453ea0f).
Report is 4 commits behind head on dev.

Additional details and impacted files
@@            Coverage Diff             @@
##              dev    #3400      +/-   ##
==========================================
+ Coverage   90.91%   90.92%   +0.01%     
==========================================
  Files         325      326       +1     
  Lines       10566    10584      +18     
==========================================
+ Hits         9606     9624      +18     
  Misses        960      960              

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

@mortenmoulder
Copy link
Contributor Author

All should be fixed now. Sorry for all the commits.

@TheJulianJES TheJulianJES added the new quirk Adds support for a new device label Oct 10, 2024
@mortenmoulder
Copy link
Contributor Author

@TheJulianJES I see that a new release was created yesterday, and mine was not included. Any idea why? The only checks failing are code coverage, which shouldn't prevent it from being merged. Was really hoping to get this quirk implemented in the next release, as I'm guessing I have to wait a few more weeks now.

@TheJulianJES
Copy link
Collaborator

There's a few things on this PR that I'd likely change. I just haven't found the time to properly review this PR and comment all small change suggestions. I still plan to do that, of course, but there are also other PRs.
Yesterday's release was just to get some bigger ZHA related changes into nightly HA builds. The quirks related changes were mostly ones that didn't need feedback.

Follows the style of other quirks where there's proper quirk defined in a `CustomDevice` class that's inherited from in other quirks that just change the `signature`, but keep the `replacement` and device triggers.
@TheJulianJES
Copy link
Collaborator

TheJulianJES commented Oct 18, 2024

Ok, so I've pushed multiple commits now. The "refactor" commit changes the structure of the (so-called v1) quirk to have a v1 device class with signature, replacement, and device triggers.
Then, a class for firmware version 2 is added that inherits from the first device class. It just changes the signature.
This is similar to the structure we have in other quirks.

The last commit (as of now) "Replace with v2 quirk" completely replaces the CustomDevice v1 quirks with a v2 quirk.
For it, we don't need to have a fixed signature and replacement. .replaces(CR2032PowerConfigurationCluster) will automatically replace all clusters with the same cluster id on endpoint 1. It's used to replace the default PowerConfiguration cluster with the custom CR2032PowerConfigurationCluster.

.replace_cluster_occurrences(CustomMultistateInputCluster) will look at all endpoints and replace all clusters with the same cluster id (of MultistateInput) it can find.

Please test if that v2 quirk works as expected.


With the v1 quirk before, the MultistateInput cluster was always an output/client cluster in the original signature. In the replacement, it was a input/server cluster then. It was also missing on endpoint 1 in the replacement. I don't think that was intentional?

If the replacement CustomMultistateInputCluster needs to be an input/server cluster (so the role swapped compared the original signature), we can do it like this in a v2 quirk (but for all endpoints):

    .removes(MultistateInput.cluster_id, cluster_type=ClusterType.Client, endpoint_id=1)  # remove output cluster
    .adds(CustomMultistateInputCluster, endpoint_id=1)  # default cluster_type is server, so it'll add an input cluster

The test here is no longer really needed for the v2 quirk. There's no real point in testing if all the correct clusters are included.
Ideally, we would send messages from the device and see if they are converted to "ZHA events" as expected in a test.
Comment on lines 48 to 60
async def bind(self):
"""Prevent bind."""
return zigpy.zcl.foundation.Status.SUCCESS

async def unbind(self):
"""Prevent unbind."""
return zigpy.zcl.foundation.Status.SUCCESS

async def _configure_reporting(self, *args, **kwargs):
"""Prevent remote configure reporting."""
return (
zigpy.zcl.foundation.ConfigureReportingResponse.deserialize(b"\x00")[0],
)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Unrelated to converting the whole quirk to a v2 quirk:
Are these necessary? We already set SKIP_CONFIGURATION = True.

@mortenmoulder
Copy link
Contributor Author

@TheJulianJES Hi and thanks for your effort. Unfortunately it's not working.

When I am talking about V1 and V2 in terms of firmware, it's because I have one physical device with two different firmware versions. The signature of the devices are completely different, which is why I need to be able to support both signatures on the same device. V1 of the firmware came out back in 2023, and now I've updated it in late 2024. Does that make sense?

For all I care, Quirk V1 or Quirk V2 doesn't matter to me. Quirk V2 looks better with the QuirkBuilder - definitely, but unfortunately it's not working as intended in this case.

Regards to your "It was also missing on endpoint 1 in the replacement. I don't think that was intentional" it actually was. The physical device has 5 buttons, but only 4 of them should work as MultistateInput. The last is used for resetting the device, which is done on a firmware level.

@mortenmoulder
Copy link
Contributor Author

And for good measure, here's the old firmware (firmware V1 from 2023)'s device signature:

{
  "node_descriptor": {
    "logical_type": 2,
    "complex_descriptor_available": 0,
    "user_descriptor_available": 0,
    "reserved": 0,
    "aps_flags": 0,
    "frequency_band": 8,
    "mac_capability_flags": 128,
    "manufacturer_code": 4447,
    "maximum_buffer_size": 80,
    "maximum_incoming_transfer_size": 160,
    "server_mask": 0,
    "maximum_outgoing_transfer_size": 160,
    "descriptor_capability_field": 0
  },
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0xfffe",
      "input_clusters": [
        "0x0000",
        "0x0001",
        "0x0007"
      ],
      "output_clusters": [
        "0x0000",
        "0x0001",
        "0x0012"
      ]
    },
    "2": {
      "profile_id": "0x0104",
      "device_type": "0xfffe",
      "input_clusters": [
        "0x0007"
      ],
      "output_clusters": [
        "0x0012"
      ]
    },
    "3": {
      "profile_id": "0x0104",
      "device_type": "0xfffe",
      "input_clusters": [
        "0x0007"
      ],
      "output_clusters": [
        "0x0012"
      ]
    },
    "4": {
      "profile_id": "0x0104",
      "device_type": "0xfffe",
      "input_clusters": [
        "0x0007"
      ],
      "output_clusters": [
        "0x0012"
      ]
    },
    "5": {
      "profile_id": "0x0104",
      "device_type": "0xfffe",
      "input_clusters": [
        "0x0007"
      ],
      "output_clusters": [
        "0x0012"
      ]
    }
  },
  "manufacturer": "smarthjemmet.dk",
  "model": "QUAD-ZIG-SW",
  "class": "zigpy.device.Device"
}

and here is the new firmware V2 (from late 2024) device signature:

{
  "node_descriptor": {
    "logical_type": 2,
    "complex_descriptor_available": 0,
    "user_descriptor_available": 0,
    "reserved": 0,
    "aps_flags": 0,
    "frequency_band": 8,
    "mac_capability_flags": 128,
    "manufacturer_code": 4447,
    "maximum_buffer_size": 80,
    "maximum_incoming_transfer_size": 160,
    "server_mask": 0,
    "maximum_outgoing_transfer_size": 160,
    "descriptor_capability_field": 0
  },
  "endpoints": {
    "1": {
      "profile_id": "0x0104",
      "device_type": "0x0006",
      "input_clusters": [
        "0x0000",
        "0x0001"
      ],
      "output_clusters": [
        "0x0000"
      ]
    },
    "2": {
      "profile_id": "0x0104",
      "device_type": "0x0006",
      "input_clusters": [
        "0x0007",
        "0x0012"
      ],
      "output_clusters": [
        "0x0012"
      ]
    },
    "3": {
      "profile_id": "0x0104",
      "device_type": "0x0006",
      "input_clusters": [
        "0x0007",
        "0x0012"
      ],
      "output_clusters": [
        "0x0012"
      ]
    },
    "4": {
      "profile_id": "0x0104",
      "device_type": "0x0006",
      "input_clusters": [
        "0x0007",
        "0x0012"
      ],
      "output_clusters": [
        "0x0012"
      ]
    },
    "5": {
      "profile_id": "0x0104",
      "device_type": "0x0006",
      "input_clusters": [
        "0x0007",
        "0x0012"
      ],
      "output_clusters": [
        "0x0012"
      ]
    }
  },
  "manufacturer": "smarthjemmet.dk",
  "model": "QUAD-ZIG-SW",
  "class": "QUAD-ZIG-SW.QUAD_ZIG_SW"
}

@TheJulianJES TheJulianJES added the help wanted Extra attention is needed label Oct 18, 2024
@mortenmoulder
Copy link
Contributor Author

mortenmoulder commented Oct 18, 2024

@TheJulianJES Help is not really wanted. What I originally had worked perfectly. Only thing not passing is the code coverage. Is that a requirement to get it merged?

@TheJulianJES
Copy link
Collaborator

TheJulianJES commented Oct 18, 2024

"Help wanted" just means this needs to be looked again. A v2 quirk should work.
And yes, the code should be covered fully. That's not really a big issue though.

@mortenmoulder
Copy link
Contributor Author

Okay I see. Is it for you to look at "at some point" as a reminder? Or someone else? My question really is, do I need to take action?

@TheJulianJES
Copy link
Collaborator

I'll take another look again at this soon. In the mean time, you can try to see if you can make the v2 quirk work if you want.
E.g. by copying/pasting the lines at the bottom from this comment into the quirk (replacing the replace_cluster_occurrences).
(Adding those two lines for endoints (1?) 2, 3, 4, 5.)

Regards to your "It was also missing on endpoint 1 in the replacement. I don't think that was intentional" it actually was. The physical device has 5 buttons, but only 4 of them should work as MultistateInput.

range(1, 6) gives us device triggers for five buttons though. That was also in the original code.
Isn't that one batch of device triggers too many then?
It's also a bit weird, because the original device signature has the MultistateInputCluster on all 5 endpoints (as an output cluster). Could be firmware thing of course, still weird though..

Unfortunately it's not working.

On which HA version did you test the v2 quirk? Did you test it by replacing the whole quirks library or just inserting the one quirks file as a "custom quirk" (using the ZHA config option) (recommended for testing this).
Also, did the quirk apply at least? E.g., in device settings in HA or in the device signature, was there a CustomDeviceV2 quirk used?

@mortenmoulder
Copy link
Contributor Author

mortenmoulder commented Oct 19, 2024

@TheJulianJES I am doing the custom quirk with the ZHA config option. It was matched to the signature of one of the devices I tested (the old V1 firmware), but no events were shown when I pressed the buttons.

Also, I appreciate the help. Let me know if there is anything I can do.

event_args = {VALUE: value}
self.listener_event(ZHA_SEND_EVENT, action, event_args)

super()._update_attribute(0, action)
Copy link
Collaborator

Choose a reason for hiding this comment

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

If the changes work, please also try and see what these additional changes to this line do:

  • replacing 0 with MultistateInput.AttributeDefs.present_value.id in this line (sensor entity in HA?)
  • completely removing this line

I believe this was copied from other quirks where it doesn't actually work, as there is no attribute with id=0 on this cluster.

@OptionHenrik
Copy link

@OptionHenrik Yes, the quirk was working perfectly before @TheJulianJES's changes. Feel free to go look at the commit just before his changes, and grab the file from there to give it a go yourself.

Works like a charm … great work so far even though it’s only a custom quirk. I hope you guys get it integrated into the standard ZHA soon

@TheJulianJES
Copy link
Collaborator

TheJulianJES commented Oct 24, 2024

Please also test the v2 quirk now. It was updated a few days ago.

@TheJulianJES TheJulianJES added waiting for reply Waiting for a reply (e.g. to test a custom quirk) and removed help wanted Extra attention is needed labels Oct 26, 2024
@TheJulianJES TheJulianJES linked an issue Oct 26, 2024 that may be closed by this pull request
@radhus
Copy link

radhus commented Oct 27, 2024

@mortenmoulder can confirm your quirk works with just a model name change for MULTI-ZIG-SW as well! Great job.

I'll try to find time to test out @TheJulianJES changes later.

@bangert
Copy link
Contributor

bangert commented Dec 9, 2024

Any news here on the current version in this PR?

@OptionHenrik
Copy link

Any news here on the current version in this PR?

See my previous comment. Works like a charm with ZHA if you install it as a quirk.

@TheJulianJES
Copy link
Collaborator

It would also be ideal to know if the updated v2 quirk version works correctly now. Then, we'd be able to finally merge this (after I add some tests).

@bangert
Copy link
Contributor

bangert commented Dec 9, 2024

@mortenmoulder would this quirk also work for MULTI-ZIG-SW?

@bangert
Copy link
Contributor

bangert commented Dec 13, 2024

trying to get the latest version of this quirk to work with MULTI-ZIG-SW it doesnt work, and i get the following in the HA logs:

2024-12-13 01:04:27.370 ERROR (MainThread) [homeassistant.components.logbook.processor] Error with zha describe event for zha_event
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/logbook/processor.py", line 259, in _humanify
    data = describe_event(event_cache_get(row))
  File "/usr/src/homeassistant/homeassistant/components/zha/logbook.py", line 73, in async_describe_zha_event
    event_type = event_type.replace("_", " ").title()
                 ^^^^^^^^^^^^^^^^^^
AttributeError: 'bool' object has no attribute 'replace'

this is on HA 2024.12.2

@bangert
Copy link
Contributor

bangert commented Jan 27, 2025

okay - some more feedback. the current quirk (latest version on this PR) does not actually for me on the sister device MULTI-ZIG-SW, but it is recognised if i add two lines. The first is line 28

MODEL_ALT_ID = "MULTI-ZIG-SW"

and its usage on line 58/59

.applies_to(MANUFACTURER, MODEL_ALT_ID)

meaning it will show up as "MULTI-ZIG-SW by smarthjemmet.dk" and show Quirk: zigpy.quirks.v2.CustomDeviceV2 in zigbee info.

Nothing happens when pushing any of the buttons though.

@TheJulianJES TheJulianJES added the needs reviewer answer An answer from a reviewer is needed (e.g. why a PR isn't acceptable in the current state). label Jan 27, 2025
@bangert
Copy link
Contributor

bangert commented Feb 1, 2025

with this patch the quadzigsw.py quirk works for me on a MULTI_ZIG_SW:

--- quadzigsw-orig.py   2025-02-01 06:26:31.211611131 +0100
+++ quadzigsw.py        2025-02-01 06:27:26.903118134 +0100
@@ -25,6 +25,7 @@
 
 MANUFACTURER = "smarthjemmet.dk"
 MODEL_ID = "QUAD-ZIG-SW"
+MODEL_ALT_ID = "MULTI-ZIG-SW"
 
 ACTION_TYPE = {
     0: COMMAND_RELEASE,
@@ -43,20 +44,19 @@
 
 
 class CustomMultistateInputCluster(CustomCluster, MultistateInput):
-    """Multistate input cluster."""
+    """CustomMultistate input cluster."""
 
     def _update_attribute(self, attrid, value):
         super()._update_attribute(attrid, value)
         if attrid == MultistateInput.AttributeDefs.present_value.id:
-            if action := ACTION_TYPE.get(value) is not None:
+            if (action := ACTION_TYPE.get(value)) is not None:
                 event_args = {VALUE: value}
                 self.listener_event(ZHA_SEND_EVENT, action, event_args)
 
-            super()._update_attribute(0, action)
-
 
 (
     QuirkBuilder(MANUFACTURER, MODEL_ID)
+    .applies_to(MANUFACTURER, MODEL_ALT_ID)
     .skip_configuration()
     .replaces(CR2032PowerConfigurationCluster)
     .removes(MultistateInput.cluster_id, cluster_type=ClusterType.Client, endpoint_id=2)

@TheJulianJES TheJulianJES self-assigned this Feb 1, 2025
@TheJulianJES TheJulianJES added the needs review This PR should be reviewed soon, as it generally looks good. label Feb 1, 2025
@TheJulianJES
Copy link
Collaborator

@bangert Thanks! The issue with the walrus operator was an oversight on my part. I'll merge these changes and add tests for this device soon, then we can finally merge this quirk.

@TheJulianJES TheJulianJES removed the waiting for reply Waiting for a reply (e.g. to test a custom quirk) label Feb 1, 2025
@bangert
Copy link
Contributor

bangert commented Feb 5, 2025

@TheJulianJES i have re-tested the latest version on a MULTI-ZIG-SW v1 firmware: it still works.

@mortenmoulder @OptionHenrik could you test with QUAD-ZIG-SW and/or v2 firmware?

@TheJulianJES TheJulianJES added the ready PR should be ready to merge label Feb 5, 2025
Copy link
Collaborator

@TheJulianJES TheJulianJES left a comment

Choose a reason for hiding this comment

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

Thanks!

@TheJulianJES TheJulianJES merged commit 78687d2 into zigpy:dev Feb 6, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs review This PR should be reviewed soon, as it generally looks good. needs reviewer answer An answer from a reviewer is needed (e.g. why a PR isn't acceptable in the current state). new quirk Adds support for a new device ready PR should be ready to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Device Support Request] smarthjemmet.dk QUAD-ZIG-SW
5 participants