Ejemplo n.º 1
0
    def softwareUpdateInProgress(self, value):
        try:
            self.__softwareUpdateInProgress = bool(value)
            if (bool(value)):
                # Announce
                WebSocketUtil.emit(wsEmitQueue=self.wsEmitQueue,
                                   event='update',
                                   id=self.chargerName,
                                   data={
                                       "restartRequired":
                                       self.__restartRequired,
                                       'softwareUpdateInProgress':
                                       self.__softwareUpdateInProgress,
                                       "upSince":
                                       self.upSinceDatetimeStr,
                                       "clientsConnected":
                                       len(self.connectedClients)
                                   },
                                   namespace='/system_status',
                                   public=False)

        except ValueError:
            self.___logger.warning(
                "@softwareUpdateInProgress.setter - Value {} could not be interpreted as bool"
                .format(value),
                exc_info=True)
Ejemplo n.º 2
0
    def connect():
        global oppleoLogger, oppleoConfig, threadLock, wsClientCnt
        with threadLock:
            wsClientCnt += 1
            if request.sid not in oppleoConfig.connectedClients.keys():
                oppleoConfig.connectedClients[request.sid] = {
                    'sid': request.sid,
                    'auth': True if (current_user.is_authenticated) else False,
                    'stats': 'connected'
                }
        oppleoLogger.debug('socketio.connect sid: {} wsClientCnt: {} connectedClients:{}'.format( \
                        request.sid, \
                        wsClientCnt, \
                        oppleoConfig.connectedClients \
                        )
                    )

        WebSocketUtil.emit(wsEmitQueue=oppleoConfig.wsEmitQueue,
                           event='update',
                           id=oppleoConfig.chargerName,
                           data={
                               "restartRequired":
                               (oppleoConfig.restartRequired
                                or oppleoSystemConfig.restartRequired),
                               "upSince":
                               oppleoConfig.upSinceDatetimeStr,
                               "clientsConnected":
                               len(oppleoConfig.connectedClients)
                           },
                           namespace='/system_status',
                           public=False,
                           room=request.sid)
Ejemplo n.º 3
0
    def handle(self):
        self.logger.debug("Start measure %s" % self.energy_device_id)

        if not self.enabled:
            self.energyModbusReader = None
            self.logger.debug("Skip measure {} (enabled=False)".format(self.energy_device_id))
            return

        if self.energyModbusReader is None and self.enabled:
            # Try to create it
            self.createEnergyModbusReader()
            if self.energyModbusReader is None:
                # still nothing
                self.logger.warn("Cannot read energy device. No workinig modbus reader for {}".format(self.energy_device_id))
                return

        data = self.energyModbusReader.getMeasurementValue()

        self.logger.debug('Measurement returned %s' % str(data))
        device_measurement = EnergyDeviceMeasureModel()
        device_measurement.set(data)

        self.logger.debug('New measurement values: %s, %s, %s' % (device_measurement.id, device_measurement.kw_total,
                                                            device_measurement.created_at))

        last_save_measurement = EnergyDeviceMeasureModel().get_last_saved(self.energy_device_id)

        if last_save_measurement is None:
            self.logger.info('No saved measurement found, is this the first run for device %s?' % self.energy_device_id)
        else:
            self.logger.debug(
                'Last save measurement values: %s, %s, %s' % (last_save_measurement.id, last_save_measurement.kw_total,
                                                            last_save_measurement.created_at))

        if last_save_measurement is None or self.is_a_value_changed(last_save_measurement, device_measurement) \
                or self.is_measurement_older_than_1hour(last_save_measurement, device_measurement):
            self.logger.debug('Measurement has changed or old one is older than 1 hour, saving it to db (if env=Production)')
            device_measurement.save()
            self.logger.debug("value saved %s %s %s" %
                    (device_measurement.energy_device_id, device_measurement.id, device_measurement.created_at))
            if self.appSocketIO is not None:
                # Emit as web socket update
                self.counter += 1
                self.logger.debug(f'Queue msg {self.counter} to be send via websocket ...{device_measurement.to_str()}')
                # Info heeft actuele kWh meter gegevens, geen laadpas info, dus public
                WebSocketUtil.emit(
                        wsEmitQueue=oppleoConfig.wsEmitQueue,
                        event='status_update', 
                        data=device_measurement.to_str(), 
                        namespace='/usage',
                        public=True
                    )

            # Callbacks to notify update
            self.callback(device_measurement)
        else:
            self.logger.debug('Not saving new measurement, no significant change and not older than 1 hour')
Ejemplo n.º 4
0
    def handle_charging(self, evse_state):
        if evse_state == EvseState.EVSE_STATE_CHARGING:
            # self.logger.debug("Device is currently charging")
            if not self.is_status_charging:
                # Switching to charging
                """
                 AUTO CHARGE SESSION
                  Automatic detect new charge sessions. When the car is present, it keeps using limited amounts of
                  energy. (Tesla Model 3 0.2kWh each 1:23h). If this usage has not occurred, and now the EVSE
                  goes to charging again, the car probably has gone away and returned.
                """
                self.handle_auto_session()

                self.is_status_charging = True
                if self.appSocketIO is not None:
                    self.logger.debug(
                        '.handle_charging() - Send msg charge_session_status_update via websocket ...{}'
                        .format(evse_state))
                    WebSocketUtil.emit(wsEmitQueue=oppleoConfig.wsEmitQueue,
                                       event='charge_session_status_update',
                                       status=evse_state,
                                       id=oppleoConfig.chargerName,
                                       namespace='/charge_session',
                                       public=True)
            self.logger.debug(
                '.handle_charging() - Start charging light pulse')
            oppleoConfig.rgblcThread.charging = True

        else:
            # self.logger.debug("Not charging")
            # Not charging. If it was charging, set light back to previous (before charging) light
            if self.is_status_charging:
                self.is_status_charging = False
                self.logger.debug(".handle_charging() - Charging is stopped")
                if self.appSocketIO is not None:
                    self.logger.debug(
                        '.handle_charging() - Send msg charge_session_status_update via websocket ...'
                        .format(evse_state))
                    WebSocketUtil.emit(
                        wsEmitQueue=oppleoConfig.wsEmitQueue,
                        event='charge_session_status_update',
                        # INACTIVE IS ALSO CONNECTED
                        status=EvseState.EVSE_STATE_CONNECTED,
                        id=oppleoConfig.chargerName,
                        namespace='/charge_session',
                        public=True)

        if oppleoConfig.rgblcThread.charging != (
                evse_state == EvseState.EVSE_STATE_CHARGING):
            # Only the change
            self.logger.debug(
                '.handle_charging() - Charging light pulse to {}'.format(
                    str(evse_state == EvseState.EVSE_STATE_CHARGING)))
            oppleoConfig.rgblcThread.charging = (
                evse_state == EvseState.EVSE_STATE_CHARGING)
Ejemplo n.º 5
0
Archivo: Evse.py Proyecto: ilseh/Oppleo
    def switch_off(self):
        global oppleoConfig

        self.evse.switch_off()
        WebSocketUtil.emit(
                wsEmitQueue=oppleoConfig.wsEmitQueue,
                event='evse_disabled', 
                id=oppleoConfig.chargerName,
                namespace='/evse_status',
                public=True
            )
Ejemplo n.º 6
0
    def requestVehicleWakeup(self):
        with self.__threadLock:
            self.__requestVehicleWakeupNow = True

        # Send wakeup request notification
        WebSocketUtil.emit(wsEmitQueue=oppleoConfig.wsEmitQueue,
                           event='vehicle_status_update',
                           id=oppleoConfig.chargerName,
                           data={
                               'request': 'wakeupVehicle',
                               'result': HTTP_CODE_202_ACCEPTED,
                               'msg': 'Waking up vehicle'
                           },
                           namespace='/charge_session',
                           public=False)
Ejemplo n.º 7
0
    def clearVehicleWakeupRequest(self,
                                  resultCode: int = 500,
                                  msg: str = 'Unknown'):
        with self.__threadLock:
            self.__requestVehicleWakeupNow = False

        # Send wakeup result notification
        WebSocketUtil.emit(wsEmitQueue=oppleoConfig.wsEmitQueue,
                           event='vehicle_status_update',
                           id=oppleoConfig.chargerName,
                           data={
                               'request': 'wakeupVehicle',
                               'result': resultCode,
                               'msg': msg
                           },
                           namespace='/charge_session',
                           public=False)
Ejemplo n.º 8
0
    def end_charge_session(self, charge_session, detect=False):
        global oppleoConfig

        charge_session.end_value = 0

        start_value = 0
        if (oppleoConfig.energyDevice is not None
                and oppleoConfig.energyDevice.enabled
                and oppleoConfig.energyDevice.energyModbusReader is not None):
            charge_session.end_value = oppleoConfig.energyDevice.energyModbusReader.getTotalKWHHValue(
            )
            self.logger.debug(
                ".end_charge_session() - end_value from energyModbusReader: {}"
                .format(charge_session.end_value))

        if detect:
            # end_time is the time the kWh was updated to this value, and the current went to 0
            end_time = EnergyDeviceMeasureModel.get_time_of_kwh(
                charge_session.energy_device_id, charge_session.end_value)
            charge_session.end_time = end_time if end_time is not None else datetime.now(
            )
            self.logger.debug(
                '.end_charge_session() - Detected end time is {}'.format(
                    charge_session.end_time.strftime("%d/%m/%Y, %H:%M:%S")))
        else:
            charge_session.end_time = datetime.now()
        charge_session.total_energy = charge_session.end_value - charge_session.start_value
        charge_session.total_price = round(
            charge_session.total_energy * charge_session.tariff * 100) / 100
        charge_session.save()
        # Emit websocket update
        if self.appSocketIO is not None:
            self.logger.debug(
                '.end_charge_session() - Send msg charge_session_ended via websocket ...'
                .format(charge_session.to_str))
            WebSocketUtil.emit(wsEmitQueue=oppleoConfig.wsEmitQueue,
                               event='charge_session_ended',
                               id=oppleoConfig.chargerName,
                               data=charge_session.to_str(),
                               namespace='/charge_session',
                               public=False)
        # Stop the VehicleChargeStatusMonitorThread
        if oppleoConfig.vcsmThread is not None:
            oppleoConfig.vcsmThread.stop()
            oppleoConfig.vcsmThread = None
Ejemplo n.º 9
0
    def __purgeBackupSmbShare__(self, n: int = 99):
        self.logger.debug('__purgeBackupSmbShare__() n={}'.format(n))
        if n >= 99:
            self.logger.debug('__purgeBackupSmbShare__() no purge')
            return

        smb_client = SMBClient(
            serverOrIP=self.oppleoConfig.smbBackupServerNameOrIPAddress,
            username=self.oppleoConfig.smbBackupUsername,
            password=self.oppleoConfig.smbBackupPassword,
            service_name=self.oppleoConfig.smbBackupServiceName,
        )

        smb_client.connect()

        smbBackups = self.listSMBBackups()
        if not smbBackups['success']:
            self.logger.debug(
                '__purgeBackupSmbShare__() no purge, could not get file list - {}'
                .format(smbBackups['reason']))
            return
        # Sorted and filtered - now limit and get the filenames
        purgelist = []
        for file in smbBackups['files'][0:(-1 * n)]:
            purgelist.append(file['filename'])
        self.logger.debug(
            '__purgeBackupSmbShare__() purging {} of {} backups'.format(
                str(len(purgelist)), str(len(smbBackups['files']))))
        result = smb_client.deleteFiles(
            service_name=self.oppleoConfig.smbBackupServiceName,
            remote_path=smbBackups['directory'],
            files=purgelist)
        smb_client.close()
        # Send message to front end
        WebSocketUtil.emit(wsEmitQueue=self.oppleoConfig.wsEmitQueue,
                           event='os_backup_purged',
                           id=self.oppleoConfig.chargerName,
                           data=smbBackups['files'][0:(-1 * n)],
                           namespace='/backup',
                           public=False)
        return result
Ejemplo n.º 10
0
    def restartRequired(self, value):
        try: 
            self.__restartRequired = bool(value)
            if (bool(value) and self.wsEmitQueue is not None and self.chargerName is not None):
                # Announce
                WebSocketUtil.emit(
                        wsEmitQueue=self.wsEmitQueue,
                        event='update', 
                        id=self.chargerName,
                        data={
                            "restartRequired"   : self.__restartRequired
#                            "restartRequired"   : self.__restartRequired,
#                            "upSince"           : self.upSinceDatetimeStr,
#                            "clientsConnected"  : len(self.connectedClients)
                        },
                        namespace='/system_status',
                        public=False
                    )

        except ValueError:
            self.__logger.warning("Value {} could not be interpreted as bool".format(value), exc_info=True)
Ejemplo n.º 11
0
 def energyUpdate(self, device_measurement):
     self.logger.debug('.energyUpdate() callback...')
     # Open charge session for this energy device?
     with self.threadLock:
         open_charge_session_for_device = \
             ChargeSessionModel.get_open_charge_session_for_device(
                     device_measurement.energy_device_id
             )
         if open_charge_session_for_device != None:
             self.logger.debug(
                 '.energyUpdate() open charge session, updating usage. device_measurement {}, open_charge_session_for_device {}'
                 .format(str(device_measurement.to_str()),
                         str(open_charge_session_for_device.to_str())))
             # Update session usage
             open_charge_session_for_device.end_value = device_measurement.kw_total
             self.logger.debug('.energyUpdate() end_value to %s...' %
                               open_charge_session_for_device.end_value)
             open_charge_session_for_device.total_energy = \
                 round((open_charge_session_for_device.end_value - open_charge_session_for_device.start_value) *10) /10
             self.logger.debug('.energyUpdate() total_energy to %s...' %
                               open_charge_session_for_device.total_energy)
             open_charge_session_for_device.total_price = \
                 round(open_charge_session_for_device.total_energy * open_charge_session_for_device.tariff * 100) /100
             self.logger.debug('.energyUpdate() total_price to %s...' %
                               open_charge_session_for_device.total_price)
             open_charge_session_for_device.save()
             # Emit changes via web socket
             if self.appSocketIO is not None and oppleoConfig.app is not None:
                 self.counter += 1
                 self.logger.debug(
                     '.energyUpdate() Send msg {} for charge_session_data_update via websocket...'
                     .format(self.counter))
                 # Emit only to authenticated users, not public
                 WebSocketUtil.emit(
                     wsEmitQueue=oppleoConfig.wsEmitQueue,
                     event='charge_session_data_update',
                     id=oppleoConfig.chargerName,
                     data=open_charge_session_for_device.to_str(),
                     namespace='/charge_session',
                     public=False)
Ejemplo n.º 12
0
Archivo: Evse.py Proyecto: ilseh/Oppleo
    def switch_on(self):
        global oppleoConfig

        if not oppleoConfig.offpeakEnabled or \
                    self.isOffPeak or \
                    oppleoConfig.allowPeakOnePeriod:
            self.logger.debug('EVSE switched ON (OffPeakEnabled:{}, offPeak={}, PeakAllowed={}).'.format( \
                            oppleoConfig.offpeakEnabled, \
                            self.isOffPeak, \
                            oppleoConfig.allowPeakOnePeriod
                            )
                        )
            self.evse.switch_on()
            WebSocketUtil.emit(
                    wsEmitQueue=oppleoConfig.wsEmitQueue,
                    event='evse_enabled', 
                    id=oppleoConfig.chargerName,
                    namespace='/evse_status',
                    public=True
                )

        else:
            self.logger.debug('Evse NOT switched on. Waiting for Off Peak hours')
Ejemplo n.º 13
0
    def purgeLocalBackups(self, n: int = 99):
        self.logger.debug('purgeLocalBackups() n={}'.format(n))
        if n >= 99:
            self.logger.debug('purgeLocalBackups() no purge')
            return

        localBackups = self.listLocalBackups()
        # note: the list is sorted
        purgelist = localBackups['files'][0:(-1 * n)]
        self.logger.debug(
            'purgeLocalBackups() purging {} of {} backups'.format(
                str(len(purgelist)), str(len(localBackups['files']))))

        for file in purgelist:
            filename = os.path.join(localBackups['directory'],
                                    file['filename'])
            os.remove(filename)

        WebSocketUtil.emit(wsEmitQueue=self.oppleoConfig.wsEmitQueue,
                           event='local_backup_purged',
                           id=self.oppleoConfig.chargerName,
                           data=localBackups['files'][0:(-1 * n)],
                           namespace='/backup',
                           public=False)
Ejemplo n.º 14
0
    def start_charge_session(self,
                             rfid: str,
                             trigger=ChargeSessionModel.TRIGGER_RFID,
                             condense=False):
        global oppleoConfig

        self.logger.debug(
            ".start_charge_session() new charging session for rfid {}".format(
                rfid))

        # Optimize: maybe get this from the latest db value rather than from the energy meter directly

        start_value = 0
        if (oppleoConfig.energyDevice is not None
                and oppleoConfig.energyDevice.enabled
                and oppleoConfig.energyDevice.energyModbusReader is not None):
            start_value = oppleoConfig.energyDevice.energyModbusReader.getTotalKWHHValue(
            )
            self.logger.debug(
                ".start_charge_session() start_value from energyModbusReader: {}"
                .format(start_value))

        data_for_session = {
            "rfid": rfid,
            "energy_device_id": self.device,
            "start_value": start_value,
            "tariff": ChargerConfigModel.get_config().charger_tariff,
            "end_value": start_value,
            "total_energy": 0,
            "total_price": 0,
            "trigger": trigger
        }
        charge_session = ChargeSessionModel()
        charge_session.set(data_for_session)
        charge_session.save()
        self.logger.info(
            '.start_charge_session() New charge session started with {}'.
            format(charge_session.id))

        rfidObj = RfidModel.get_one(rfid)
        if rfidObj.vehicle_make.upper() == "TESLA" and rfidObj.get_odometer:
            # Try to add odometer
            self.logger.debug(
                '.start_charge_session() Update odometer for this Tesla')
            self.save_tesla_values_in_thread(
                charge_session_id=charge_session.id, condense=condense)
        # Emit websocket update
        if self.appSocketIO is not None:
            self.logger.debug(
                '.start_charge_session() Send msg charge_session_started via websocket ...{}'
                .format(charge_session.to_str))
            WebSocketUtil.emit(wsEmitQueue=oppleoConfig.wsEmitQueue,
                               event='charge_session_started',
                               id=oppleoConfig.chargerName,
                               data=charge_session.to_str(),
                               namespace='/charge_session',
                               public=False)
        # Start the VehicleChargeStatusMonitorThread
        oppleoConfig.vcsmThread = VehicleChargeStatusMonitorThread()
        oppleoConfig.vcsmThread.rfid = rfid
        oppleoConfig.vcsmThread.start()
Ejemplo n.º 15
0
    def monitor(self):
        """
        Off peak hours
            If the EVSE is enabled during Peak hours, and the config is set to Off Peak, the EVSE is disabled untill the
            Off Peak hours start.
            Detecting Off Peak is database intensive. Checking if EVSE status has changed not.
                Quickly detect changed EVSE conditions - react when a session is started.
                Take time to see if Off Peak time period is entered

        Working
            Check for changed EVSE state every second, by quickly asking the EVSE Thread.
            Check for Off Peak every 5 minutes. 
            -   If a session is active, off peak, and the EVSE is disabled, (re-)enable the EVSE (and possibly wake 
                car for charging), oh, and reset any 'over-ride off peak for once' authorizations
            -   If Peak and reader is enabled, disable the EVSE, warn through push message (prowl)?
            Allow overriding off-peak for one period.
            Check only once per 1 or 5 minutes, to prevent database overload and bad rfid response 
        """
        changeEvseStatusCheckLastRun = 0
        offPeakWindowCheckLastRun = 0
        ohm = OffPeakHoursModel()
        evse = Evse()
        while not self.stop_event.is_set():

            try:
                """ 
                Off Peak Window Change check
                """
                if (time.time() *
                        1000.0) > (offPeakWindowCheckLastRun +
                                   (self.offPeakWindowCheckInterval * 1000.0)):
                    # Time to determine if it is Off Peak again
                    wasOffPeak = evse.isOffPeak
                    evse.isOffPeak = ohm.is_off_peak_now()
                    if (wasOffPeak != evse.isOffPeak):
                        # Send change notification
                        WebSocketUtil.emit(
                            wsEmitQueue=oppleoConfig.wsEmitQueue,
                            event='off_peak_status_update',
                            id=oppleoConfig.chargerName,
                            data={
                                'isOffPeak':
                                evse.isOffPeak,
                                'offPeakEnabled':
                                oppleoConfig.offpeakEnabled,
                                'peakAllowOnePeriod':
                                oppleoConfig.allowPeakOnePeriod
                            },
                            namespace='/charge_session',
                            public=True)
                    self.logger.debug(
                        'Off Peak Window Change check ... (wasOffPeak:{}, isOffPeak:{})'
                        .format(wasOffPeak, evse.isOffPeak))
                    offPeakWindowCheckLastRun = time.time() * 1000.0
                """ 
                EVSE Status Change check
                """
                if (time.time() * 1000.0) > (
                        changeEvseStatusCheckLastRun +
                    (self.changeEvseStatusCheckInterval * 1000.0)):
                    self.logger.debug('EVSE Status Change check ...')
                    # Time to check if the EVSE should be disabled in Peak or Enabled in Off Peak

                    # When to switch the EVSE off:
                    #    if the EVSE is enabled (off is already off), and
                    #    if it is Peak hours, and OffPeak enabled in settings, and not overridden for one session,
                    #    switch the EVSE off untill the next Off Peak hours
                    if (evse.is_enabled() and \
                            ( not evse.isOffPeak and \
                            oppleoConfig.offpeakEnabled and \
                            not oppleoConfig.allowPeakOnePeriod  \
                            ) \
                    ):
                        self.logger.debug(
                            'Peak hours, EVSE ON and Off Peak enabled (not bypassed). Switching EVSE OFF'
                        )
                        # Switch the EVSE off untill Off Peak hours
                        evse.switch_off()

                    # When to switch the EVSE on:
                    #    if the EVSE is disabled (on is already on), and
                    #    if it is Off Peak hours, or
                    #        if peakHours are not enabled, or
                    #        if PeakAllowed for once,
                    #    and there is an active charge session (don't switch on without)
                    # Clear one-session override
                    if (not evse.is_enabled() and \
                        ( evse.isOffPeak or not oppleoConfig.offpeakEnabled or oppleoConfig.allowPeakOnePeriod) \
                    ):
                        # Only see if charge session exists in the database if the EVSE is enabled Off Peak
                        csm = ChargeSessionModel.get_open_charge_session_for_device(
                            oppleoConfig.chargerName)
                        if csm is not None:
                            # Open charge session, enable the EVSE
                            self.logger.debug(
                                'Off Peak hours, EVSE OFF and Active charge session. Switching EVSE ON'
                            )
                            evse.switch_on()
                    if evse.isOffPeak:
                        with self.threadLock:
                            # Off peak now, reset the one session peak authorization
                            oppleoConfig.allowPeakOnePeriod = False

                    changeEvseStatusCheckLastRun = time.time() * 1000.0
                    pass

                # Sleep for quite a while, and yield for other threads
                self.appSocketIO.sleep(self.sleepInterval)
            except Exception as e:
                self.logger.error("Exception tracking off peak hours",
                                  exc_info=True)

        self.logger.info("Stopping PeakHoursMonitorThread")
Ejemplo n.º 16
0
    def createBackup(self):
        if self.backupInProgress:
            # Skip this backup request, already running one
            self.logger.debug(
                'createBackup() - backup already active. Additional backup aborted.'
            )
            WebSocketUtil.emit(wsEmitQueue=self.oppleoConfig.wsEmitQueue,
                               event='backup_request_ignored',
                               id=self.oppleoConfig.chargerName,
                               data={"reason": 'Backup in progress'},
                               namespace='/backup',
                               public=False)
            return
        self.backupInProgress = True

        try:
            startTime = datetime.now()
            wsData = {"started": startTime.strftime('%Y-%m-%d %H:%M.%S')}

            filesize = 0
            # Announce
            WebSocketUtil.emit(wsEmitQueue=self.oppleoConfig.wsEmitQueue,
                               event='backup_started',
                               id=self.oppleoConfig.chargerName,
                               data=wsData,
                               namespace='/backup',
                               public=False)
            localBackup = self.createLocalBackup(start_time=startTime)
            self.logger.debug(
                'createBackup() - local backup created (success={})'.format(
                    localBackup['success']))

            remoteBackup = None
            if localBackup['success']:
                wsData.update({
                    'localBackupSuccess': True,
                    'filename': localBackup['filename']
                })
                # Purge excess backups
                self.purgeLocalBackups(n=self.oppleoConfig.backupLocalHistory)
                if self.oppleoConfig.osBackupEnabled:
                    self.logger.debug(
                        'createBackup() - offsite backup enabled')
                    # Create offsite backup
                    if (self.oppleoConfig.osBackupType ==
                            self.oppleoConfig.OS_BACKUP_TYPE_SMB):
                        self.logger.debug(
                            'createBackup() - remoteBackup type {}'.format(
                                self.oppleoConfig.OS_BACKUP_TYPE_SMB_STR))
                        wsData.update({
                            'osBackupType':
                            self.oppleoConfig.OS_BACKUP_TYPE_SMB
                        })
                        remoteBackup = self.__storeBackupToSmbShare__(
                            filename=localBackup['filename'],
                            localpath=localBackup['path'])
                        if remoteBackup['success']:
                            # Purge excess SMB backups
                            self.__purgeBackupSmbShare__(
                                n=self.oppleoConfig.osBackupHistory)
                        self.logger.debug(
                            'createBackup() - offsite backup created (success={})'
                            .format(remoteBackup['success']))
                        wsData.update(
                            {'osBackupSuccess': remoteBackup['success']})
                        if not remoteBackup['success']:
                            wsData.update({
                                'osBackupFailedReason':
                                remoteBackup['reason']
                            })
                wsData.update(
                    {'osBackupEnabled': self.oppleoConfig.osBackupEnabled})

                # Get the fileszie
                try:
                    filesize = os.path.getsize(
                        os.path.join(localBackup['path'],
                                     localBackup['filename']))
                    wsData.update({'filesize': filesize})
                except OSError as ose:
                    pass

            timeCompleted = datetime.now()
            wsData.update(
                {'completed': timeCompleted.strftime('%Y-%m-%d %H:%M.%S')})

            wsEvent = 'backup_failed'
            # Announce
            if (localBackup['success']
                    and (not self.oppleoConfig.osBackupEnabled or
                         (self.oppleoConfig.osBackupEnabled
                          and remoteBackup['success']))):
                # Full success
                self.oppleoConfig.backupSuccessTimestamp = startTime
                wsEvent = 'backup_completed'

            WebSocketUtil.emit(wsEmitQueue=self.oppleoConfig.wsEmitQueue,
                               event=wsEvent,
                               id=self.oppleoConfig.chargerName,
                               data=wsData,
                               namespace='/backup',
                               public=False)

            pushMsg = ("Local backup {}{} {}.".format(
                ('(' + formatFilesize(filesize) +
                 ')') if localBackup['success'] else '',
                ' completed' if localBackup['success'] else 'failed',
                timeCompleted.strftime('%A %-d %B %Y, %H:%Mu')))
            pushMsg += (" {}".format(
                "(Offsite backup not enabled)"
                if not self.oppleoConfig.osBackupEnabled else (
                    "Offsite backup (SMB) to //{}/{}{} {}".format(
                        self.oppleoConfig.smbBackupServerNameOrIPAddress, self.
                        oppleoConfig.smbBackupServiceName, self.oppleoConfig.
                        smbBackupRemotePath,
                        'completed.' if remoteBackup['success'] else 'failed!'
                    ) if self.oppleoConfig.osBackupType ==
                    self.oppleoConfig.OS_BACKUP_TYPE_SMB else (
                        "Offsite backup enabled but type ({}) not supported.".
                        format(self.oppleoConfig.osBackupType)))))

            PushMessage.sendMessage(
                "Backup {}".format('completed' if wsEvent ==
                                   'backup_completed' else 'failed'), pushMsg)

        except Exception as e:
            self.logger.debug('createBackup() - Exception {}'.format(str(e)))
        # Signal end of backup
        self.backupInProgress = False
        self.logger.debug('createBackup() - Done')
Ejemplo n.º 17
0
    def monitor(self):
        global oppleoConfig

        self.__logger.debug('monitor()')

        teslaApi = TeslaAPI()

        if self.__rfidTag is None:
            self.__logger.error('monitor() Cannot run Thread for RFID None!')
            return False

        rfidData = RfidModel.get_one(self.__rfidTag)
        if rfidData is None:
            self.__logger.error(
                'monitor() Cannot run Thread. Cannot get data for RFID {}'.
                format(self.__rfidTag))

        monitorInterval = (self.__vehicleMonitorInterval +
                           self.__sleepInterval)

        while not self.__stop_event.is_set():
            if monitorInterval > self.__vehicleMonitorInterval or self.__requestChargeStatusNow or self.__requestVehicleWakeupNow:
                monitorInterval = 0
                with self.__threadLock:
                    self.__requestChargeStatusNow = False
                self.__logger.debug("monitor() loop")
                if len(oppleoConfig.connectedClients
                       ) > 0 and oppleoConfig.vehicleDataOnDashboard:
                    self.__logger.debug(
                        "monitor() connected clients ({})".format(
                            len(oppleoConfig.connectedClients)))
                    # See if something changes (could be added or retracted)

                    if rfidData is None or rfidData.api_access_token is None:
                        # No token? Try once more
                        rfidData = RfidModel.get_one(self.__rfidTag)
                        if rfidData is None or rfidData.api_access_token is None:
                            # Still no token, next While iteration
                            self.__logger.debug(
                                "monitor() no token, continue to next While iteration"
                            )
                            continue

                    # Token, checkout
                    tKey = tokenMediator.checkout(
                        token=rfidData.api_access_token,
                        ref='VehicleStatusMonitorThread: ' + rfidData.rfid,
                        wait=True)
                    self.__logger.debug(
                        "monitor() tokenMediator.checkout returned key {}".
                        format(tKey))

                    if tKey is None:
                        # Checkout failed? Token must not be valid anymore
                        if not tokenMediator.validate(
                                token=rfidData.api_access_token):
                            self.__logger.debug(
                                "monitor() token not valid, continue to next While iteration"
                            )
                            # Make sure we reload the RFID tag data next loop
                            rfidData = None
                            with self.__threadLock:
                                self.__requestChargeStatusNow = False
                            continue

                    UpdateOdometerTeslaUtil.copy_token_from_rfid_model_to_api(
                        rfidData, teslaApi)

                    if not teslaApi.hasValidToken():
                        # Not valid, invalidate and continue
                        tokenMediator.invalidate(
                            token=rfidData.api_access_token,
                            key=tKey,
                            ref='VehicleStatusMonitorThread: ' + rfidData.rfid,
                        )
                        # Make sure we reload the RFID tag data next loop
                        rfidData = None
                        if self.__requestVehicleWakeupNow:
                            self.clearVehicleWakeupRequest(
                                resultCode=HTTP_CODE_424_FAILED_DEPENDENCY,
                                msg='No valid token')
                        continue

                    self.__logger.debug("monitor() valid token")

                    # Refresh if required
                    if teslaApi.refreshTokenIfRequired():
                        # Invalidate the old token
                        tokenMediator.invalidate(
                            token=rfidData.api_access_token,
                            key=tKey,
                            ref='VehicleStatusMonitorThread: ' + rfidData.rfid)
                        UpdateOdometerTeslaUtil.copy_token_from_api_to_rfid_model(
                            teslaApi, rfidData)
                        # Checkout the new token
                        tKey = tokenMediator.checkout(
                            token=rfidData.api_access_token,
                            ref='VehicleStatusMonitorThread: ' + rfidData.rfid,
                            wait=True)
                        rfidData.save()

                    self.__logger.debug("monitor() [1] tKey={}".format(tKey))

                    # Force update, for now do not wakeup
                    # TODO - add wakeup as parameter
                    chargeState = teslaApi.getChargeStateWithId(
                        id=rfidData.vehicle_id,
                        update=True,
                        wakeUpWhenSleeping=oppleoConfig.
                        wakeupVehicleOnDataRequest
                        or self.__requestVehicleWakeupNow)

                    if self.__requestVehicleWakeupNow:
                        self.clearVehicleWakeupRequest(
                            resultCode=HTTP_CODE_200_OK if chargeState
                            is not None else HTTP_CODE_424_FAILED_DEPENDENCY,
                            msg='Vehicle awake' if chargeState is not None else
                            'Could not wakeup vehicle')

                    self.__logger.debug("monitor() [2] tKey={}".format(tKey))

                    # Release the token
                    tokenMediator.release(token=rfidData.api_access_token,
                                          key=tKey)

                    if chargeState is not None and oppleoConfig.vehicleDataOnDashboard:
                        self.__logger.debug("monitor() chargeState (not None)")
                        # Send change notification
                        WebSocketUtil.emit(
                            wsEmitQueue=oppleoConfig.wsEmitQueue,
                            event='vehicle_charge_status_update',
                            id=oppleoConfig.chargerName,
                            data={
                                'chargeState':
                                formatChargeState(chargeState),
                                'vehicle':
                                formatVehicle(
                                    teslaApi.getVehicleWithId(
                                        rfidData.vehicle_id)),
                                'vehicleMonitorInterval':
                                self.__vehicleMonitorInterval
                            },
                            namespace='/charge_session',
                            public=False)
                        # len(oppleoConfig.connectedClients) == 0
                    else:
                        self.__logger.debug(
                            'monitor() - could not get charge state (None)')
                        if teslaApi.vehicleWithIdIsAsleep(
                                id=rfidData.vehicle_id):
                            # Send change notification - vehicle asleep
                            WebSocketUtil.emit(
                                wsEmitQueue=oppleoConfig.wsEmitQueue,
                                event='vehicle_charge_status_update',
                                id=oppleoConfig.chargerName,
                                data={
                                    'chargeState':
                                    formatChargeState(chargeState),
                                    # No need to update vehicle information, done when requesting charge state
                                    'vehicle':
                                    formatVehicle(
                                        teslaApi.getVehicleWithId(
                                            id=rfidData.vehicle_id,
                                            update=False)),
                                    'vehicleMonitorInterval':
                                    self.__vehicleMonitorInterval
                                },
                                namespace='/charge_session',
                                public=False)
                else:
                    # len(oppleoConfig.connectedClients) == 0
                    self.__logger.debug(
                        'monitor() no connectedClients to report chargeState to or display not enabled. Skip and go directly to sleep.'
                    )

                    self.clearVehicleWakeupRequest(
                        resultCode=HTTP_CODE_410_GONE,
                        msg='No clients connected')

            # Sleep for quite a while, and yield for other threads
            time.sleep(self.__sleepInterval)
            monitorInterval = (monitorInterval + self.__sleepInterval)

        self.__logger.info("Stopping VehicleChargeStatusMonitorThread")
Ejemplo n.º 18
0
        print('Starting web server on {}:{} (debug:{}, use_reloader={})...'.
              format(oppleoSystemConfig.httpHost, oppleoSystemConfig.httpPort,
                     oppleoSystemConfig.DEBUG, oppleoConfig.useReloader))
        oppleoLogger.debug(
            'Starting web server on {}:{} (debug:{}, use_reloader={})...'.
            format(oppleoSystemConfig.httpHost, oppleoSystemConfig.httpPort,
                   oppleoSystemConfig.DEBUG, oppleoConfig.useReloader))

        WebSocketUtil.emit(wsEmitQueue=oppleoConfig.wsEmitQueue,
                           event='update',
                           id=oppleoConfig.chargerName,
                           data={
                               "restartRequired":
                               (oppleoConfig.restartRequired
                                or oppleoSystemConfig.restartRequired),
                               "upSince":
                               oppleoConfig.upSinceDatetimeStr,
                               "clientsConnected":
                               len(oppleoConfig.connectedClients)
                           },
                           namespace='/system_status',
                           public=False)

        PushMessage.sendMessage(
            "Starting", "Starting Oppleo {} at {}.".format(
                oppleoConfig.chargerName,
                datetime.now().strftime("%d/%m/%Y, %H:%M:%S")))

        appSocketIO.run(app,
                        port=oppleoSystemConfig.httpPort,
                        debug=oppleoSystemConfig.DEBUG,