@@ -39,3 +39,71 @@ async def test_control_doors(mocker):
3939
4040 assert await alarm .control_door ("Door 1" , "unlock" )
4141 alarm .panel .control_doors .assert_called_once_with ([1 ], "unlock" )
42+
43+
44+ def _add_module_pgm (alarm , module_address , pgm_index ):
45+ key = f"module{ module_address } _pgm{ pgm_index } "
46+ alarm .storage .get_container ("module_pgm" )[key ] = {
47+ "id" : pgm_index ,
48+ "key" : key ,
49+ "label" : f"Module { module_address } PGM { pgm_index } " ,
50+ "module_address" : module_address ,
51+ "pgm_index" : pgm_index ,
52+ }
53+ alarm .storage .update_container_object ("module_pgm" , key , {"on" : False })
54+ return key
55+
56+
57+ @pytest .mark .asyncio
58+ async def test_control_output_regular_pgm_routes_to_control_outputs (mocker ):
59+ """Regular PGM uses control_outputs, not control_module_pgm_outputs."""
60+ alarm = Paradox ()
61+ alarm .panel = mocker .Mock (spec = Panel )
62+ alarm .panel .control_outputs = AsyncMock (return_value = True )
63+ alarm .panel .control_module_pgm_outputs = AsyncMock (return_value = True )
64+
65+ alarm .storage .get_container ("pgm" ).deep_merge ({1 : {"id" : 1 , "key" : "PGM 1" }})
66+
67+ assert await alarm .control_output ("PGM 1" , "on" )
68+ alarm .panel .control_outputs .assert_called_once ()
69+ alarm .panel .control_module_pgm_outputs .assert_not_called ()
70+
71+
72+ @pytest .mark .asyncio
73+ async def test_control_output_module_pgm_routes_to_control_module_pgm_outputs (mocker ):
74+ """Module PGM uses control_module_pgm_outputs with the correct address and index."""
75+ alarm = Paradox ()
76+ alarm .panel = mocker .Mock (spec = Panel )
77+ alarm .panel .control_outputs = AsyncMock (return_value = True )
78+ alarm .panel .control_module_pgm_outputs = AsyncMock (return_value = True )
79+
80+ _add_module_pgm (alarm , module_address = 4 , pgm_index = 2 )
81+
82+ assert await alarm .control_output ("module4_pgm2" , "on_override" )
83+ alarm .panel .control_module_pgm_outputs .assert_called_once_with (4 , 2 , "on_override" )
84+ alarm .panel .control_outputs .assert_not_called ()
85+
86+
87+ @pytest .mark .asyncio
88+ async def test_control_output_module_pgm_optimistic_state (mocker ):
89+ """Accepted on_override sets on=True; off_override sets on=False."""
90+ alarm = Paradox ()
91+ alarm .panel = mocker .Mock (spec = Panel )
92+ alarm .panel .control_module_pgm_outputs = AsyncMock (return_value = True )
93+
94+ key = _add_module_pgm (alarm , module_address = 4 , pgm_index = 1 )
95+
96+ await alarm .control_output (key , "on_override" )
97+ assert alarm .storage .get_container ("module_pgm" )[key ]["on" ] is True
98+
99+ await alarm .control_output (key , "off_override" )
100+ assert alarm .storage .get_container ("module_pgm" )[key ]["on" ] is False
101+
102+
103+ @pytest .mark .asyncio
104+ async def test_control_output_no_match_returns_false (mocker ):
105+ """Returns False when the output key matches neither pgm nor module_pgm."""
106+ alarm = Paradox ()
107+ alarm .panel = mocker .Mock (spec = Panel )
108+
109+ assert await alarm .control_output ("nonexistent" , "on" ) is False
0 commit comments