def _get_thermostat_pid(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) ValveToThermostat.create(thermostat=thermostat, valve=Valve.create( number=1, name='valve 1', output=Output.create(number=1)), mode=ThermostatGroup.Modes.HEATING, priority=0) ValveToThermostat.create(thermostat=thermostat, valve=Valve.create( number=2, name='valve 2', output=Output.create(number=2)), mode=ThermostatGroup.Modes.COOLING, priority=0) Preset.create(type=Preset.Types.SCHEDULE, heating_setpoint=20.0, cooling_setpoint=25.0, active=True, thermostat=thermostat) return ThermostatPid(thermostat=thermostat, pump_valve_controller=self._pump_valve_controller)
def dto_to_orm( thermostat_dto, fields, mode): # type: (ThermostatDTO, List[str], str) -> Thermostat # TODO: A mapper should not alter the database, but instead give an in-memory # structure back to the caller to process objects = {} # type: Dict[str, Dict[int, Any]] def _load_object(orm_type, number): if number is None: return None return objects.setdefault(orm_type.__name__, {}).setdefault( number, orm_type.get(number=number)) # We don't get a start date, calculate last monday night to map the schedules now = int(time.time()) day_of_week = (now / 86400 - 4) % 7 # 0: Monday, 1: Tuesday, ... last_monday_night = now - now % 86400 - day_of_week * 86400 # Update/save thermostat configuration try: thermostat = Thermostat.get(number=thermostat_dto.id) except Thermostat.DoesNotExist: thermostat_group = ThermostatGroup.get(number=0) thermostat = Thermostat(number=thermostat_dto.id) thermostat.thermostat_group = thermostat_group for orm_field, (dto_field, mapping) in { 'name': ('name', None), 'sensor': ('sensor', lambda n: _load_object(Sensor, n)), 'room': ('room', lambda n: _load_object(Room, n)), 'pid_{0}_p'.format(mode): ('pid_p', float), 'pid_{0}_i'.format(mode): ('pid_i', float), 'pid_{0}_d'.format(mode): ('pid_d', float) }.items(): if dto_field not in fields: continue value = getattr(thermostat_dto, dto_field) if value is None: continue if mapping is not None: value = mapping(value) setattr(thermostat, orm_field, value) thermostat.start = last_monday_night thermostat.save() # Update/save output configuration output_config_present = 'output0' in fields or 'output1' in fields if output_config_present: # Unlink all previously linked valve_ids, we are resetting this with the new outputs we got from the API deleted = ValveToThermostat \ .delete() \ .where(ValveToThermostat.thermostat == thermostat) \ .where(ValveToThermostat.mode == mode) \ .execute() logger.info('Unlinked {0} valve_ids from thermostat {1}'.format( deleted, thermostat.name)) for field in ['output0', 'output1']: dto_data = getattr(thermostat_dto, field) if dto_data is None: continue # 1. Get or create output, creation also saves to db output_number = int(dto_data) output, output_created = Output.get_or_create( number=output_number) # 2. Get or create the valve and link to this output try: valve = Valve.get(output=output) except DoesNotExist: valve = Valve(output=output) valve.name = 'Valve (output {0})'.format(output_number) valve.save() # 3. Link the valve to the thermostat, set properties try: valve_to_thermostat = ValveToThermostat.get( valve=valve, thermostat=thermostat, mode=mode) except DoesNotExist: valve_to_thermostat = ValveToThermostat( valve=valve, thermostat=thermostat, mode=mode) # TODO: Decide if this is a cooling thermostat or heating thermostat valve_to_thermostat.priority = 0 if field == 'output0' else 1 valve_to_thermostat.save() # Update/save scheduling configuration for day_index, key in [ (0, 'auto_mon'), (1, 'auto_tue'), (2, 'auto_wed'), (3, 'auto_thu'), (4, 'auto_fri'), (5, 'auto_sat'), (6, 'auto_sun') ]: if key not in fields: continue dto_data = getattr(thermostat_dto, key) if dto_data is None: continue try: day_schedule = DaySchedule.get(thermostat=thermostat, index=day_index, mode=mode) except DoesNotExist: day_schedule = DaySchedule(thermostat=thermostat, index=day_index, mode=mode) day_schedule.schedule_data = ThermostatMapper._schedule_dto_to_orm( dto_data) day_schedule.save() # Presets for field, preset_type in [('setp3', Preset.Types.AWAY), ('setp4', Preset.Types.VACATION), ('setp5', Preset.Types.PARTY)]: if field not in fields: continue dto_data = getattr(thermostat_dto, field) if dto_data is None: continue try: preset = Preset.get(type=preset_type, thermostat=thermostat) except DoesNotExist: preset = Preset(type=preset_type, thermostat=thermostat) setattr(preset, '{0}_setpoint'.format(mode), float(dto_data)) preset.active = False preset.save() # TODO: Map missing [permanent_manual, setp0, setp1, setp2, pid_int] return thermostat
def test_thermostat_control(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) Output.create(number=1) Output.create(number=2) Output.create(number=3) valve_output = Output.create(number=4) valve = Valve.create(number=1, name='valve 1', output=valve_output) ValveToThermostat.create(thermostat=thermostat, valve=valve, mode=ThermostatGroup.Modes.HEATING, priority=0) self._thermostat_controller.refresh_config_from_db() expected = ThermostatGroupStatusDTO(id=0, on=True, setpoint=0, cooling=False, automatic=True, statusses=[ThermostatStatusDTO(id=1, name='thermostat 1', automatic=True, setpoint=0, sensor_id=10, actual_temperature=10.0, setpoint_temperature=14.0, outside_temperature=10.0, output_0_level=0, output_1_level=0, mode=0, airco=0)]) self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_current_setpoint(thermostat_number=1, heating_temperature=15.0) expected.statusses[0].setpoint_temperature = 15.0 self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_per_thermostat_mode(thermostat_number=1, automatic=True, setpoint=16.0) expected.statusses[0].setpoint_temperature = 16.0 self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) preset = self._thermostat_controller.get_current_preset(thermostat_number=1) self.assertTrue(preset.active) self.assertEqual(30.0, preset.cooling_setpoint) self.assertEqual(16.0, preset.heating_setpoint) self.assertEqual(Preset.Types.SCHEDULE, preset.type) self._thermostat_controller.set_current_preset(thermostat_number=1, preset_type=Preset.Types.PARTY) expected.statusses[0].setpoint_temperature = 14.0 expected.statusses[0].setpoint = expected.setpoint = 5 # PARTY = legacy `5` setpoint expected.statusses[0].automatic = expected.automatic = False self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_thermostat_mode(thermostat_on=True, cooling_mode=True, cooling_on=True, automatic=False, setpoint=4) expected.statusses[0].setpoint_temperature = 30.0 expected.statusses[0].setpoint = expected.setpoint = 4 # VACATION = legacy `4` setpoint expected.cooling = True self.assertEqual(expected, self._thermostat_controller.get_thermostat_status()) self._thermostat_controller.set_thermostat_mode(thermostat_on=True, cooling_mode=False, cooling_on=True, automatic=True) expected.statusses[0].setpoint_temperature = 16.0 expected.statusses[0].setpoint = expected.setpoint = 0 # AUTO = legacy `0/1/2` setpoint expected.statusses[0].automatic = expected.automatic = True expected.cooling = False self.assertEqual(expected, self._thermostat_controller.get_thermostat_status())
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_thermostat_group_crud(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) Output.create(number=1) Output.create(number=2) Output.create(number=3) valve_output = Output.create(number=4) valve = Valve.create(number=1, name='valve 1', output=valve_output) ValveToThermostat.create(thermostat=thermostat, valve=valve, mode=ThermostatGroup.Modes.HEATING, priority=0) thermostat_group = ThermostatGroup.get(number=0) # type: ThermostatGroup self.assertEqual(10.0, thermostat_group.threshold_temperature) self.assertEqual(0, OutputToThermostatGroup.select() .where(OutputToThermostatGroup.thermostat_group == thermostat_group) .count()) self._thermostat_controller.save_thermostat_group((ThermostatGroupDTO(id=0, outside_sensor_id=1, pump_delay=30, threshold_temperature=15, switch_to_heating_0=(1, 0), switch_to_heating_1=(2, 100), switch_to_cooling_0=(1, 100)), ['outside_sensor_id', 'pump_delay', 'threshold_temperature', 'switch_to_heating_0', 'switch_to_heating_1', 'switch_to_cooling_0'])) thermostat_group = ThermostatGroup.get(number=0) self.assertEqual(15.0, thermostat_group.threshold_temperature) links = [{'index': link.index, 'value': link.value, 'mode': link.mode, 'output': link.output_id} for link in (OutputToThermostatGroup.select() .where(OutputToThermostatGroup.thermostat_group == thermostat_group))] self.assertEqual(3, len(links)) self.assertIn({'index': 0, 'value': 0, 'mode': 'heating', 'output': 1}, links) self.assertIn({'index': 1, 'value': 100, 'mode': 'heating', 'output': 2}, links) self.assertIn({'index': 0, 'value': 100, 'mode': 'cooling', 'output': 1}, links) new_thermostat_group_dto = ThermostatGroupDTO(id=0, outside_sensor_id=1, pump_delay=60, threshold_temperature=10, switch_to_heating_0=(1, 50), switch_to_cooling_0=(2, 0)) self._thermostat_controller.save_thermostat_group((new_thermostat_group_dto, ['outside_sensor_id', 'pump_delay', 'threshold_temperature', 'switch_to_heating_0', 'switch_to_heating_1', 'switch_to_cooling_0'])) thermostat_group = ThermostatGroup.get(number=0) self.assertEqual(10.0, thermostat_group.threshold_temperature) links = [{'index': link.index, 'value': link.value, 'mode': link.mode, 'output': link.output_id} for link in (OutputToThermostatGroup.select() .where(OutputToThermostatGroup.thermostat_group == thermostat_group))] self.assertEqual(2, len(links)) self.assertIn({'index': 0, 'value': 50, 'mode': 'heating', 'output': 1}, links) self.assertIn({'index': 0, 'value': 0, 'mode': 'cooling', 'output': 2}, links) self.assertEqual(new_thermostat_group_dto, self._thermostat_controller.load_thermostat_group())