Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 16 additions & 70 deletions tests/test_schneiderelectric.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,77 +8,19 @@
from zigpy.zcl.clusters.smartenergy import Metering

from tests.common import ClusterListener
from zhaquirks.schneiderelectric import SE_MANUF_NAME
import zhaquirks.schneiderelectric.outlet
import zhaquirks.schneiderelectric.shutters

zhaquirks.setup()


def test_1gang_shutter_1_signature(assert_signature_matches_quirk):
"""Test signature."""
signature = {
"node_descriptor": (
"NodeDescriptor(logical_type=<LogicalType.Router: 1>, "
"complex_descriptor_available=0, user_descriptor_available=0, reserved=0, "
"aps_flags=0, frequency_band=<FrequencyBand.Freq2400MHz: 8>, "
"mac_capability_flags=<MACCapabilityFlags.FullFunctionDevice|MainsPowered"
"|RxOnWhenIdle|AllocateAddress: 142>, manufacturer_code=4190, "
"maximum_buffer_size=82, maximum_incoming_transfer_size=82, "
"server_mask=10752, maximum_outgoing_transfer_size=82, "
"descriptor_capability_field=<DescriptorCapability.NONE: 0>, "
"*allocate_address=True, *is_alternate_pan_coordinator=False, "
"*is_coordinator=False, *is_end_device=False, "
"*is_full_function_device=True, *is_mains_powered=True, "
"*is_receiver_on_when_idle=True, *is_router=True, "
"*is_security_capable=False)"
),
"endpoints": {
"5": {
"profile_id": 0x0104,
"device_type": "0x0202",
"in_clusters": [
"0x0000",
"0x0003",
"0x0004",
"0x0005",
"0x0102",
"0x0b05",
],
"out_clusters": ["0x0019"],
},
"21": {
"profile_id": 0x0104,
"device_type": "0x0104",
"in_clusters": [
"0x0000",
"0x0003",
"0x0b05",
"0xff17",
],
"out_clusters": [
"0x0003",
"0x0005",
"0x0006",
"0x0008",
"0x0019",
"0x0102",
],
},
},
"manufacturer": "Schneider Electric",
"model": "1GANG/SHUTTER/1",
"class": "zigpy.device.Device",
}
assert_signature_matches_quirk(
zhaquirks.schneiderelectric.shutters.OneGangShutter1, signature
)


async def test_1gang_shutter_1_go_to_lift_percentage_cmd(zigpy_device_from_quirk):
async def test_1gang_shutter_1_go_to_lift_percentage_cmd(zigpy_device_from_v2_quirk):
"""Asserts that the go_to_lift_percentage command inverts the percentage value."""

device = zigpy_device_from_quirk(
zhaquirks.schneiderelectric.shutters.OneGangShutter1
device = zigpy_device_from_v2_quirk(
manufacturer=SE_MANUF_NAME,
model="1GANG/SHUTTER/1",
endpoint_ids=[5, 21],
)
window_covering_cluster = device.endpoints[5].window_covering

Expand All @@ -95,11 +37,13 @@ async def test_1gang_shutter_1_go_to_lift_percentage_cmd(zigpy_device_from_quirk
assert request_mock.call_args[0][3] == 42 # 100 - 58


async def test_1gang_shutter_1_unpatched_cmd(zigpy_device_from_quirk):
async def test_1gang_shutter_1_unpatched_cmd(zigpy_device_from_v2_quirk):
"""Asserts that unpatched ZCL commands keep working."""

device = zigpy_device_from_quirk(
zhaquirks.schneiderelectric.shutters.OneGangShutter1
device = zigpy_device_from_v2_quirk(
manufacturer=SE_MANUF_NAME,
model="1GANG/SHUTTER/1",
endpoint_ids=[5, 21],
)
window_covering_cluster = device.endpoints[5].window_covering

Expand All @@ -115,14 +59,16 @@ async def test_1gang_shutter_1_unpatched_cmd(zigpy_device_from_quirk):
)


async def test_1gang_shutter_1_lift_percentage_updates(zigpy_device_from_quirk):
async def test_1gang_shutter_1_lift_percentage_updates(zigpy_device_from_v2_quirk):
"""Asserts that updates to the ``current_position_lift_percentage`` attribute.

(e.g., by the device) invert the reported percentage value.
"""

device = zigpy_device_from_quirk(
zhaquirks.schneiderelectric.shutters.OneGangShutter1
device = zigpy_device_from_v2_quirk(
manufacturer=SE_MANUF_NAME,
model="1GANG/SHUTTER/1",
endpoint_ids=[5, 21],
)
window_covering_cluster = device.endpoints[5].window_covering
cluster_listener = ClusterListener(window_covering_cluster)
Expand Down
88 changes: 69 additions & 19 deletions zhaquirks/schneiderelectric/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,20 @@ class SEDimmingCurve(t.enum8):
Exponential = 2 # Not supported in current FW, but defined in the spec


class SESunProtectionStatus(t.bitmap8):
"""Window covering protetion status."""

NotActive = 0
Active = 1


class SESunProtectionSensor(t.bitmap8):
"""Window covering protetion status."""

NotConnected = 0
Connected = 1


class SEBallast(CustomCluster, Ballast):
"""Schneider Electric Ballast cluster."""

Expand All @@ -180,49 +194,85 @@ class SEWindowCovering(CustomCluster, WindowCovering):
class AttributeDefs(WindowCovering.AttributeDefs):
"""Attribute definitions."""

unknown_attribute_65533: Final = ZCLAttributeDef(
id=0xFFFD,
type=t.uint16_t,
is_manufacturer_specific=True,
)
lift_duration: Final = ZCLAttributeDef(
# Obsolete, use se_lift_drive_up_time and se_lift_drive_down_time instead.
se_lift_duration: Final = ZCLAttributeDef(
id=0xE000,
type=t.uint16_t,
access="rw",
is_manufacturer_specific=True,
)
unknown_attribute_57360: Final = ZCLAttributeDef(
se_sun_protection_status: Final = ZCLAttributeDef(
id=0xE010,
type=t.bitmap8,
type=SESunProtectionStatus,
access="r",
is_manufacturer_specific=True,
)
unknown_attribute_57362: Final = ZCLAttributeDef(
# SunProtectionIlluminanceThreshold = 10,000 x log10 Illuminance.
# Where 1 lx <= Illuminance <=3.576 Mlx, corresponding to a SunProtectionIlluminanceThreshold in the range 0 to 0xfffe.
# A value of 0xffff indicates that this attribute is not valid.
se_sun_protection_illuminance_thershold: Final = ZCLAttributeDef(
id=0xE012,
type=t.uint16_t,
access="rw",
is_manufacturer_specific=True,
)
unknown_attribute_57363: Final = ZCLAttributeDef(
se_sun_protection_sensor: Final = ZCLAttributeDef(
id=0xE013,
type=t.bitmap8,
type=SESunProtectionSensor,
access="rw",
is_manufacturer_specific=True,
)
unknown_attribute_57364: Final = ZCLAttributeDef(
# Driving time from fully close to fully open state in 1/10 seconds
se_lift_drive_up_time: Final = ZCLAttributeDef(
id=0xE014,
type=t.uint16_t,
access="rw",
is_manufacturer_specific=True,
)
unknown_attribute_57365: Final = ZCLAttributeDef(
# Driving time from fully open to fully close state in 1/10 seconds
se_lift_drive_down_time: Final = ZCLAttributeDef(
id=0xE015,
type=t.uint16_t,
access="rw",
is_manufacturer_specific=True,
)
unknown_attribute_57366: Final = ZCLAttributeDef(
# Time from fully open to fully close tilt position in 1/100 seconds.
# This time is also taken as base for calculation of step size in Schneider manufacture specific command StopOrStepLiftPercentage.
# If set to 0, WindosCoveringType attribute is automatically set to 0 (lift only).
se_tilt_open_close_and_step_time: Final = ZCLAttributeDef(
id=0xE016,
type=t.uint16_t,
access="rw",
is_manufacturer_specific=True,
)
unknown_attribute_57367: Final = ZCLAttributeDef(
# Tilt position in percent adopted by tilt after receiving go to lift percentage command.
# Values 0-100 are absolute position of tilt with following meaning:
# 100: Position of tilt when shutter is moving up (usually up).
# 0: Position of tilt when shutter is moving down (usually down).
# 255: No action after command.
# 101-254: Tilt position before movement is restored.
se_tilt_position_percentage_after_move_to_level: Final = ZCLAttributeDef(
id=0xE017,
type=t.uint8_t,
access="rw",
is_manufacturer_specific=True,
)
se_cluster_revision: Final = ZCLAttributeDef(
id=0xFFFD,
type=t.uint16_t,
access="r",
is_manufacturer_specific=True,
)

class ServerCommandDefs(WindowCovering.ServerCommandDefs):
"""Server command definitions."""

se_stop_or_step_lift_percentage: Final = foundation.ZCLCommandDef(
id=0x80,
schema={
"direction": t.uint8_t,
"step_value": t.uint8_t,
},
is_manufacturer_specific=True,
)

Expand Down Expand Up @@ -305,11 +355,11 @@ class SESwitchAction(t.enum8):
NotUsed = 0x7F


class SESpecific(CustomCluster):
"""Schneider Electric manufacturer specific cluster."""
class SESwitchConfiguration(CustomCluster):
"""Schneider Electric manufacturer specific switch configuration cluster."""

name = "Schneider Electric Manufacturer Specific"
ep_attribute = "schneider_electric_manufacturer"
name = "Schneider Electric Manufacturer Specific Switch Configuration"
ep_attribute = "switch_configuration"
cluster_id = 0xFF17

class AttributeDefs(BaseAttributeDefs):
Expand Down
6 changes: 3 additions & 3 deletions zhaquirks/schneiderelectric/dimmers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
SEBallast,
SEBasic,
SEOnOff,
SESpecific,
SESwitchConfiguration,
)

(
Expand All @@ -19,7 +19,7 @@
.replaces(SEBallast, endpoint_id=3)
.replaces(SEOnOff, endpoint_id=3)
.replaces(SEBasic, endpoint_id=21)
.replaces(SESpecific, endpoint_id=21)
.replaces(SESwitchConfiguration, endpoint_id=21)
.add_to_registry()
)

Expand All @@ -29,6 +29,6 @@
.replaces(SEBasic)
.replaces(SEOnOff)
.replaces(SEBasic, endpoint_id=21)
.replaces(SESpecific, endpoint_id=21)
.replaces(SESwitchConfiguration, endpoint_id=21)
.add_to_registry()
)
Loading
Loading