61
61
ZCL_TUYA_VALVE_AUTO_LOCK_ON = b"\t 2\x01 \x03 \x04 \x74 \x01 \x00 \x01 \x01 "
62
62
ZCL_TUYA_VALVE_BATTERY_LOW = b"\t 2\x01 \x03 \x04 \x6E \x01 \x00 \x01 \x01 "
63
63
64
+ ZCL_TUYA_VALVE_ZONNSMART_TEMPERATURE = (
65
+ b"\t p\x01 \x00 \x02 \x18 \x02 \x00 \x04 \x00 \x00 \x00 \xd3 "
66
+ )
67
+ ZCL_TUYA_VALVE_ZONNSMART_TARGET_TEMP = (
68
+ b"\t 3\x01 \x03 \x05 \x10 \x02 \x00 \x04 \x00 \x00 \x00 \xcd "
69
+ )
70
+ ZCL_TUYA_VALVE_ZONNSMART_HOLIDAY_TEMP = (
71
+ b"\t 3\x01 \x03 \x05 \x20 \x02 \x00 \x04 \x00 \x00 \x00 \xaa "
72
+ )
73
+ ZCL_TUYA_VALVE_ZONNSMART_TEMP_OFFSET = (
74
+ b"\t 3\x01 \x03 \x05 \x1b \x02 \x00 \x04 \x00 \x00 \x00 \x0b "
75
+ )
76
+ ZCL_TUYA_VALVE_ZONNSMART_MODE_MANUAL = b"\t 2\x01 \x03 \x04 \x02 \x04 \x00 \x01 \x01 "
77
+ ZCL_TUYA_VALVE_ZONNSMART_MODE_SCHEDULE = b"\t 2\x01 \x03 \x04 \x02 \x04 \x00 \x01 \x00 "
78
+ ZCL_TUYA_VALVE_ZONNSMART_HEAT_STOP = b"\t 2\x01 \x03 \x04 \x6b \x01 \x00 \x01 \x00 "
79
+
64
80
ZCL_TUYA_EHEAT_TEMPERATURE = b"\t p\x02 \x00 \x02 \x18 \x02 \x00 \x04 \x00 \x00 \x00 \xb3 "
65
81
ZCL_TUYA_EHEAT_TARGET_TEMP = b"\t 3\x01 \x03 \x05 \x10 \x02 \x00 \x04 \x00 \x00 \x00 \x15 "
66
82
@@ -223,8 +239,8 @@ async def test_singleswitch_requests(zigpy_device_from_quirk, quirk):
223
239
status = await switch_cluster .command (0x0000 )
224
240
m1 .assert_called_with (
225
241
61184 ,
226
- 1 ,
227
- b"\x01 \x01 \x00 \x00 \x00 \x01 \x01 \x00 \x01 \x00 " ,
242
+ 2 ,
243
+ b"\x01 \x02 \x00 \x00 \x01 \x01 \x01 \x00 \x01 \x00 " ,
228
244
expect_reply = True ,
229
245
command_id = 0 ,
230
246
)
@@ -233,8 +249,8 @@ async def test_singleswitch_requests(zigpy_device_from_quirk, quirk):
233
249
status = await switch_cluster .command (0x0001 )
234
250
m1 .assert_called_with (
235
251
61184 ,
236
- 2 ,
237
- b"\x01 \x02 \x00 \x00 \x00 \x01 \x01 \x00 \x01 \x01 " ,
252
+ 4 ,
253
+ b"\x01 \x04 \x00 \x00 \x03 \x01 \x01 \x00 \x01 \x01 " ,
238
254
expect_reply = True ,
239
255
command_id = 0 ,
240
256
)
@@ -408,6 +424,130 @@ async def async_success(*args, **kwargs):
408
424
assert status == foundation .Status .UNSUP_CLUSTER_COMMAND
409
425
410
426
427
+ @pytest .mark .parametrize ("quirk" , (zhaquirks .tuya .ts0601_trv .ZonnsmartTV01_ZG ,))
428
+ async def test_zonnsmart_state_report (zigpy_device_from_quirk , quirk ):
429
+ """Test thermostatic valves standard reporting from incoming commands."""
430
+
431
+ valve_dev = zigpy_device_from_quirk (quirk )
432
+ tuya_cluster = valve_dev .endpoints [1 ].tuya_manufacturer
433
+
434
+ thermostat_listener = ClusterListener (valve_dev .endpoints [1 ].thermostat )
435
+
436
+ frames = (
437
+ ZCL_TUYA_VALVE_ZONNSMART_TEMPERATURE ,
438
+ ZCL_TUYA_VALVE_ZONNSMART_TARGET_TEMP ,
439
+ ZCL_TUYA_VALVE_ZONNSMART_HOLIDAY_TEMP ,
440
+ ZCL_TUYA_VALVE_ZONNSMART_TEMP_OFFSET ,
441
+ ZCL_TUYA_VALVE_ZONNSMART_MODE_MANUAL ,
442
+ ZCL_TUYA_VALVE_ZONNSMART_MODE_SCHEDULE ,
443
+ ZCL_TUYA_VALVE_ZONNSMART_HEAT_STOP ,
444
+ )
445
+ for frame in frames :
446
+ hdr , args = tuya_cluster .deserialize (frame )
447
+ tuya_cluster .handle_message (hdr , args )
448
+
449
+ assert len (thermostat_listener .cluster_commands ) == 0
450
+ assert len (thermostat_listener .attribute_updates ) == 11
451
+ assert thermostat_listener .attribute_updates [0 ][0 ] == 0x0000 # TEMP
452
+ assert thermostat_listener .attribute_updates [0 ][1 ] == 2110
453
+ assert thermostat_listener .attribute_updates [1 ][0 ] == 0x0012 # TARGET
454
+ assert thermostat_listener .attribute_updates [1 ][1 ] == 2050
455
+ assert thermostat_listener .attribute_updates [4 ][0 ] == 0x0014 # HOLIDAY
456
+ assert thermostat_listener .attribute_updates [4 ][1 ] == 1700
457
+ assert thermostat_listener .attribute_updates [5 ][0 ] == 0x0010 # OFFSET
458
+ assert thermostat_listener .attribute_updates [5 ][1 ] == 110
459
+ assert thermostat_listener .attribute_updates [6 ][0 ] == 0x0025 # MANUAL
460
+ assert thermostat_listener .attribute_updates [6 ][1 ] == 0
461
+ assert thermostat_listener .attribute_updates [7 ][0 ] == 0x4002
462
+ assert thermostat_listener .attribute_updates [7 ][1 ] == 1
463
+ assert thermostat_listener .attribute_updates [8 ][0 ] == 0x0025 # SCHEDULE
464
+ assert thermostat_listener .attribute_updates [8 ][1 ] == 1
465
+ assert thermostat_listener .attribute_updates [9 ][0 ] == 0x4002
466
+ assert thermostat_listener .attribute_updates [9 ][1 ] == 0
467
+ assert thermostat_listener .attribute_updates [10 ][0 ] == 0x001C # HEAT ON
468
+ assert thermostat_listener .attribute_updates [10 ][1 ] == 4
469
+
470
+
471
+ @pytest .mark .parametrize ("quirk" , (zhaquirks .tuya .ts0601_trv .ZonnsmartTV01_ZG ,))
472
+ async def test_zonnsmart_send_attribute (zigpy_device_from_quirk , quirk ):
473
+ """Test thermostatic valve outgoing commands."""
474
+
475
+ valve_dev = zigpy_device_from_quirk (quirk )
476
+ tuya_cluster = valve_dev .endpoints [1 ].tuya_manufacturer
477
+ thermostat_cluster = valve_dev .endpoints [1 ].thermostat
478
+
479
+ async def async_success (* args , ** kwargs ):
480
+ return foundation .Status .SUCCESS
481
+
482
+ with mock .patch .object (
483
+ tuya_cluster .endpoint , "request" , side_effect = async_success
484
+ ) as m1 :
485
+
486
+ (status ,) = await thermostat_cluster .write_attributes (
487
+ {
488
+ "occupied_heating_setpoint" : 2500 ,
489
+ }
490
+ )
491
+ m1 .assert_called_with (
492
+ 61184 ,
493
+ 1 ,
494
+ b"\x01 \x01 \x00 \x00 \x01 \x10 \x02 \x00 \x04 \x00 \x00 \x00 \xfa " ,
495
+ expect_reply = False ,
496
+ command_id = 0 ,
497
+ )
498
+ assert status == [
499
+ foundation .WriteAttributesStatusRecord (foundation .Status .SUCCESS )
500
+ ]
501
+
502
+ (status ,) = await thermostat_cluster .write_attributes (
503
+ {
504
+ "operation_preset" : 1 ,
505
+ }
506
+ )
507
+ m1 .assert_called_with (
508
+ 61184 ,
509
+ 2 ,
510
+ b"\x01 \x02 \x00 \x00 \x02 \x02 \x04 \x00 \x01 \x01 " ,
511
+ expect_reply = False ,
512
+ command_id = 0 ,
513
+ )
514
+ assert status == [
515
+ foundation .WriteAttributesStatusRecord (foundation .Status .SUCCESS )
516
+ ]
517
+
518
+ (status ,) = await thermostat_cluster .write_attributes (
519
+ {
520
+ "operation_preset" : 4 , # frost protection wrapped as operation_preset
521
+ }
522
+ )
523
+ m1 .assert_called_with (
524
+ 61184 ,
525
+ 3 ,
526
+ b"\x01 \x03 \x00 \x00 \x03 \x0a \x01 \x00 \x01 \x01 " ,
527
+ expect_reply = False ,
528
+ command_id = 0 ,
529
+ )
530
+ assert status == [
531
+ foundation .WriteAttributesStatusRecord (foundation .Status .SUCCESS )
532
+ ]
533
+
534
+ (status ,) = await thermostat_cluster .write_attributes (
535
+ {
536
+ "system_mode" : 0 , # SystemMode.Off
537
+ }
538
+ )
539
+ m1 .assert_called_with (
540
+ 61184 ,
541
+ 4 ,
542
+ b"\x01 \x04 \x00 \x00 \x04 \x6b \x01 \x00 \x01 \x01 " ,
543
+ expect_reply = False ,
544
+ command_id = 0 ,
545
+ )
546
+ assert status == [
547
+ foundation .WriteAttributesStatusRecord (foundation .Status .SUCCESS )
548
+ ]
549
+
550
+
411
551
@pytest .mark .parametrize ("quirk" , (zhaquirks .tuya .ts0601_trv .SiterwellGS361_Type1 ,))
412
552
async def test_valve_state_report (zigpy_device_from_quirk , quirk ):
413
553
"""Test thermostatic valves standard reporting from incoming commands."""
0 commit comments