Skip to content

Instantly share code, notes, and snippets.

@cemizm
Last active December 13, 2025 21:51
Show Gist options
  • Select an option

  • Save cemizm/037f02827f5818baa77749876205943c to your computer and use it in GitHub Desktop.

Select an option

Save cemizm/037f02827f5818baa77749876205943c to your computer and use it in GitHub Desktop.
Aqara FP300 Presence Sensor
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Final
from zigpy import types as t
from zigpy.quirks.v2 import QuirkBuilder, ReportingConfig
from zigpy.quirks.v2.homeassistant import EntityType, UnitOfTime, UnitOfLength
from zigpy.quirks.v2.homeassistant.binary_sensor import BinarySensorDeviceClass
from zigpy.quirks.v2.homeassistant.number import NumberDeviceClass
from zigpy.quirks.v2.homeassistant.sensor import SensorDeviceClass, SensorStateClass
from zigpy.zcl.foundation import BaseAttributeDefs, DataTypeId, ZCLAttributeDef
from zhaquirks import LocalDataCluster
from zhaquirks.xiaomi import XiaomiAqaraE1Cluster, XiaomiPowerConfigurationPercent, BATTERY_PERCENTAGE_REMAINING_ATTRIBUTE, BATTERY_VOLTAGE_MV
#
# Enums matching Zigbee2MQTT converter semantics
#
class MotionSensitivity(t.enum8):
"""Presence / motion sensitivity."""
LOW = 1
MEDIUM = 2
HIGH = 3
class PresenceDetectionMode(t.enum8):
"""Which sensors are used for presence."""
BOTH = 0 # mmWave + PIR
MMWAVE_ONLY = 1
PIR_ONLY = 2
class TempHumiditySampling(t.enum8):
"""Sampling frequency for temperature & humidity."""
OFF = 0
LOW = 1
MEDIUM = 2
HIGH = 3
CUSTOM = 4
class ReportMode(t.enum8):
"""Reporting mode for temp/humidity/illuminance in custom mode."""
THRESHOLD = 1
INTERVAL = 2
THRESHOLD_AND_INTERVAL = 3
class LightSampling(t.enum8):
"""Sampling frequency for illuminance."""
OFF = 0
LOW = 1
MEDIUM = 2
HIGH = 3
CUSTOM = 4
#
# Manufacturer specific cluster (0xFCC0)
#
class AqaraFP300ManuCluster(XiaomiAqaraE1Cluster):
"""Aqara FP300 manufacturer specific cluster (0xFCC0)."""
class AttributeDefs(BaseAttributeDefs):
#
# Presence / motion
#
presence: Final = ZCLAttributeDef(
id=0x0142,
type=t.Bool,
zcl_type=DataTypeId.uint8,
access="rp",
is_manufacturer_specific=True,
)
pir_detection: Final = ZCLAttributeDef(
id=0x014D,
type=t.Bool,
zcl_type=DataTypeId.uint8,
access="rp",
is_manufacturer_specific=True,
)
motion_sensitivity: Final = ZCLAttributeDef(
id=0x010C,
type=MotionSensitivity,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
absence_delay_timer: Final = ZCLAttributeDef(
id=0x0197,
type=t.uint32_t,
zcl_type=DataTypeId.uint32,
access="rwp",
is_manufacturer_specific=True,
)
pir_detection_interval: Final = ZCLAttributeDef(
id=0x014F,
type=t.uint16_t,
zcl_type=DataTypeId.uint16,
access="rwp",
is_manufacturer_specific=True,
)
presence_detection_options: Final = ZCLAttributeDef(
id=0x0199,
type=PresenceDetectionMode,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
detection_range_raw: Final = ZCLAttributeDef(
id=0x019A,
type=t.LVBytes,
zcl_type=DataTypeId.octstr,
access="rpw",
is_manufacturer_specific=True,
)
#
# AI helpers
#
ai_interference_source_selfidentification: Final = ZCLAttributeDef(
id=0x015E,
type=t.uint8_t,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
ai_sensitivity_adaptive: Final = ZCLAttributeDef(
id=0x015D,
type=t.uint8_t,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
#
# Target distance / tracking
#
target_distance: Final = ZCLAttributeDef(
id=0x015F,
type=t.uint32_t,
zcl_type=DataTypeId.uint32,
access="rp",
is_manufacturer_specific=True,
)
track_target_distance: Final = ZCLAttributeDef(
id=0x0198,
type=t.uint8_t,
zcl_type=DataTypeId.uint8,
access="w",
is_manufacturer_specific=True,
)
#
# Temp/humidity sampling + reporting
#
temp_humidity_sampling: Final = ZCLAttributeDef(
id=0x0170,
type=TempHumiditySampling,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
temp_humidity_sampling_period: Final = ZCLAttributeDef(
id=0x0162,
type=t.uint32_t,
zcl_type=DataTypeId.uint32,
access="rwp",
is_manufacturer_specific=True,
)
temp_reporting_interval: Final = ZCLAttributeDef(
id=0x0163,
type=t.uint32_t,
zcl_type=DataTypeId.uint32,
access="rwp",
is_manufacturer_specific=True,
)
temp_reporting_threshold: Final = ZCLAttributeDef(
id=0x0164,
type=t.uint16_t,
zcl_type=DataTypeId.uint16,
access="rwp",
is_manufacturer_specific=True,
)
temp_reporting_mode: Final = ZCLAttributeDef(
id=0x0165,
type=ReportMode,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
humidity_reporting_interval: Final = ZCLAttributeDef(
id=0x016A,
type=t.uint32_t,
zcl_type=DataTypeId.uint32,
access="rwp",
is_manufacturer_specific=True,
)
humidity_reporting_threshold: Final = ZCLAttributeDef(
id=0x016B,
type=t.uint16_t,
zcl_type=DataTypeId.uint16,
access="rwp",
is_manufacturer_specific=True,
)
humidity_reporting_mode: Final = ZCLAttributeDef(
id=0x016C,
type=ReportMode,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
#
# Illuminance sampling + reporting
#
light_sampling: Final = ZCLAttributeDef(
id=0x0192,
type=LightSampling,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
light_sampling_period: Final = ZCLAttributeDef(
id=0x0193,
type=t.uint32_t,
zcl_type=DataTypeId.uint32,
access="rwp",
is_manufacturer_specific=True,
)
light_reporting_interval: Final = ZCLAttributeDef(
id=0x0194,
type=t.uint32_t,
zcl_type=DataTypeId.uint32,
access="rwp",
is_manufacturer_specific=True,
)
light_reporting_threshold: Final = ZCLAttributeDef(
id=0x0195,
type=t.uint16_t,
zcl_type=DataTypeId.uint16,
access="rwp",
is_manufacturer_specific=True,
)
light_reporting_mode: Final = ZCLAttributeDef(
id=0x0196,
type=ReportMode,
zcl_type=DataTypeId.uint8,
access="rwp",
is_manufacturer_specific=True,
)
#
# Spatial learning / restart (FP1E-style maintenance actions)
#
spatial_learning: Final = ZCLAttributeDef(
id=0x0157,
type=t.uint8_t,
zcl_type=DataTypeId.uint8,
access="w",
is_manufacturer_specific=True,
)
restart_device: Final = ZCLAttributeDef(
id=0x00E8,
type=t.Bool,
zcl_type=DataTypeId.bool_,
access="w",
is_manufacturer_specific=True,
)
def _parse_aqara_attributes(self, value: Any) -> None:
"""Parse non-standard and fp300 specific attributes."""
attributes = super()._parse_aqara_attributes(value)
if "0xff01-23" in attributes:
attributes[BATTERY_VOLTAGE_MV] = attributes.pop("0xff01-23")
if "0xff01-24" in attributes:
attributes[BATTERY_PERCENTAGE_REMAINING_ATTRIBUTE] = attributes.pop("0xff01-24")
return attributes
def _update_attribute(self, attrid: int, value: Any) -> None:
"""Only delegate 0x019A to the FP300DetectionRangeCluster."""
if attrid == self.AttributeDefs.detection_range_raw.id:
dr_cluster = self.endpoint.in_clusters.get(FP300DetectionRangeCluster.cluster_id)
if dr_cluster is not None:
dr_cluster._update_from_raw(value)
return super()._update_attribute(attrid, value)
class FP300DetectionRangeCluster(LocalDataCluster):
"""Local cluster for detection range handling."""
cluster_id = 0xFC30
class AttributeDefs(BaseAttributeDefs):
prefix: Final = ZCLAttributeDef(
id=0x0000,
type=t.uint16_t,
zcl_type=DataTypeId.uint16,
access="rpw",
)
range_0_1m: Final = ZCLAttributeDef(
id=0x0001,
type=t.Bool,
zcl_type=DataTypeId.bool_,
access="rwp",
)
range_1_2m: Final = ZCLAttributeDef(
id=0x0002,
type=t.Bool,
zcl_type=DataTypeId.bool_,
access="rwp",
)
range_2_3m: Final = ZCLAttributeDef(
id=0x0003,
type=t.Bool,
zcl_type=DataTypeId.bool_,
access="rwp",
)
range_3_4m: Final = ZCLAttributeDef(
id=0x0004,
type=t.Bool,
zcl_type=DataTypeId.bool_,
access="rwp",
)
range_4_5m: Final = ZCLAttributeDef(
id=0x0005,
type=t.Bool,
zcl_type=DataTypeId.bool_,
access="rwp",
)
range_5_6m: Final = ZCLAttributeDef(
id=0x0006,
type=t.Bool,
zcl_type=DataTypeId.bool_,
access="rwp",
)
def _update_from_raw(self, raw: t.LVBytes | bytes | bytearray | None) -> None:
"""updates from raw buffer of 0x019A attribute from manu cluster."""
if isinstance(raw, t.LVBytes):
data = bytes(raw)
elif isinstance(raw, (bytes, bytearray)):
data = bytes(raw)
else:
data = b""
if len(data) >= 5:
prefix = int.from_bytes(data[0:2], "little")
mask = int.from_bytes(data[2:5], "little") & ((1 << 24) - 1)
else:
prefix = 0x0300
mask = (1 << 24) - 1 # 0xFFFFFF
super()._update_attribute(self.AttributeDefs.prefix.id, prefix)
seg_defs = [
(self.AttributeDefs.range_0_1m.id, 0),
(self.AttributeDefs.range_1_2m.id, 4),
(self.AttributeDefs.range_2_3m.id, 8),
(self.AttributeDefs.range_3_4m.id, 12),
(self.AttributeDefs.range_4_5m.id, 16),
(self.AttributeDefs.range_5_6m.id, 20),
]
for attr_id, start_bit in seg_defs:
seg_mask = ((1 << 4) - 1) << start_bit
enabled = (mask & seg_mask) != 0
super()._update_attribute(attr_id, bool(enabled))
def _build_raw(self) -> t.LVBytes:
"""builds raw buffer for 0x019A attribute for manu cluster from local range switches."""
prefix = self._attr_cache.get(self.AttributeDefs.prefix.id, 0x0300)
try:
prefix_int = int(prefix) & 0xFFFF
except (TypeError, ValueError):
prefix_int = 0x0300
seg_defs = [
(self.AttributeDefs.range_0_1m.id, 0),
(self.AttributeDefs.range_1_2m.id, 4),
(self.AttributeDefs.range_2_3m.id, 8),
(self.AttributeDefs.range_3_4m.id, 12),
(self.AttributeDefs.range_4_5m.id, 16),
(self.AttributeDefs.range_5_6m.id, 20),
]
mask = 0
for attr_id, start_bit in seg_defs:
enabled = bool(self._attr_cache.get(attr_id, True))
if enabled:
mask |= ((1 << 4) - 1) << start_bit
buf = prefix_int.to_bytes(2, "little") + mask.to_bytes(3, "little")
return t.LVBytes(buf)
async def write_attributes(
self,
attributes: dict[int, Any],
manufacturer: int | None = None,
**kwargs: Any,
) -> Any:
"""
HA writes to local range switches → we build 0x019A
and pass it to the manufacturer cluster.
"""
res = await super().write_attributes(attributes, manufacturer=manufacturer, **kwargs)
raw = self._build_raw()
manu = self.endpoint.in_clusters.get(AqaraFP300ManuCluster.cluster_id)
if manu is not None:
await manu.write_attributes(
{AqaraFP300ManuCluster.AttributeDefs.detection_range_raw.id: raw},
manufacturer=manufacturer,
)
return res
#
# QuirkBuilder definition
#
FP300_QUIRK = (
QuirkBuilder("Aqara", "lumi.sensor_occupy.agl8")
.friendly_name(manufacturer="Aqara", model="Presence Sensor FP300")
.replaces(AqaraFP300ManuCluster)
.adds(XiaomiPowerConfigurationPercent)
.adds(FP300DetectionRangeCluster)
# Main presence entity (mmWave)
.binary_sensor(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.presence.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=BinarySensorDeviceClass.OCCUPANCY,
entity_type=EntityType.STANDARD,
translation_key="presence",
fallback_name="Presence",
reporting_config=ReportingConfig(
min_interval=1,
max_interval=300,
reportable_change=1,
),
)
# Diagnostic PIR detection
.binary_sensor(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.pir_detection.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=BinarySensorDeviceClass.MOTION,
entity_type=EntityType.DIAGNOSTIC,
translation_key="pir_detection",
fallback_name="PIR detection",
reporting_config=ReportingConfig(
min_interval=1,
max_interval=300,
reportable_change=1,
),
initially_disabled=True,
)
# Target distance (from fp1eTargetDistance)
.sensor(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.target_distance.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=SensorDeviceClass.DISTANCE,
state_class=SensorStateClass.MEASUREMENT,
unit="m",
multiplier=0.01, # raw = meters * 100
entity_type=EntityType.DIAGNOSTIC,
translation_key="target_distance",
fallback_name="Target distance",
)
# Button: start tracking current target distance
.write_attr_button(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.track_target_distance.name,
attribute_value=1,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="track_target_distance",
fallback_name="Start target distance tracking",
)
# Motion / presence config
.enum(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.motion_sensitivity.name,
enum_class=MotionSensitivity,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="motion_sensitivity",
fallback_name="Motion sensitivity",
)
.enum(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.presence_detection_options.name,
enum_class=PresenceDetectionMode,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="presence_detection_options",
fallback_name="Presence detection options",
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.absence_delay_timer.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.DURATION,
entity_type=EntityType.CONFIG,
translation_key="absence_delay_timer",
fallback_name="Absence delay timer",
min_value=10,
max_value=300,
step=5,
unit=UnitOfTime.SECONDS,
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.pir_detection_interval.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.DURATION,
entity_type=EntityType.CONFIG,
translation_key="pir_detection_interval",
fallback_name="PIR detection interval",
min_value=2,
max_value=300,
step=1,
unit=UnitOfTime.SECONDS,
)
# AI helper switches
.switch(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.ai_interference_source_selfidentification.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="ai_interference_source_selfidentification",
fallback_name="AI interference source self-identification",
)
.switch(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.ai_sensitivity_adaptive.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="ai_sensitivity_adaptive",
fallback_name="AI adaptive sensitivity",
)
# Temp/humidity sampling & reporting
.enum(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.temp_humidity_sampling.name,
enum_class=TempHumiditySampling,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="temp_humidity_sampling",
fallback_name="Temp & humidity sampling",
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.temp_humidity_sampling_period.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.DURATION,
entity_type=EntityType.CONFIG,
translation_key="temp_humidity_sampling_period",
fallback_name="Temp & humidity sampling period",
min_value=0.5,
max_value=3600.0,
step=0.5,
multiplier=0.001, # ms -> s
unit=UnitOfTime.SECONDS,
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.temp_reporting_interval.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.DURATION,
entity_type=EntityType.CONFIG,
translation_key="temp_reporting_interval",
fallback_name="Temperature reporting interval",
min_value=600,
max_value=3600,
step=600,
multiplier=0.001,
unit=UnitOfTime.SECONDS,
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.temp_reporting_threshold.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.TEMPERATURE,
entity_type=EntityType.CONFIG,
translation_key="temp_reporting_threshold",
fallback_name="Temperature reporting threshold",
min_value=0.2,
max_value=3.0,
step=0.1,
multiplier=0.01,
unit="°C",
)
.enum(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.temp_reporting_mode.name,
enum_class=ReportMode,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="temp_reporting_mode",
fallback_name="Temperature reporting mode",
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.humidity_reporting_interval.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.DURATION,
entity_type=EntityType.CONFIG,
translation_key="humidity_reporting_interval",
fallback_name="Humidity reporting interval",
min_value=600,
max_value=3600,
step=600,
multiplier=0.001,
unit=UnitOfTime.SECONDS,
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.humidity_reporting_threshold.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.HUMIDITY,
entity_type=EntityType.CONFIG,
translation_key="humidity_reporting_threshold",
fallback_name="Humidity reporting threshold",
min_value=2.0,
max_value=20.0,
step=0.5,
multiplier=0.01,
unit="%",
)
.enum(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.humidity_reporting_mode.name,
enum_class=ReportMode,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="humidity_reporting_mode",
fallback_name="Humidity reporting mode",
)
# Illuminance sampling & reporting
.enum(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.light_sampling.name,
enum_class=LightSampling,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="light_sampling",
fallback_name="Light sampling",
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.light_sampling_period.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.DURATION,
entity_type=EntityType.CONFIG,
translation_key="light_sampling_period",
fallback_name="Light sampling period",
min_value=0.5,
max_value=3600.0,
step=0.5,
multiplier=0.001,
unit=UnitOfTime.SECONDS,
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.light_reporting_interval.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
device_class=NumberDeviceClass.DURATION,
entity_type=EntityType.CONFIG,
translation_key="light_reporting_interval",
fallback_name="Light reporting interval",
min_value=20,
max_value=3600,
step=20,
multiplier=0.001,
unit=UnitOfTime.SECONDS,
)
.number(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.light_reporting_threshold.name,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
# “percentage change” – omit device_class
entity_type=EntityType.CONFIG,
translation_key="light_reporting_threshold",
fallback_name="Light reporting threshold",
min_value=3.0,
max_value=20.0,
step=0.5,
multiplier=0.01,
unit="%",
)
.enum(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.light_reporting_mode.name,
enum_class=ReportMode,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="light_reporting_mode",
fallback_name="Light reporting mode",
)
# Maintenance buttons
.write_attr_button(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.spatial_learning.name,
attribute_value=1,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="spatial_learning",
fallback_name="Start spatial learning",
)
.write_attr_button(
attribute_name=AqaraFP300ManuCluster.AttributeDefs.restart_device.name,
attribute_value=1,
cluster_id=AqaraFP300ManuCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="restart_device",
fallback_name="Restart device",
)
# Detection range switches
.switch(
attribute_name=FP300DetectionRangeCluster.AttributeDefs.range_0_1m.name,
cluster_id=FP300DetectionRangeCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="detection_range_0_1m",
fallback_name="Detection range 0–1 m",
)
.switch(
attribute_name=FP300DetectionRangeCluster.AttributeDefs.range_1_2m.name,
cluster_id=FP300DetectionRangeCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="detection_range_1_2m",
fallback_name="Detection range 1–2 m",
)
.switch(
attribute_name=FP300DetectionRangeCluster.AttributeDefs.range_2_3m.name,
cluster_id=FP300DetectionRangeCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="detection_range_2_3m",
fallback_name="Detection range 2–3 m",
)
.switch(
attribute_name=FP300DetectionRangeCluster.AttributeDefs.range_3_4m.name,
cluster_id=FP300DetectionRangeCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="detection_range_3_4m",
fallback_name="Detection range 3–4 m",
)
.switch(
attribute_name=FP300DetectionRangeCluster.AttributeDefs.range_4_5m.name,
cluster_id=FP300DetectionRangeCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="detection_range_4_5m",
fallback_name="Detection range 4–5 m",
)
.switch(
attribute_name=FP300DetectionRangeCluster.AttributeDefs.range_5_6m.name,
cluster_id=FP300DetectionRangeCluster.cluster_id,
endpoint_id=1,
entity_type=EntityType.CONFIG,
translation_key="detection_range_5_6m",
fallback_name="Detection range 5–6 m",
)
.add_to_registry()
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment