def refresh_from_db(self): # type: () -> None with self._config_change_lock: # Collect valve drivers current_ids = [] for item in Valve.select(): if item.id in self._valve_drivers: self._valve_drivers[item.id].update(item) else: self._valve_drivers[item.id] = ValveDriver(item) current_ids.append(item.id) for item_id in list(self._valve_drivers.keys()): if item_id not in current_ids: del self._valve_drivers[item_id] # Collect pump drivers current_ids = [] pump_drivers_per_valve = {} # type: Dict[int, Set[PumpDriver]] for item in Pump.select(): if item.id in self._pump_drivers: pump_driver = self._pump_drivers[item.id] pump_driver.update(item) else: pump_driver = PumpDriver(item) self._pump_drivers[item.id] = pump_driver current_ids.append(item.id) for valve_id in pump_driver.valve_ids: if valve_id not in pump_drivers_per_valve: pump_drivers_per_valve[valve_id] = set() pump_drivers_per_valve[valve_id].add(pump_driver) for item_id in list(self._pump_drivers.keys()): if item_id not in current_ids: del self._pump_drivers[item_id] self._pump_drivers_per_valve = pump_drivers_per_valve
def _save_pump_groups( mode, pump_groups ): # type: (str, List[Tuple[PumpGroupDTO, List[str]]]) -> None for pump_group_dto, fields in pump_groups: if 'pump_output_id' in fields and 'valve_output_ids' in fields: valve_output_ids = pump_group_dto.valve_output_ids pump = Pump.get(id=pump_group_dto.id) # type: Pump pump.output = Output.get(number=pump_group_dto.pump_output_id) links = { pump_to_valve.valve.output.number: pump_to_valve for pump_to_valve in PumpToValve.select( PumpToValve, Pump, Valve, Output).join_from( PumpToValve, Valve).join_from( PumpToValve, Pump).join_from(Valve, Output). join_from(Valve, ValveToThermostat).where(( ValveToThermostat.mode == mode) & (Pump.id == pump.id)) } for output_id in list(links.keys()): if output_id not in valve_output_ids: pump_to_valve = links.pop( output_id) # type: PumpToValve pump_to_valve.delete_instance() else: valve_output_ids.remove(output_id) for output_id in valve_output_ids: output = Output.get(number=output_id) valve = Valve.get_or_none(output=output) if valve is None: valve = Valve(name=output.name, output=output) valve.save() PumpToValve.create(pump=pump, valve=valve)
def load_cooling_pump_group(self, pump_group_id): # type: (int) -> PumpGroupDTO pump = Pump.get(number=pump_group_id) return PumpGroupDTO(id=pump_group_id, pump_output_id=pump.output.number, valve_output_ids=[ valve.output.number for valve in pump.cooling_valves ], room_id=None)
def load_cooling_pump_groups(self): # type: () -> List[PumpGroupDTO] pump_groups = [] for pump in Pump.select(): pump_groups.append( PumpGroupDTO(id=pump.id, pump_output_id=pump.output.number, valve_output_ids=[ valve.output.number for valve in pump.cooling_valves ], room_id=None)) return pump_groups
def test_pump_driver(self): output = Output.create(number=0) pump = Pump.create(number=1, name='pump', output=output) SetUpTestInjections(output_controller=mock.Mock(OutputController)) driver = PumpDriver(pump) self.assertIsNone(driver.state) self.assertFalse(driver.error) self.assertEqual(pump.id, driver.id) driver.turn_on() self.assertTrue(driver.state) self.assertFalse(driver.error) driver.turn_off() self.assertFalse(driver.state) self.assertFalse(driver.error) driver._output_controller.set_output_status.side_effect = RuntimeError() with self.assertRaises(RuntimeError): driver.turn_on() self.assertFalse(driver.state) self.assertTrue(driver.error) driver._output_controller.set_output_status.side_effect = None driver.turn_on() self.assertTrue(driver.state) self.assertFalse(driver.error) driver._output_controller.set_output_status.side_effect = RuntimeError() with self.assertRaises(RuntimeError): driver.turn_off() self.assertTrue(driver.state) self.assertTrue(driver.error) driver._output_controller.set_output_status.side_effect = None driver.turn_off() self.assertFalse(driver.state) self.assertFalse(driver.error)
def test_save_pumpgroups(self): thermostat = Thermostat.create(number=1, name='thermostat 1', sensor=Sensor.create(number=10), pid_heating_p=200, pid_heating_i=100, pid_heating_d=50, pid_cooling_p=200, pid_cooling_i=100, pid_cooling_d=50, automatic=True, room=None, start=0, valve_config='equal', thermostat_group=self._thermostat_group) valve_1_output = Output.create(number=1) valve_1 = Valve.create(number=1, name='valve 1', output=valve_1_output) valve_2_output = Output.create(number=2) valve_2 = Valve.create(number=2, name='valve 2', output=valve_2_output) valve_3_output = Output.create(number=3) valve_3 = Valve.create(number=3, name='valve 3', output=valve_3_output) ValveToThermostat.create(thermostat=thermostat, valve=valve_1, mode=ThermostatGroup.Modes.HEATING, priority=0) ValveToThermostat.create(thermostat=thermostat, valve=valve_2, mode=ThermostatGroup.Modes.COOLING, priority=0) ValveToThermostat.create(thermostat=thermostat, valve=valve_3, mode=ThermostatGroup.Modes.HEATING, priority=0) Preset.create(type=Preset.Types.SCHEDULE, heating_setpoint=20.0, cooling_setpoint=25.0, active=True, thermostat=thermostat) pump_output = Output.create(number=4) pump = Pump.create(name='pump 1', output=pump_output) heating_pump_groups = self._thermostat_controller.load_heating_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[], room_id=None)], heating_pump_groups) PumpToValve.create(pump=pump, valve=valve_1) PumpToValve.create(pump=pump, valve=valve_2) pump_groups = self._thermostat_controller.load_heating_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_1_output.id], room_id=None)], pump_groups) pump_groups = self._thermostat_controller.load_cooling_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_2_output.id], room_id=None)], pump_groups) self._thermostat_controller._save_pump_groups(ThermostatGroup.Modes.HEATING, [(PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_1_output.id, valve_3_output.id]), ['pump_output_id', 'valve_output_ids'])]) pump_groups = self._thermostat_controller.load_heating_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_1_output.id, valve_3_output.id], room_id=None)], pump_groups) pump_groups = self._thermostat_controller.load_cooling_pump_groups() self.assertEqual([PumpGroupDTO(id=pump.id, pump_output_id=pump_output.id, valve_output_ids=[valve_2_output.id], room_id=None)], pump_groups)
def test_transitions(self): pump_1 = Pump.create(number=1, name='pump 1', output=Output.create(number=1)) pump_2 = Pump.create(number=2, name='pump 2', output=Output.create(number=2)) valve_1 = Valve.create(number=1, name='valve 1', delay=30, output=Output.create(number=11)) valve_2 = Valve.create(number=2, name='valve 2', delay=15, output=Output.create(number=12)) valve_3 = Valve.create(number=3, name='valve 3', delay=15, output=Output.create(number=13)) PumpToValve.create(pump=pump_1, valve=valve_1) PumpToValve.create(pump=pump_1, valve=valve_2) PumpToValve.create(pump=pump_2, valve=valve_3) SetUpTestInjections(output_controller=mock.Mock(OutputController)) controller = PumpValveController() controller.refresh_from_db() valve_driver_1 = controller.get_valve_driver(1) valve_driver_2 = controller.get_valve_driver(2) valve_driver_3 = controller.get_valve_driver(3) pump_driver_1 = controller._pump_drivers[1] pump_driver_2 = controller._pump_drivers[2] # Initial state, everything is off self.assertFalse(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(0, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Set the second valve to 50% # The pump should only be turned on after 15s valve_driver_2.set(50) controller.steer() self.assertFalse(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Pump still off after 10s time.sleep(10) controller.steer() self.assertFalse(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Pump is on after 10s time.sleep(10) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(0, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage) # Other valves are also opened valve_driver_1.set(100) valve_driver_3.set(100) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(100, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(100, valve_driver_3.percentage) # After a time, both valves are fully open time.sleep(40) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(100, valve_driver_1.percentage) self.assertEqual(50, valve_driver_2.percentage) self.assertTrue(pump_driver_2.state) self.assertEqual(100, valve_driver_3.percentage) # Two valves are closed again # When valves are closed, the pumps are stopped immediately valve_driver_2.set(0) valve_driver_3.set(0) time.sleep(10) controller.steer() self.assertTrue(pump_driver_1.state) self.assertEqual(100, valve_driver_1.percentage) self.assertEqual(0, valve_driver_2.percentage) self.assertFalse(pump_driver_2.state) self.assertEqual(0, valve_driver_3.percentage)