@@ -600,6 +600,270 @@ async def test_legacy_deprecation(
600600 assert "platform: template" not in issue .translation_placeholders ["config" ]
601601
602602
603+ @pytest .mark .parametrize (
604+ ("domain" , "config" , "strings_to_check" ),
605+ [
606+ (
607+ "light" ,
608+ {
609+ "light" : {
610+ "platform" : "template" ,
611+ "lights" : {
612+ "garage_light_template" : {
613+ "friendly_name" : "Garage Light Template" ,
614+ "min_mireds_template" : 153 ,
615+ "max_mireds_template" : 500 ,
616+ "turn_on" : [],
617+ "turn_off" : [],
618+ "set_temperature" : [],
619+ "set_hs" : [],
620+ "set_level" : [],
621+ }
622+ },
623+ },
624+ },
625+ [
626+ "turn_on: []" ,
627+ "turn_off: []" ,
628+ "set_temperature: []" ,
629+ "set_hs: []" ,
630+ "set_level: []" ,
631+ ],
632+ ),
633+ (
634+ "switch" ,
635+ {
636+ "switch" : {
637+ "platform" : "template" ,
638+ "switches" : {
639+ "my_switch" : {
640+ "friendly_name" : "Switch Template" ,
641+ "turn_on" : [],
642+ "turn_off" : [],
643+ }
644+ },
645+ },
646+ },
647+ [
648+ "turn_on: []" ,
649+ "turn_off: []" ,
650+ ],
651+ ),
652+ (
653+ "light" ,
654+ {
655+ "light" : [
656+ {
657+ "platform" : "template" ,
658+ "lights" : {
659+ "atrium_lichterkette" : {
660+ "unique_id" : "atrium_lichterkette" ,
661+ "friendly_name" : "Atrium Lichterkette" ,
662+ "value_template" : "{{ states('input_boolean.atrium_lichterkette_power') }}" ,
663+ "level_template" : "{% if is_state('input_boolean.atrium_lichterkette_power', 'off') %}\n 0\n {% else %}\n {{ states('input_number.atrium_lichterkette_brightness') | int * (255 / state_attr('input_number.atrium_lichterkette_brightness', 'max') | int) }}\n {% endif %}" ,
664+ "effect_list_template" : "{{ state_attr('input_select.atrium_lichterkette_mode', 'options') }}" ,
665+ "effect_template" : "'{{ states('input_select.atrium_lichterkette_mode')}}'" ,
666+ "turn_on" : [
667+ {
668+ "service" : "button.press" ,
669+ "target" : {
670+ "entity_id" : "button.esphome_web_28a814_lichterkette_on"
671+ },
672+ },
673+ {
674+ "service" : "input_boolean.turn_on" ,
675+ "target" : {
676+ "entity_id" : "input_boolean.atrium_lichterkette_power"
677+ },
678+ },
679+ ],
680+ "turn_off" : [
681+ {
682+ "service" : "button.press" ,
683+ "target" : {
684+ "entity_id" : "button.esphome_web_28a814_lichterkette_off"
685+ },
686+ },
687+ {
688+ "service" : "input_boolean.turn_off" ,
689+ "target" : {
690+ "entity_id" : "input_boolean.atrium_lichterkette_power"
691+ },
692+ },
693+ ],
694+ "set_level" : [
695+ {
696+ "variables" : {
697+ "scaled" : "{{ (brightness / (255 / state_attr('input_number.atrium_lichterkette_brightness', 'max'))) | round | int }}" ,
698+ "diff" : "{{ scaled | int - states('input_number.atrium_lichterkette_brightness') | int }}" ,
699+ "direction" : "{{ 'dim' if diff | int < 0 else 'bright' }}" ,
700+ }
701+ },
702+ {
703+ "repeat" : {
704+ "count" : "{{ diff | int | abs }}" ,
705+ "sequence" : [
706+ {
707+ "service" : "button.press" ,
708+ "target" : {
709+ "entity_id" : "button.esphome_web_28a814_lichterkette_{{ direction }}"
710+ },
711+ },
712+ {"delay" : {"milliseconds" : 500 }},
713+ ],
714+ }
715+ },
716+ {
717+ "service" : "input_number.set_value" ,
718+ "data" : {
719+ "value" : "{{ scaled }}" ,
720+ "entity_id" : "input_number.atrium_lichterkette_brightness" ,
721+ },
722+ },
723+ ],
724+ "set_effect" : [
725+ {
726+ "service" : "button.press" ,
727+ "target" : {
728+ "entity_id" : "button.esphome_web_28a814_lichterkette_{{ effect }}"
729+ },
730+ }
731+ ],
732+ }
733+ },
734+ }
735+ ]
736+ },
737+ [
738+ "scaled: " ,
739+ "diff: " ,
740+ "direction: " ,
741+ ],
742+ ),
743+ (
744+ "cover" ,
745+ {
746+ "cover" : [
747+ {
748+ "platform" : "template" ,
749+ "covers" : {
750+ "large_garage_door" : {
751+ "device_class" : "garage" ,
752+ "friendly_name" : "Large Garage Door" ,
753+ "value_template" : "{% if is_state('binary_sensor.large_garage_door', 'off') %}\n closed\n {% elif is_state('timer.large_garage_opening_timer', 'active') %}\n opening\n {% elif is_state('timer.large_garage_closing_timer', 'active') %} \n closing\n {% elif is_state('binary_sensor.large_garage_door', 'on') %}\n open\n {% endif %}\n " ,
754+ "open_cover" : [
755+ {
756+ "condition" : "state" ,
757+ "entity_id" : "binary_sensor.large_garage_door" ,
758+ "state" : "off" ,
759+ },
760+ {
761+ "action" : "switch.turn_on" ,
762+ "target" : {
763+ "entity_id" : "switch.garage_door_relay_1"
764+ },
765+ },
766+ {
767+ "action" : "timer.start" ,
768+ "entity_id" : "timer.large_garage_opening_timer" ,
769+ },
770+ ],
771+ "close_cover" : [
772+ {
773+ "condition" : "state" ,
774+ "entity_id" : "binary_sensor.large_garage_door" ,
775+ "state" : "on" ,
776+ },
777+ {
778+ "action" : "switch.turn_on" ,
779+ "target" : {
780+ "entity_id" : "switch.garage_door_relay_1"
781+ },
782+ },
783+ {
784+ "action" : "timer.start" ,
785+ "entity_id" : "timer.large_garage_closing_timer" ,
786+ },
787+ ],
788+ "stop_cover" : [
789+ {
790+ "action" : "switch.turn_on" ,
791+ "target" : {
792+ "entity_id" : "switch.garage_door_relay_1"
793+ },
794+ },
795+ {
796+ "action" : "timer.cancel" ,
797+ "entity_id" : "timer.large_garage_opening_timer" ,
798+ },
799+ {
800+ "action" : "timer.cancel" ,
801+ "entity_id" : "timer.large_garage_closing_timer" ,
802+ },
803+ ],
804+ }
805+ },
806+ }
807+ ]
808+ },
809+ ["device_class: garage" ],
810+ ),
811+ (
812+ "binary_sensor" ,
813+ {
814+ "binary_sensor" : {
815+ "platform" : "template" ,
816+ "sensors" : {
817+ "motion_sensor" : {
818+ "friendly_name" : "Motion Sensor" ,
819+ "device_class" : "motion" ,
820+ "value_template" : "{{ is_state('sensor.motion_detector', 'on') }}" ,
821+ }
822+ },
823+ },
824+ },
825+ ["device_class: motion" ],
826+ ),
827+ (
828+ "sensor" ,
829+ {
830+ "sensor" : {
831+ "platform" : "template" ,
832+ "sensors" : {
833+ "some_sensor" : {
834+ "friendly_name" : "Sensor" ,
835+ "device_class" : "timestamp" ,
836+ "value_template" : "{{ now().isoformat() }}" ,
837+ }
838+ },
839+ },
840+ },
841+ ["device_class: timestamp" ],
842+ ),
843+ ],
844+ )
845+ async def test_legacy_deprecation_with_unique_objects (
846+ hass : HomeAssistant ,
847+ domain : str ,
848+ config : dict ,
849+ strings_to_check : list [str ],
850+ issue_registry : ir .IssueRegistry ,
851+ ) -> None :
852+ """Test legacy configuration raises issue and unique objects are properly converted to valid configurations."""
853+
854+ await async_setup_component (hass , domain , config )
855+ await hass .async_block_till_done ()
856+
857+ assert len (issue_registry .issues ) == 1
858+ issue = next (iter (issue_registry .issues .values ()))
859+
860+ assert issue .domain == "template"
861+ assert issue .severity == ir .IssueSeverity .WARNING
862+ assert issue .translation_placeholders is not None
863+ for string in strings_to_check :
864+ assert string in issue .translation_placeholders ["config" ]
865+
866+
603867@pytest .mark .parametrize (
604868 ("domain" , "config" ),
605869 [
0 commit comments