import asyncio from types import SimpleNamespace from app.auto.config import TemperatureConfig from app.auto.controller import AutoController from app.auto.temperature_policy import TemperaturePolicy from app.my_dataclasses import MAX_TARGET_TEMP class FakeQingpingService: def __init__(self): self.online = True self.state = SimpleNamespace( temperature=19.0, ) class FakeTionController: def __init__(self): self.calls = [] async def set_target_temperature( self, temperature: int, ): self.calls.append( ( "set_target_temperature", temperature, ) ) async def heater_on(self): self.calls.append( ( "heater_on", None, ) ) async def heater_off(self): self.calls.append( ( "heater_off", None, ) ) class FakeTionService: def __init__(self): self.online = True self.state = SimpleNamespace( in_temp=22, ) self.controller = FakeTionController() async def execute( self, operation, ): return await operation( self.controller ) def make_controller(): qingping = FakeQingpingService() tion = FakeTionService() temperature_policy = TemperaturePolicy( TemperatureConfig( hysteresis=0.5, ) ) controller = AutoController( schedule_service=None, qingping_service=qingping, tion_service=tion, temperature_policy=temperature_policy, ) return ( controller, qingping, tion, ) def make_resolution( target_temp: int, ): return SimpleNamespace( auto_target_temp=target_temp, ) async def test_heating_sets_tion_target_first(): controller, qingping, tion = ( make_controller() ) resolution = make_resolution( target_temp=20 ) # Qingping = 19.0 # AUTO target = 20 # # Нужно греть. # # Сначала Tion.target_temp поднимается # до технического максимума, # затем включается heater. await controller._process_heater( resolution ) assert tion.controller.calls == [ ( "set_target_temperature", MAX_TARGET_TEMP, ), ( "heater_on", None, ), ] assert ( controller._target_temperature == MAX_TARGET_TEMP ) assert ( controller._target_heater is True ) assert ( controller._auto_heater is True ) async def test_repeated_heating_does_not_repeat_commands(): controller, qingping, tion = ( make_controller() ) resolution = make_resolution( target_temp=20 ) await controller._process_heater( resolution ) tion.controller.calls.clear() # Температура всё ещё ниже цели. # AUTO продолжает хотеть нагрев, # но повторно слать команды Tion не нужно. qingping.state.temperature = 19.2 await controller._process_heater( resolution ) assert tion.controller.calls == [] async def test_target_reached_turns_heater_off(): controller, qingping, tion = ( make_controller() ) resolution = make_resolution( target_temp=20 ) # Сначала включаем нагрев. await controller._process_heater( resolution ) tion.controller.calls.clear() # Цель достигнута. qingping.state.temperature = 20.0 await controller._process_heater( resolution ) # MAX_TARGET_TEMP обратно сейчас не меняем. # Достаточно запретить нагрев. assert tion.controller.calls == [ ( "heater_off", None, ) ] assert ( controller._auto_heater is False ) assert ( controller._target_heater is False ) async def main(): await test_heating_sets_tion_target_first() await test_repeated_heating_does_not_repeat_commands() await test_target_reached_turns_heater_off() print() print("=" * 70) print( "ALL AUTO HEATER TION TARGET " "TESTS PASSED" ) print("=" * 70) if __name__ == "__main__": asyncio.run(main())