@@ -60,12 +60,11 @@ public class HomeAssistantThingHandlerTests extends AbstractHomeAssistantTests {
60
60
private static final int ATTRIBUTE_RECEIVE_TIMEOUT = 2000 ;
61
61
62
62
private static final List <String > CONFIG_TOPICS = Arrays .asList ("climate/0x847127fffe11dd6a_climate_zigbee2mqtt" ,
63
- "switch/0x847127fffe11dd6a_auto_lock_zigbee2mqtt" ,
64
-
65
- "sensor/0x1111111111111111_test_sensor_zigbee2mqtt" , "camera/0x1111111111111111_test_camera_zigbee2mqtt" ,
66
-
67
- "cover/0x2222222222222222_test_cover_zigbee2mqtt" , "fan/0x2222222222222222_test_fan_zigbee2mqtt" ,
68
- "light/0x2222222222222222_test_light_zigbee2mqtt" , "lock/0x2222222222222222_test_lock_zigbee2mqtt" );
63
+ "switch/0x847127fffe11dd6a_auto_lock_zigbee2mqtt" , "sensor/0x1111111111111111_test_sensor_zigbee2mqtt" ,
64
+ "camera/0x1111111111111111_test_camera_zigbee2mqtt" , "cover/0x2222222222222222_test_cover_zigbee2mqtt" ,
65
+ "fan/0x2222222222222222_test_fan_zigbee2mqtt" , "light/0x2222222222222222_test_light_zigbee2mqtt" ,
66
+ "lock/0x2222222222222222_test_lock_zigbee2mqtt" , "binary_sensor/abc/activeEnergyReports" ,
67
+ "number/abc/activeEnergyReports" , "sensor/abc/activeEnergyReports" );
69
68
70
69
private static final List <String > MQTT_TOPICS = CONFIG_TOPICS .stream ()
71
70
.map (AbstractHomeAssistantTests ::configTopicToMqtt ).collect (Collectors .toList ());
@@ -354,4 +353,171 @@ public void testRestoreComponentFromChannelConfig() {
354
353
assertThat (thingHandler .getComponents ().keySet ().iterator ().next (), is ("switch" ));
355
354
assertThat (thingHandler .getComponents ().values ().iterator ().next ().getClass (), is (Switch .class ));
356
355
}
356
+
357
+ @ Test
358
+ public void testDuplicateChannelId () {
359
+ thingHandler .initialize ();
360
+
361
+ verify (callbackMock ).statusUpdated (eq (haThing ), any ());
362
+ // Expect a call to the bridge status changed, the start, the propertiesChanged method
363
+ verify (thingHandler ).bridgeStatusChanged (any ());
364
+ verify (thingHandler , timeout (SUBSCRIBE_TIMEOUT )).start (any ());
365
+
366
+ MQTT_TOPICS .forEach (t -> {
367
+ verify (bridgeConnection , timeout (SUBSCRIBE_TIMEOUT )).subscribe (eq (t ), any ());
368
+ });
369
+
370
+ verify (thingHandler , never ()).componentDiscovered (any (), any ());
371
+ assertThat (haThing .getChannels ().size (), is (0 ));
372
+
373
+ thingHandler .discoverComponents .processMessage ("homeassistant/number/abc/activeEnergyReports/config" , """
374
+ {
375
+ "name":"ActiveEnergyReports",
376
+ "object_id":"mud_room_cans_switch_(garage)_activeEnergyReports",
377
+ "state_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)",
378
+ "unique_id":"0x04cd15fffedb7f81_activeEnergyReports_zigbee2mqtt",
379
+ "value_template":"{{ value_json.activeEnergyReports }}"
380
+ }
381
+ """ .getBytes (StandardCharsets .UTF_8 ));
382
+ thingHandler .discoverComponents .processMessage ("homeassistant/sensor/abc/activeEnergyReports/config" , """
383
+ {
384
+ "command_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)/set/activeEnergyReports",
385
+ "max":32767,
386
+ "min":0,
387
+ "name":"ActiveEnergyReports",
388
+ "object_id":"mud_room_cans_switch_(garage)_activeEnergyReports",
389
+ "state_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)",
390
+ "unique_id":"0x04cd15fffedb7f81_activeEnergyReports_zigbee2mqtt",
391
+ "value_template":"{{ value_json.activeEnergyReports }}"
392
+ }
393
+ """ .getBytes (StandardCharsets .UTF_8 ));
394
+ thingHandler .delayedProcessing .forceProcessNow ();
395
+ waitForAssert (() -> {
396
+ assertThat ("2 channels created" , nonSpyThingHandler .getThing ().getChannels ().size () == 2 );
397
+ });
398
+
399
+ Channel numberChannel = nonSpyThingHandler .getThing ()
400
+ .getChannel ("0x04cd15fffedb7f81_5FactiveEnergyReports_5Fzigbee2mqtt_number#number" );
401
+ assertThat ("Number channel is created" , numberChannel , notNullValue ());
402
+
403
+ Channel sensorChannel = nonSpyThingHandler .getThing ()
404
+ .getChannel ("0x04cd15fffedb7f81_5FactiveEnergyReports_5Fzigbee2mqtt_sensor#sensor" );
405
+ assertThat ("Sensor channel is created" , sensorChannel , notNullValue ());
406
+ }
407
+
408
+ @ Test
409
+ public void testDuplicateChannelIdNewStyleChannels () {
410
+ haThing .setProperty ("newStyleChannels" , "true" );
411
+ thingHandler = new HomeAssistantThingHandler (haThing , channelTypeProvider , stateDescriptionProvider ,
412
+ channelTypeRegistry , new Jinjava (), SUBSCRIBE_TIMEOUT , ATTRIBUTE_RECEIVE_TIMEOUT );
413
+ thingHandler .setConnection (bridgeConnection );
414
+ thingHandler .setCallback (callbackMock );
415
+ nonSpyThingHandler = thingHandler ;
416
+ thingHandler = spy (thingHandler );
417
+
418
+ thingHandler .initialize ();
419
+
420
+ verify (callbackMock ).statusUpdated (eq (haThing ), any ());
421
+ // Expect a call to the bridge status changed, the start, the propertiesChanged method
422
+ verify (thingHandler ).bridgeStatusChanged (any ());
423
+ verify (thingHandler , timeout (SUBSCRIBE_TIMEOUT )).start (any ());
424
+
425
+ MQTT_TOPICS .forEach (t -> {
426
+ verify (bridgeConnection , timeout (SUBSCRIBE_TIMEOUT )).subscribe (eq (t ), any ());
427
+ });
428
+
429
+ verify (thingHandler , never ()).componentDiscovered (any (), any ());
430
+ assertThat (haThing .getChannels ().size (), is (0 ));
431
+
432
+ thingHandler .discoverComponents .processMessage ("homeassistant/number/abc/activeEnergyReports/config" , """
433
+ {
434
+ "name":"ActiveEnergyReports",
435
+ "object_id":"mud_room_cans_switch_(garage)_activeEnergyReports",
436
+ "state_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)",
437
+ "unique_id":"0x04cd15fffedb7f81_activeEnergyReports_zigbee2mqtt",
438
+ "value_template":"{{ value_json.activeEnergyReports }}"
439
+ }
440
+ """ .getBytes (StandardCharsets .UTF_8 ));
441
+ thingHandler .discoverComponents .processMessage ("homeassistant/sensor/abc/activeEnergyReports/config" , """
442
+ {
443
+ "command_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)/set/activeEnergyReports",
444
+ "max":32767,
445
+ "min":0,
446
+ "name":"ActiveEnergyReports",
447
+ "object_id":"mud_room_cans_switch_(garage)_activeEnergyReports",
448
+ "state_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)",
449
+ "unique_id":"0x04cd15fffedb7f81_activeEnergyReports_zigbee2mqtt",
450
+ "value_template":"{{ value_json.activeEnergyReports }}"
451
+ }
452
+ """ .getBytes (StandardCharsets .UTF_8 ));
453
+ thingHandler .delayedProcessing .forceProcessNow ();
454
+ waitForAssert (() -> {
455
+ assertThat ("2 channels created" , nonSpyThingHandler .getThing ().getChannels ().size () == 2 );
456
+ });
457
+
458
+ Channel numberChannel = nonSpyThingHandler .getThing ().getChannel ("activeEnergyReports_number" );
459
+ assertThat ("Number channel is created" , numberChannel , notNullValue ());
460
+
461
+ Channel sensorChannel = nonSpyThingHandler .getThing ().getChannel ("activeEnergyReports_sensor" );
462
+ assertThat ("Sensor channel is created" , sensorChannel , notNullValue ());
463
+ }
464
+
465
+ @ Test
466
+ public void testDuplicateChannelIdNewStyleChannelsComplex () {
467
+ haThing .setProperty ("newStyleChannels" , "true" );
468
+ thingHandler = new HomeAssistantThingHandler (haThing , channelTypeProvider , stateDescriptionProvider ,
469
+ channelTypeRegistry , new Jinjava (), SUBSCRIBE_TIMEOUT , ATTRIBUTE_RECEIVE_TIMEOUT );
470
+ thingHandler .setConnection (bridgeConnection );
471
+ thingHandler .setCallback (callbackMock );
472
+ nonSpyThingHandler = thingHandler ;
473
+ thingHandler = spy (thingHandler );
474
+
475
+ thingHandler .initialize ();
476
+
477
+ verify (callbackMock ).statusUpdated (eq (haThing ), any ());
478
+ // Expect a call to the bridge status changed, the start, the propertiesChanged method
479
+ verify (thingHandler ).bridgeStatusChanged (any ());
480
+ verify (thingHandler , timeout (SUBSCRIBE_TIMEOUT )).start (any ());
481
+
482
+ MQTT_TOPICS .forEach (t -> {
483
+ verify (bridgeConnection , timeout (SUBSCRIBE_TIMEOUT )).subscribe (eq (t ), any ());
484
+ });
485
+
486
+ verify (thingHandler , never ()).componentDiscovered (any (), any ());
487
+ assertThat (haThing .getChannels ().size (), is (0 ));
488
+
489
+ thingHandler .discoverComponents .processMessage ("homeassistant/number/abc/activeEnergyReports/config" , """
490
+ {
491
+ "name":"ActiveEnergyReports",
492
+ "object_id":"mud_room_cans_switch_(garage)_activeEnergyReports",
493
+ "state_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)",
494
+ "unique_id":"0x04cd15fffedb7f81_activeEnergyReports_zigbee2mqtt",
495
+ "value_template":"{{ value_json.activeEnergyReports }}",
496
+ "json_attributes_topic":"somewhere"
497
+ }
498
+ """ .getBytes (StandardCharsets .UTF_8 ));
499
+ thingHandler .discoverComponents .processMessage ("homeassistant/sensor/abc/activeEnergyReports/config" , """
500
+ {
501
+ "command_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)/set/activeEnergyReports",
502
+ "max":32767,
503
+ "min":0,
504
+ "name":"ActiveEnergyReports",
505
+ "object_id":"mud_room_cans_switch_(garage)_activeEnergyReports",
506
+ "state_topic":"zigbee2mqtt/Mud Room Cans Switch (Garage)",
507
+ "unique_id":"0x04cd15fffedb7f81_activeEnergyReports_zigbee2mqtt",
508
+ "value_template":"{{ value_json.activeEnergyReports }}",
509
+ "json_attributes_topic":"somewhere"
510
+ }
511
+ """ .getBytes (StandardCharsets .UTF_8 ));
512
+ thingHandler .delayedProcessing .forceProcessNow ();
513
+ waitForAssert (() -> {
514
+ assertThat ("4 channels created" , nonSpyThingHandler .getThing ().getChannels ().size () == 4 );
515
+ });
516
+
517
+ Channel numberChannel = nonSpyThingHandler .getThing ().getChannel ("activeEnergyReports_number#number" );
518
+ assertThat ("Number channel is created" , numberChannel , notNullValue ());
519
+
520
+ Channel sensorChannel = nonSpyThingHandler .getThing ().getChannel ("activeEnergyReports_sensor#sensor" );
521
+ assertThat ("Sensor channel is created" , sensorChannel , notNullValue ());
522
+ }
357
523
}
0 commit comments