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)
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)
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')
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)
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 )
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)
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)
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
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
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)
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)
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')
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)
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()
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")
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')
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")
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,