-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Migrate Aqara pet feeder ACN001 to quirks v2 #5296
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 4 commits
622b5cc
770bd1b
2368891
f0805e2
86c6ee4
8764556
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 |
|---|---|---|
| @@ -1,35 +1,24 @@ | ||
| """Quirk for Aqara aqara.feeder.acn001.""" | ||
| """Quirk V2 for Aqara aqara.feeder.acn001.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import logging | ||
| from typing import Any, Final | ||
|
|
||
| from zigpy import types | ||
| from zigpy.profiles import zgp, zha | ||
| from zigpy.zcl import AttributeReportedEvent, AttributeUpdatedEvent, foundation | ||
| from zigpy.zcl.clusters.general import ( | ||
| Basic, | ||
| GreenPowerProxy, | ||
| Groups, | ||
| Identify, | ||
| OnOff, | ||
| Ota, | ||
| Scenes, | ||
| Time, | ||
| ) | ||
| from zigpy.zcl.clusters.general import OnOff, Time | ||
| from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef | ||
|
|
||
| from zhaquirks.const import ( | ||
| DEVICE_TYPE, | ||
| ENDPOINTS, | ||
| INPUT_CLUSTERS, | ||
| MANUFACTURER, | ||
| MODEL, | ||
| OUTPUT_CLUSTERS, | ||
| PROFILE_ID, | ||
| from zhaquirks.builder import ( | ||
| BinarySensorDeviceClass, | ||
| EntityPlatform, | ||
| EntityType, | ||
| QuirkBuilder, | ||
| SensorStateClass, | ||
| UnitOfMass, | ||
| ) | ||
| from zhaquirks.xiaomi import XiaomiAqaraE1Cluster, XiaomiCustomDevice | ||
| from zhaquirks.xiaomi import XiaomiAqaraE1Cluster | ||
|
|
||
| # 32 bit signed integer values that are encoded in FEEDER_ATTR = 0xFFF1 | ||
| FEEDING = 0x04150055 | ||
|
|
@@ -86,8 +75,9 @@ | |
| class FeedingSource(types.enum8): | ||
| """Feeding source.""" | ||
|
|
||
| Schedule = 0x00 | ||
| Feeder = 0x01 | ||
| Remote = 0x02 | ||
| HomeAssistant = 0x02 | ||
|
|
||
|
|
||
| class FeedingMode(types.enum8): | ||
|
|
@@ -274,65 +264,109 @@ async def write_attributes( | |
| return await super().write_attributes(attrs, update_cache=False, **kwargs) | ||
|
|
||
|
|
||
| class AqaraFeederAcn001(XiaomiCustomDevice): | ||
| """Aqara aqara.feeder.acn001 custom device implementation.""" | ||
|
|
||
| signature = { | ||
| MODEL: "aqara.feeder.acn001", | ||
| ENDPOINTS: { | ||
| 1: { | ||
| PROFILE_ID: zha.PROFILE_ID, | ||
| DEVICE_TYPE: zha.DeviceType.ON_OFF_OUTPUT, | ||
| INPUT_CLUSTERS: [ | ||
| Basic.cluster_id, | ||
| Identify.cluster_id, | ||
| Groups.cluster_id, | ||
| Scenes.cluster_id, | ||
| OnOff.cluster_id, | ||
| OppleCluster.cluster_id, | ||
| ], | ||
| OUTPUT_CLUSTERS: [ | ||
| Identify.cluster_id, | ||
| Ota.cluster_id, | ||
| ], | ||
| }, | ||
| 242: { | ||
| PROFILE_ID: zgp.PROFILE_ID, | ||
| DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, | ||
| INPUT_CLUSTERS: [], | ||
| OUTPUT_CLUSTERS: [ | ||
| GreenPowerProxy.cluster_id, | ||
| ], | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| replacement = { | ||
| MANUFACTURER: "Aqara", | ||
| ENDPOINTS: { | ||
| 1: { | ||
| PROFILE_ID: zha.PROFILE_ID, | ||
| DEVICE_TYPE: zha.DeviceType.ON_OFF_OUTPUT, | ||
| INPUT_CLUSTERS: [ | ||
| Basic.cluster_id, | ||
| Identify.cluster_id, | ||
| Groups.cluster_id, | ||
| Scenes.cluster_id, | ||
| OppleCluster, | ||
| Time.cluster_id, | ||
| ], | ||
| OUTPUT_CLUSTERS: [ | ||
| Identify.cluster_id, | ||
| Ota.cluster_id, | ||
| ], | ||
| }, | ||
| 242: { | ||
| PROFILE_ID: zgp.PROFILE_ID, | ||
| DEVICE_TYPE: zgp.DeviceType.PROXY_BASIC, | ||
| INPUT_CLUSTERS: [], | ||
| OUTPUT_CLUSTERS: [ | ||
| GreenPowerProxy.cluster_id, | ||
| ], | ||
| }, | ||
| }, | ||
| } | ||
| ( | ||
| QuirkBuilder(None, "aqara.feeder.acn001") | ||
|
Copilot marked this conversation as resolved.
|
||
| # device does not provide manufacturer during interview | ||
| # The v2 entities only take over cleanly once the | ||
| # native classes are removed (zigpy/zha#883) if the model string matches. | ||
| .friendly_name(manufacturer="Aqara", model="aqara.feeder.acn001") | ||
| .removes(OnOff.cluster_id) | ||
| .replaces(Time) | ||
| .replaces(OppleCluster) | ||
| .enum( | ||
| attribute_name=OppleCluster.AttributeDefs.last_feeding_source.name, | ||
| enum_class=FeedingSource, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| entity_platform=EntityPlatform.SENSOR, | ||
| entity_type=EntityType.STANDARD, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-last_feeding_source", | ||
| translation_key="last_feeding_source", | ||
| fallback_name="Last feeding source", | ||
| ) | ||
| .sensor( | ||
| attribute_name=OppleCluster.AttributeDefs.last_feeding_size.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-last_feeding_size", | ||
| translation_key="last_feeding_size", | ||
| fallback_name="Last feeding size", | ||
| ) | ||
| .sensor( | ||
| attribute_name=OppleCluster.AttributeDefs.portions_dispensed.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| state_class=SensorStateClass.TOTAL_INCREASING, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thinking about this, I could add |
||
| unique_id_suffix=f"{OppleCluster.cluster_id}-portions_dispensed", | ||
| translation_key="portions_dispensed_today", | ||
| fallback_name="Portions dispensed today", | ||
| ) | ||
| .sensor( | ||
| attribute_name=OppleCluster.AttributeDefs.weight_dispensed.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| unit=UnitOfMass.GRAMS, | ||
| state_class=SensorStateClass.TOTAL_INCREASING, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-weight_dispensed", | ||
| translation_key="weight_dispensed_today", | ||
| fallback_name="Weight dispensed today", | ||
| ) | ||
| .switch( | ||
| attribute_name=OppleCluster.AttributeDefs.disable_led_indicator.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| force_inverted=True, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-disable_led_indicator", | ||
| translation_key="led_indicator", | ||
| fallback_name="LED indicator", | ||
| ) | ||
| .switch( | ||
| attribute_name=OppleCluster.AttributeDefs.child_lock.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-child_lock", | ||
| translation_key="child_lock", | ||
| fallback_name="Child lock", | ||
| ) | ||
| .enum( | ||
| attribute_name=OppleCluster.AttributeDefs.feeding_mode.name, | ||
| enum_class=FeedingMode, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-feeding_mode", | ||
| translation_key="feeding_mode", | ||
| fallback_name="Feeding mode", | ||
| ) | ||
| .number( | ||
| attribute_name=OppleCluster.AttributeDefs.serving_size.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| min_value=1, | ||
| max_value=10, | ||
| mode="box", | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-serving_size", | ||
| translation_key="serving_size", | ||
| fallback_name="Serving size", | ||
| ) | ||
| .number( | ||
| attribute_name=OppleCluster.AttributeDefs.portion_weight.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| min_value=1, | ||
| max_value=100, | ||
| unit=UnitOfMass.GRAMS, | ||
| mode="box", | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-portion_weight", | ||
| translation_key="portion_weight", | ||
| fallback_name="Portion weight", | ||
| ) | ||
| .binary_sensor( | ||
| attribute_name=OppleCluster.AttributeDefs.error_detected.name, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| entity_type=EntityType.STANDARD, | ||
| device_class=BinarySensorDeviceClass.PROBLEM, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-error_detected", | ||
| fallback_name="Error detected", | ||
| ) | ||
| .write_attr_button( | ||
| attribute_name=OppleCluster.AttributeDefs.feeding.name, | ||
| attribute_value=1, | ||
| cluster_id=OppleCluster.cluster_id, | ||
| entity_type=EntityType.STANDARD, | ||
| unique_id_suffix=f"{OppleCluster.cluster_id}-feeding", | ||
| translation_key="feed", | ||
| fallback_name="Feed", | ||
| ) | ||
| .add_to_registry() | ||
| ) | ||
Uh oh!
There was an error while loading. Please reload this page.