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
Example #3
0
 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)
Example #5
0
    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')