def _sync_orm(self): if self._sync_running: logger.info('ORM sync (PulseCounter): Already running') return False self._sync_running = True start = time.time() logger.info('ORM sync (PulseCounter)') try: for pulse_counter_dto in self._master_controller.load_pulse_counters(): pulse_counter_id = pulse_counter_dto.id pulse_counter = PulseCounter.get_or_none(number=pulse_counter_id) if pulse_counter is None: pulse_counter = PulseCounter(number=pulse_counter_id, name='PulseCounter {0}'.format(pulse_counter_id), source='master', persistent=False) pulse_counter.save() duration = time.time() - start logger.info('ORM sync (PulseCounter): completed after {0:.1f}s'.format(duration)) except CommunicationTimedOutException as ex: logger.error('ORM sync (PulseCounter): Failed: {0}'.format(ex)) except Exception: logger.exception('ORM sync (PulseCounter): Failed') finally: self._sync_running = False return True
def set_amount_of_pulse_counters(self, amount): # type: (int) -> int _ = self # This does not make a lot of sense in an ORM driven implementation, but is for legacy purposes. # The legacy implementation heavily depends on the number (legacy id) and the fact that there should be no # gaps between them. If there are gaps, legacy upstream code will most likely break. # TODO: Fix legacy implementation once the upstream can manage this better amount_of_master_pulse_counters = PulseCounter.select().where(PulseCounter.source == 'master').count() if amount < amount_of_master_pulse_counters: raise ValueError('Amount should be >= {0}'.format(amount_of_master_pulse_counters)) # Assume amount is 27: # - This means n master driven PulseCounters # - This means 27-n gateway driven PulseCounters # The `number` field will contain 0-(n-1) (zero-based counting), this means that any # number above or equal to the amount can be removed (>= n) PulseCounter.delete().where(PulseCounter.number >= amount).execute() for number in range(amount_of_master_pulse_counters, amount): pulse_counter = PulseCounter.get_or_none(number=number) if pulse_counter is None: pulse_counter = PulseCounter(number=number, name='PulseCounter {0}'.format(number), source='gateway', persistent=False) pulse_counter.save() return amount
def dto_to_orm( pulse_counter_dto): # type: (PulseCounterDTO) -> PulseCounter pulse_counter = PulseCounter.get_or_none(number=pulse_counter_dto.id) if pulse_counter is None: pulse_counter = PulseCounter(number=pulse_counter_dto.id, name='', source='gateway', persistent=False) if 'name' in pulse_counter_dto.loaded_fields: pulse_counter.name = pulse_counter_dto.name if 'persistent' in pulse_counter_dto.loaded_fields: pulse_counter.persistent = pulse_counter_dto.persistent return pulse_counter
def save_pulse_counters(self, pulse_counters): # type: (List[PulseCounterDTO]) -> None pulse_counters_to_save = [] for pulse_counter_dto in pulse_counters: pulse_counter = PulseCounter.get_or_none(number=pulse_counter_dto.id) # type: PulseCounter if pulse_counter is None: raise DoesNotExist('A PulseCounter with id {0} could not be found'.format(pulse_counter_dto.id)) if pulse_counter.source == 'master': # Only master pulse counters will be passed to the MasterController batch save pulse_counters_to_save.append(pulse_counter_dto) if 'name' in pulse_counter_dto.loaded_fields: pulse_counter.name = pulse_counter_dto.name elif pulse_counter.source == 'gateway': pulse_counter = PulseCounterMapper.dto_to_orm(pulse_counter_dto) else: logger.warning('Trying to save a PulseCounter with unknown source {0}'.format(pulse_counter.source)) continue if 'room' in pulse_counter_dto.loaded_fields: if pulse_counter_dto.room is None: pulse_counter.room = None elif 0 <= pulse_counter_dto.room <= 100: pulse_counter.room, _ = Room.get_or_create(number=pulse_counter_dto.room) pulse_counter.save() self._master_controller.save_pulse_counters(pulse_counters_to_save)
def _migrate(cls, master_controller=INJECTED ): # type: (MasterClassicController) -> None # Core(+) platforms never had non-ORM rooms if Platform.get_platform() in Platform.CoreTypes: return # Import legacy code @Inject def _load_eeprom_extension(eeprom_extension=INJECTED): # type: (EepromExtension) -> EepromExtension return eeprom_extension eext_controller = _load_eeprom_extension() from master.classic.eeprom_models import (OutputConfiguration, InputConfiguration, SensorConfiguration, ShutterConfiguration, ShutterGroupConfiguration, PulseCounterConfiguration) rooms = {} # type: Dict[int, Room] floors = {} # type: Dict[int, Floor] # Rooms and floors logger.info('* Rooms & floors') for room_id in range(100): try: RoomsMigrator._get_or_create_room(eext_controller, room_id, rooms, floors, skip_empty=True) except Exception: logger.exception('Could not migrate single RoomConfiguration') # Main objects for eeprom_model, orm_model, filter_ in [ (OutputConfiguration, Output, lambda o: True), (InputConfiguration, Input, lambda i: i.module_type in ['i', 'I']), (SensorConfiguration, Sensor, lambda s: True), (ShutterConfiguration, Shutter, lambda s: True), (ShutterGroupConfiguration, ShutterGroup, lambda s: True) ]: logger.info('* {0}s'.format(eeprom_model.__name__)) try: for classic_orm in master_controller._eeprom_controller.read_all( eeprom_model): try: object_id = classic_orm.id if object_id is None: continue if not filter_(classic_orm): RoomsMigrator._delete_eext_fields( eext_controller, eeprom_model.__name__, object_id, ['room']) continue try: room_id = int( RoomsMigrator._read_eext_fields( eext_controller, eeprom_model.__name__, object_id, ['room']).get('room', 255)) except ValueError: room_id = 255 object_orm, _ = orm_model.get_or_create( number=object_id) # type: ignore if room_id == 255: object_orm.room = None else: object_orm.room = RoomsMigrator._get_or_create_room( eext_controller, room_id, rooms, floors) object_orm.save() RoomsMigrator._delete_eext_fields( eext_controller, eeprom_model.__name__, object_id, ['room']) except Exception: logger.exception('Could not migrate single {0}'.format( eeprom_model.__name__)) except Exception: logger.exception('Could not migrate {0}s'.format( eeprom_model.__name__)) # PulseCounters pulse_counter = None # type: Optional[PulseCounter] # - Master try: logger.info('* PulseCounters (master)') for pulse_counter_classic_orm in master_controller._eeprom_controller.read_all( PulseCounterConfiguration): try: pulse_counter_id = pulse_counter_classic_orm.id try: room_id = int( RoomsMigrator._read_eext_fields( eext_controller, 'PulseCounterConfiguration', pulse_counter_id, ['room']).get('room', 255)) except ValueError: room_id = 255 pulse_counter = PulseCounter.get_or_none( number=pulse_counter_id) if pulse_counter is None: pulse_counter = PulseCounter( number=pulse_counter_id, name=pulse_counter_classic_orm.name, persistent=False, source=u'master') else: pulse_counter.name = pulse_counter_classic_orm.name pulse_counter.persistent = False pulse_counter.source = u'master' if room_id == 255: pulse_counter.room = None else: pulse_counter.room = RoomsMigrator._get_or_create_room( eext_controller, room_id, rooms, floors) pulse_counter.save() RoomsMigrator._delete_eext_fields( eext_controller, 'PulseCounterConfiguration', pulse_counter_id, ['room']) except Exception: logger.exception( 'Could not migrate classic master PulseCounter') except Exception: logger.exception('Could not migrate classic master PulseCounters') # - Old SQLite3 old_sqlite_db = constants.get_pulse_counter_database_file() if os.path.exists(old_sqlite_db): try: logger.info('* PulseCounters (gateway)') import sqlite3 connection = sqlite3.connect( old_sqlite_db, detect_types=sqlite3.PARSE_DECLTYPES, check_same_thread=False, isolation_level=None) cursor = connection.cursor() for row in cursor.execute( 'SELECT id, name, room, persistent FROM pulse_counters ORDER BY id ASC;' ): try: pulse_counter_id = int(row[0]) room_id = int(row[2]) pulse_counter = PulseCounter.get_or_none( number=pulse_counter_id) if pulse_counter is None: pulse_counter = PulseCounter( number=pulse_counter_id, name=str(row[1]), persistent=row[3] >= 1, source=u'gateway') else: pulse_counter.name = str(row[1]) pulse_counter.persistent = row[3] >= 1 pulse_counter.source = u'gateway' if room_id == 255: pulse_counter.room = None else: pulse_counter.room = RoomsMigrator._get_or_create_room( eext_controller, room_id, rooms, floors) pulse_counter.save() except Exception: logger.exception( 'Could not migratie gateway PulseCounter') os.rename(old_sqlite_db, '{0}.bak'.format(old_sqlite_db)) except Exception: logger.exception('Could not migrate gateway PulseCounters')