def test_orm_to_dto_mapping(self): controller = GatewayThermostatMappingTests._create_controller() group, _ = ThermostatGroup.get_or_create( number=0, name='Default', on=True, mode=ThermostatGroup.Modes.HEATING) thermostat = Thermostat( number=10, start=0, # 0 is on a thursday name='thermostat', thermostat_group=group) thermostat.save() for i in range(7): day_schedule = DaySchedule(index=i, content='{}', mode='heating') day_schedule.thermostat = thermostat day_schedule.save() heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) dto = heating_thermostats[0] # type: ThermostatDTO self.assertEqual( ThermostatDTO(id=10, name='thermostat', setp3=14.0, setp4=14.0, setp5=14.0, sensor=None, pid_p=120.0, pid_i=0.0, pid_d=0.0, room=None, permanent_manual=True), dto) day_schedule = thermostat.heating_schedules()[0] # type: DaySchedule day_schedule.schedule_data = { 0: 5.0, 120: 5.5, # 120 and 1200 are selected because 120 < 1200, 1200: 6.0, # but str(120) > str(1200) 3600: 6.5, 7500: 7.0 } day_schedule.save() heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) dto = heating_thermostats[0] # type: ThermostatDTO self.assertEqual( ThermostatScheduleDTO(temp_night=5.0, temp_day_1=5.5, temp_day_2=6.5, start_day_1='00:02', end_day_1='00:20', start_day_2='01:00', end_day_2='02:05'), dto.auto_thu)
def test_load(self): controller = GatewayThermostatMappingTests._create_controller() group, _ = ThermostatGroup.get_or_create( number=0, name='Default', on=True, mode=ThermostatGroup.Modes.HEATING) thermostat = Thermostat(number=10, start=0, name='thermostat', thermostat_group=group) thermostat.save() for i in range(7): day_schedule = DaySchedule(index=i, content='{}', mode='heating') day_schedule.thermostat = thermostat day_schedule.save() day_schedule = DaySchedule(index=i, content='{}', mode='cooling') day_schedule.thermostat = thermostat day_schedule.save() # Validate load calls heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) cooling_thermostats = controller.load_cooling_thermostats() self.assertEqual(1, len(cooling_thermostats)) heating_thermostat_dto = heating_thermostats[0] cooling_thermostat_dto = cooling_thermostats[0] self.assertEqual(heating_thermostat_dto, controller.load_heating_thermostat(10)) self.assertEqual(cooling_thermostat_dto, controller.load_cooling_thermostat(10)) # Validate contents # Presets have a different default value for cooling vs heating heating_thermostat_dto.setp3 = cooling_thermostat_dto.setp3 heating_thermostat_dto.setp4 = cooling_thermostat_dto.setp4 heating_thermostat_dto.setp5 = cooling_thermostat_dto.setp5 self.assertEqual(heating_thermostat_dto, cooling_thermostat_dto) self.assertEqual('thermostat', heating_thermostat_dto.name) self.assertEqual(thermostat.number, heating_thermostat_dto.id)
def test_load(self): controller = GatewayThermostatMappingTests._create_controller() group, _ = ThermostatGroup.get_or_create( number=0, name='Default', on=True, mode=ThermostatGroup.Modes.HEATING) thermostat = Thermostat(number=10, start=0, name='thermostat', thermostat_group=group) thermostat.save() # Validate load calls heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) cooling_thermostats = controller.load_cooling_thermostats() self.assertEqual(1, len(cooling_thermostats)) heating_thermostat_dto = heating_thermostats[0] cooling_thermostat_dto = cooling_thermostats[0] self.assertEqual(heating_thermostat_dto, controller.load_heating_thermostat(10)) self.assertEqual(cooling_thermostat_dto, controller.load_cooling_thermostat(10)) # Validate contents # Presets & schedules have a different default value for cooling vs heating heating_thermostat_dto.setp3 = cooling_thermostat_dto.setp3 heating_thermostat_dto.setp4 = cooling_thermostat_dto.setp4 heating_thermostat_dto.setp5 = cooling_thermostat_dto.setp5 for day in ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun']: setattr(heating_thermostat_dto, 'auto_{0}'.format(day), getattr(cooling_thermostat_dto, 'auto_{0}'.format(day))) self.assertEqual(heating_thermostat_dto, cooling_thermostat_dto) self.assertEqual('thermostat', heating_thermostat_dto.name) self.assertEqual(thermostat.number, heating_thermostat_dto.id)
def test_save(self): temperatures = {} def _get_temperature(sensor_id): return temperatures[sensor_id] controller = GatewayThermostatMappingTests._create_controller( get_sensor_temperature_status=_get_temperature) room = Room(number=5) room.save() thermostat_group = ThermostatGroup(number=0, name='global') thermostat_group.save() thermostat = Thermostat( number=10, start=0, # 0 is on a thursday name='thermostat', thermostat_group=thermostat_group) thermostat.save() heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) dto = heating_thermostats[0] # type: ThermostatDTO default_schedule_dto = ThermostatScheduleDTO(temp_day_1=20.0, start_day_1='07:00', end_day_1='09:00', temp_day_2=21.0, start_day_2='17:00', end_day_2='22:00', temp_night=16.0) Sensor.create(number=15) dto.room = 5 dto.sensor = 15 dto.output0 = 5 dto.name = 'changed' dto.auto_thu = ThermostatScheduleDTO(temp_night=10, temp_day_1=15, temp_day_2=30, start_day_1='08:00', end_day_1='10:30', start_day_2='16:00', end_day_2='18:45') temperatures[15] = 5.0 controller.save_heating_thermostats([dto]) heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) dto = heating_thermostats[0] # type: ThermostatDTO self.assertEqual( ThermostatDTO(id=10, name='changed', setp3=16.0, setp4=15.0, setp5=22.0, sensor=15, pid_p=120.0, pid_i=0.0, pid_d=0.0, room=5, output0=5, permanent_manual=True, auto_mon=default_schedule_dto, auto_tue=default_schedule_dto, auto_wed=default_schedule_dto, auto_thu=ThermostatScheduleDTO(temp_night=10.0, temp_day_1=15.0, temp_day_2=30.0, start_day_1='08:00', end_day_1='10:30', start_day_2='16:00', end_day_2='18:45'), auto_fri=default_schedule_dto, auto_sat=default_schedule_dto, auto_sun=default_schedule_dto), dto)
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_save(self): temperatures = {} def _get_temperature(sensor_id): return temperatures[sensor_id] controller = GatewayThermostatMappingTests._create_controller( get_sensor_temperature_status=_get_temperature) thermostat_group = ThermostatGroup(number=0, name='global') thermostat_group.save() thermostat = Thermostat( number=10, start=0, # 0 is on a thursday name='thermostat', thermostat_group=thermostat_group) thermostat.save() for i in range(7): day_schedule = DaySchedule(index=i, content='{}', mode='heating') day_schedule.thermostat = thermostat day_schedule.save() heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) dto = heating_thermostats[0] # type: ThermostatDTO Sensor.create(number=15) dto.room = 5 # This field won't be saved dto.sensor = 15 dto.output0 = 5 dto.name = 'changed' dto.auto_thu = ThermostatScheduleDTO(temp_night=10, temp_day_1=15, temp_day_2=30, start_day_1='08:00', end_day_1='10:30', start_day_2='16:00', end_day_2='18:45') temperatures[15] = 5.0 controller.save_heating_thermostats([ (dto, ['sensor', 'output0', 'name', 'auto_thu']) ]) heating_thermostats = controller.load_heating_thermostats() self.assertEqual(1, len(heating_thermostats)) dto = heating_thermostats[0] # type: ThermostatDTO self.assertEqual( ThermostatDTO( id=10, name='changed', setp3=14.0, setp4=14.0, setp5=14.0, sensor=15, pid_p=120.0, pid_i=0.0, pid_d=0.0, room=None, # Unchanged output0=5, permanent_manual=True, auto_thu=ThermostatScheduleDTO(temp_night=10.0, temp_day_1=15.0, temp_day_2=30.0, start_day_1='08:00', end_day_1='10:30', start_day_2='16:00', end_day_2='18:45')), dto)