- 
                Notifications
    
You must be signed in to change notification settings  - Fork 902
 
Add Third Reality button settings #4352
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
base: dev
Are you sure you want to change the base?
Changes from 29 commits
c07c896
              138ae97
              ef0efaa
              0148d86
              20f777e
              0e87d69
              126ecd8
              36eee8f
              2cc011f
              b4cdbf6
              89e80cb
              115e9e4
              b484bc7
              c798a96
              88c9847
              4f74b2e
              e25a838
              e275a43
              c5b8f9a
              86ac6c4
              44748cb
              4a8b815
              58b6ed2
              b95f82c
              9f0034f
              cfd1145
              63a1b15
              60447b7
              26a4356
              183d16b
              60f7652
              68fcff7
              61dc2e5
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| """Test the module for the "third button" function to verify the ZHA event capture logic.""" | ||
| 
     | 
||
| import pytest | ||
| 
     | 
||
| import zhaquirks | ||
| from zhaquirks.thirdreality.button_v2 import MultistateInputCluster | ||
| 
     | 
||
| 
     | 
||
| class MockListener: | ||
| """Simulate listener class for capturing ZHA events.""" | ||
| 
     | 
||
| def __init__(self): | ||
| """Initialize listener with empty event list.""" | ||
| self.zha_send_events = [] | ||
| 
     | 
||
| def zha_send_event(self, action, event_args): | ||
| """Record ZHA events. | ||
| 
     | 
||
| Args: | ||
| action (str): The type of action for the event. | ||
| event_args (dict): Relevant parameters of the event. | ||
| 
     | 
||
| """ | ||
| self.zha_send_events.append((action, event_args)) | ||
| 
     | 
||
| 
     | 
||
| zhaquirks.setup() | ||
| 
     | 
||
| 
     | 
||
| @pytest.mark.parametrize( | ||
| "manufacturer, model", | ||
| [("Third Reality, Inc", "3RSB22BZ")], | ||
| ) | ||
| async def test_third_reality_button_v2(zigpy_device_from_v2_quirk, manufacturer, model): | ||
| """Test Third Reality button event conversion and triggering functionality.""" | ||
| # Create mock device based on the v2 quirk | ||
| device = zigpy_device_from_v2_quirk(manufacturer, model) | ||
| 
     | 
||
| # Find the MultistateInputCluster | ||
| multistate_cluster = next( | ||
| ( | ||
| cluster | ||
| for cluster in device.endpoints[1].in_clusters.values() | ||
| if isinstance(cluster, MultistateInputCluster) | ||
| ), | ||
| None, | ||
| ) | ||
| assert multistate_cluster is not None, "MultistateInputCluster not found" | ||
                
      
                  TheJulianJES marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| # Create mock listener and register it with the cluster | ||
| mock_listener = MockListener() | ||
| multistate_cluster.add_listener(mock_listener) | ||
| 
     | 
||
| # Test 1: Verify single click event conversion | ||
| mock_listener.zha_send_events.clear() | ||
| multistate_cluster.update_attribute(0x0055, 1) # 1 corresponds to single click | ||
| assert len(mock_listener.zha_send_events) == 1 | ||
| assert mock_listener.zha_send_events[0][0] == "single" | ||
| 
     | 
||
| # Test 2: Verify double click event conversion | ||
| mock_listener.zha_send_events.clear() | ||
| multistate_cluster.update_attribute(0x0055, 2) # 2 corresponds to double click | ||
| assert len(mock_listener.zha_send_events) == 1 | ||
| assert mock_listener.zha_send_events[0][0] == "double" | ||
| 
     | 
||
| # Test 3: Verify hold event conversion | ||
| mock_listener.zha_send_events.clear() | ||
| multistate_cluster.update_attribute(0x0055, 0) # 0 corresponds to hold | ||
| assert len(mock_listener.zha_send_events) == 1 | ||
| assert mock_listener.zha_send_events[0][0] == "hold" | ||
| 
     | 
||
| # Test 4: Verify release event conversion | ||
| mock_listener.zha_send_events.clear() | ||
| multistate_cluster.update_attribute(0x0055, 255) # 255 corresponds to release | ||
| assert len(mock_listener.zha_send_events) == 1 | ||
| assert mock_listener.zha_send_events[0][0] == "release" | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| """Third Reality button devices.""" | ||
| 
     | 
||
| from typing import Final | ||
| 
     | 
||
| from zigpy.quirks import CustomCluster | ||
| from zigpy.quirks.v2 import QuirkBuilder | ||
| import zigpy.types as t | ||
| from zigpy.zcl.clusters.general import MultistateInput | ||
| from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef | ||
| 
     | 
||
| from zhaquirks.const import ( | ||
| COMMAND, | ||
| COMMAND_DOUBLE, | ||
| COMMAND_HOLD, | ||
| COMMAND_RELEASE, | ||
| COMMAND_SINGLE, | ||
| DOUBLE_PRESS, | ||
| LONG_PRESS, | ||
| LONG_RELEASE, | ||
| SHORT_PRESS, | ||
| VALUE, | ||
| ZHA_SEND_EVENT, | ||
| ) | ||
| 
     | 
||
| MOVEMENT_TYPE = { | ||
| 0: COMMAND_HOLD, | ||
| 1: COMMAND_SINGLE, | ||
| 2: COMMAND_DOUBLE, | ||
| 255: COMMAND_RELEASE, | ||
| } | ||
| 
     | 
||
| 
     | 
||
| class MultistateInputCluster(CustomCluster, MultistateInput): | ||
| """Multistate input cluster.""" | ||
| 
     | 
||
| def __init__(self, *args, **kwargs): | ||
| """Init.""" | ||
| self._current_state = {} | ||
| super().__init__(*args, **kwargs) | ||
| 
     | 
||
                
      
                  TheJulianJES marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| def _update_attribute(self, attrid, value): | ||
| super()._update_attribute(attrid, value) | ||
| if attrid == 0x0055: | ||
| self._current_state[0x0055] = action = MOVEMENT_TYPE.get(value) | ||
                
      
                  TheJulianJES marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| event_args = {VALUE: value} | ||
| if action is not None: | ||
| self.listener_event(ZHA_SEND_EVENT, action, event_args) | ||
| 
     | 
||
| # show something in the sensor in HA | ||
| super()._update_attribute(0, action) | ||
                
      
                  TheJulianJES marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| 
     | 
||
| 
     | 
||
| class ThirdRealityButtonCluster(CustomCluster): | ||
| """Third Reality's button private cluster.""" | ||
| 
     | 
||
| cluster_id = 0xFF01 | ||
| 
     | 
||
| class AttributeDefs(BaseAttributeDefs): | ||
| """Define the attributes of a private cluster.""" | ||
| 
     | 
||
| # cancel double click | ||
| cancel_bouble_click: Final = ZCLAttributeDef( | ||
                
      
                  TheJulianJES marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| id=0x0000, | ||
| type=t.uint8_t, | ||
| is_manufacturer_specific=True, | ||
| ) | ||
| 
     | 
||
| 
     | 
||
| ( | ||
| QuirkBuilder("Third Reality, Inc", "3RSB22BZ") | ||
| .replaces(ThirdRealityButtonCluster) | ||
| .replaces(MultistateInputCluster) | ||
| .number( | ||
| attribute_name=ThirdRealityButtonCluster.AttributeDefs.cancel_bouble_click.name, | ||
                
      
                  TheJulianJES marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| cluster_id=ThirdRealityButtonCluster.cluster_id, | ||
| endpoint_id=1, | ||
| min_value=0, | ||
| max_value=65535, | ||
| step=1, | ||
| translation_key="cancel_bouble_click", | ||
                
      
                  TheJulianJES marked this conversation as resolved.
               
              
                Outdated
          
            Show resolved
            Hide resolved
         | 
||
| fallback_name="Cancel double click", | ||
| ) | ||
                
       | 
||
| .device_automation_triggers( | ||
| { | ||
| (DOUBLE_PRESS, DOUBLE_PRESS): {COMMAND: COMMAND_DOUBLE}, | ||
| (SHORT_PRESS, SHORT_PRESS): {COMMAND: COMMAND_SINGLE}, | ||
| (LONG_PRESS, LONG_PRESS): {COMMAND: COMMAND_HOLD}, | ||
| (LONG_RELEASE, LONG_RELEASE): {COMMAND: COMMAND_RELEASE}, | ||
| } | ||
| ) | ||
| .add_to_registry() | ||
| ) | ||
Uh oh!
There was an error while loading. Please reload this page.