async def cookie2user(cookie_str): ''' Parse cookie and load user if cookie is valid. ''' if not cookie_str: return None try: L = cookie_str.split('-') if len(L) != 3: return None uid, expires, sha1 = L if int(expires) < time.time(): return None user = await User.find(uid) if user is None: return None s = '{}-{}-{}-{}'.format(uid, user.passwd, expires, _COOKIE_KEY) if sha1 != hashlib.sha1(s.encode('utf-8')).hexdigest(): logger.info('invalid sha1') return None user.passwd = '******' return user except Exception as e: logger.exception(e) return None
def __on_mqtt_message(self, client, userdata, msg): try: logger.info("mqtt msg %s %s", msg.topic, msg.payload) data = json.loads(msg.payload) charge_info = None if msg.topic.startswith(MQTT_RESP_TOPIC): if "return_code" not in data: logger.debug("mqtt msg hasn't return code") elif data["return_code"] == "400": self.refresh_remote_token(force=True) logger.error("retry last request, token was expired") elif data["return_code"] == "300": logger.error('%s', data["return_code"]) elif data["return_code"] != "0": logger.error('%s : %s', data["return_code"], data["reason"]) if msg.topic.endswith("/VehicleState"): charge_info = data["resp_data"]["charging_state"] self.precond_programs[data["vin"]] = data["resp_data"]["precond_state"]["programs"] elif msg.topic.startswith(MQTT_EVENT_TOPIC): charge_info = data["charging_state"] if charge_info is not None and charge_info['remaining_time'] != 0 and charge_info['rate'] == 0: # fix a psa server bug where charge beginning without status api being properly updated logger.warning("charge begin but API isn't updated") sleep(60) self.wakeup(data["vin"]) except KeyError: logger.exception("mqtt message:")
def get_data_france(start, end): start_str = start.strftime("%d/%m/%Y") end_str = end.strftime("%d/%m/%Y") try: res = requests.get( f"https://eco2mix.rte-france.com/curves/eco2mixWeb?type=co2&&dateDeb={start_str}" f"&dateFin={end_str}&mode=NORM", headers={ "Origin": "https://www.rte-france.com", "Referer": "https://www.rte-france.com/eco2mix/les-emissions-de-co2-par-kwh-produit-en-france", }) except RequestException: logger.exception("get_data_france: ") return None etree = ElT.fromstring(res.text) period_start = (start.hour + int(start.minute / 30)) * 4 period_end = (end.hour + int(end.minute / 30)) * 4 valeurs = etree.iter("valeur") co2_per_kw = [] valeur = next(valeurs) while int(valeur.attrib["periode"]) != period_start: valeur = next(valeurs) while int(valeur.attrib["periode"]) != period_end: co2_per_kw.append(int(valeur.text)) valeur = next(valeurs) try: return mean(co2_per_kw) except StatisticsError: return None
def call(self, car: Car, ext_temp: float = None): try: if self.token is None or len(self.token) == 0: logger.debug("No abrp token provided") elif car.vin in self.abrp_enable_vin: energy = car.status.get_energy('Electric') tlm = {"utc": int(datetime.timestamp(energy.updated_at)), "soc": energy.level, "speed": getattr(car.status.kinetic, "speed", None), "car_model": car.get_abrp_name(), "current": car.status.battery.current, "is_charging": energy.charging.status == "InProgress", "lat": car.status.last_position.geometry.coordinates[1], "lon": car.status.last_position.geometry.coordinates[0], "power": energy.consumption } if ext_temp is not None: tlm["ext_temp"] = ext_temp params = {"tlm": json.dumps(tlm), "token": self.token, "api_key": self.api_key} response = requests.request("POST", self.url, params=params, proxies=self.proxies, verify=self.proxies is None) logger.debug(response.text) return response.json()["status"] == "ok" except (AttributeError, IndexError, ValueError): logger.exception("abrp:") return False
def __get_charge_hour(self, vin): hour_str = self.vehicles_list.get_car_by_vin(vin).status.get_energy( 'Electric').charging.next_delayed_time try: return parse_hour(hour_str)[:2] except IndexError: logger.exception("Can't get charge hour: %s", hour_str) return None
def __get_charge_hour(self, vin): data = self.get_vehicle_info(vin) hour_str = data.get_energy('Electric').charging.next_delayed_time try: return parse_hour(hour_str)[:2] except IndexError: logger.exception("Can't get charge hour: %s", hour_str) return None
def get_otp_code(self): try: otp_code = self.otp.get_otp_code() except ConfigException: logger.exception("get_otp_code:") self.load_otp(force_new=True) otp_code = self.otp.get_otp_code() save_otp(self.otp) return otp_code
def get_vehicles(self): try: res = self.api().get_vehicles_by_device() for vehicle in res.embedded.vehicles: self.vehicles_list.add(Car(vehicle.vin, vehicle.id, vehicle.brand, vehicle.label)) self.vehicles_list.save_cars() except (ApiException, InvalidHeader): logger.exception("get_vehicles:") return self.vehicles_list
def __keep_mqtt(self): # avoid token expiration timeout = 3600 * 24 # 1 day if len(self.vehicles_list) > 0: try: self.wakeup(self.vehicles_list[0].vin) except RateLimitException: logger.exception("__keep_mqtt") t = threading.Timer(timeout, self.__keep_mqtt) t.setDaemon(True) t.start()
def __refresh_vehicle_info(self): if self.info_refresh_rate is not None: while True: try: logger.debug("refresh_vehicle_info") for car in self.vehicles_list: self.get_vehicle_info(car.vin) for callback in self.info_callback: callback() except: # pylint: disable=bare-except logger.exception("refresh_vehicle_info: ") sleep(self.info_refresh_rate)
def __get_charge_hour(self, vin): reg = r"PT([0-9]{1,2})H([0-9]{1,2})?" data = self.get_vehicle_info(vin) hour_str = data.get_energy('Electric').charging.next_delayed_time try: hour_minute = re.findall(reg, hour_str)[0] hour = int(hour_minute[0]) if hour_minute[1] == '': minute = 0 else: minute = hour_minute[1] return hour, minute except IndexError: logger.exception("Can't get charge hour: %s", hour_str) return None
def finishOtp(n_clicks, code_pin, sms_code): # pylint: disable=unused-argument ctx = callback_context if ctx.triggered: try: otp_session = new_otp_session(sms_code, code_pin, config.myp.remote_client.otp) config.myp.remote_client.otp = otp_session config.myp.save_config() config.start_remote_control() return dbc.Alert([ "OTP config finish !!! ", html.A("Go to home", href=request.url_root) ], color="success") except Exception as e: res = str(e) logger.exception("finishOtp:") return dbc.Alert(res, color="danger") raise PreventUpdate()
def __on_mqtt_message(self, client, userdata, msg): try: logger.info("mqtt msg received: %s %s", msg.topic, msg.payload) logger.debug("client: %s userdata: %s", client, userdata) data = json.loads(msg.payload) charge_info = None if msg.topic.startswith(MQTT_RESP_TOPIC): if "return_code" not in data: logger.debug("mqtt msg hasn't return code") elif data["return_code"] == "400": self._refresh_remote_token(force=True) if self.last_request: logger.warning( "last request is send again, token was expired") last_request = self.last_request self.last_request = None self.publish(last_request, store=False) else: logger.error( "Last request might have been send twice without success" ) elif data["return_code"] != "0": logger.error('%s : %s', data["return_code"], data.get("reason", "?")) elif msg.topic.startswith(MQTT_EVENT_TOPIC): charge_info = data["charging_state"] self.precond_programs[ data["vin"]] = data["precond_state"]["programs"] if charge_info is not None and charge_info['remaining_time'] != 0: try: car = self.vehicles_list.get_car_by_vin( vin=msg.topic.split("/")[-1]) if car and car.status.get_energy( 'Electric').charging.status != INPROGRESS: # fix a psa server bug where charge beginning without status api being properly updated logger.warning("charge begin but API isn't updated") sleep(60) self.wakeup(data["vin"]) except (IndexError, AttributeError, RateLimitException): logger.exception("on_mqtt_message:") except KeyError: logger.exception("on_mqtt_message:")
def _refresh_remote_token(self, force=False): bad_remote_token = self.remoteCredentials.refresh_token is None if not force and not bad_remote_token and self.remoteCredentials.last_update: last_update: datetime = self.remoteCredentials.last_update if (datetime.now() - last_update).total_seconds() < MQTT_TOKEN_TTL: return True try: self.manager.refresh_token_now() if bad_remote_token: logger.error("remote_refresh_token isn't defined") else: res = self.manager.post( REMOTE_URL + self.account_info.client_id, json={ "grant_type": "refresh_token", "refresh_token": self.remoteCredentials.refresh_token }, headers=self.headers) data = res.json() logger.debug("refresh_remote_token: %s", data) if "access_token" in data: self.remoteCredentials.access_token = data["access_token"] self.remoteCredentials.refresh_token = data[ "refresh_token"] bad_remote_token = False else: logger.error( "can't refresh_remote_token: %s\n Create a new one", data) bad_remote_token = True if bad_remote_token: otp_code = self.get_otp_code() res = self.get_remote_access_token(otp_code) self.remote_token_last_update = datetime.now() self.mqtt_client.username_pw_set( "IMA_OAUTH_ACCESS_TOKEN", self.remoteCredentials.access_token) return True except (RequestException, RateLimitException) as e: logger.exception("Can't refresh remote token %s", e) sleep(60) return False
def process(self): now = datetime.now() try: vehicle_status = self.psacc.vehicles_list.get_car_by_vin( self.vin).get_status() status = vehicle_status.get_energy('Electric').charging.status level = vehicle_status.get_energy('Electric').level logger.info("charging status of %s is %s, battery level: %d", self.vin, status, level) if status == "InProgress": self.force_update() if level >= self.percentage_threshold and self.retry_count < 2: logger.info("Charge threshold is reached, stop the charge") self.control_charge_with_ack(False) elif self._next_stop_hour is not None: if self._next_stop_hour < now: self._next_stop_hour += timedelta(days=1) logger.info("it's time to stop the charge") self.control_charge_with_ack(False) else: next_in_second = (self._next_stop_hour - now).total_seconds() if next_in_second < self.psacc.info_refresh_rate: periodicity = next_in_second thread = threading.Timer(periodicity, self.process) thread.setDaemon(True) thread.start() else: if self._next_stop_hour is not None and self._next_stop_hour < now: self._next_stop_hour += timedelta(days=1) self.retry_count = 0 except (AttributeError, ValueError): logger.exception( "Probably can't retrieve all information from API:") except: # pylint: disable=bare-except logger.exception("Charge control:")
def get_control_tabs(config): tabs = [] for car in config.myp.vehicles_list: if car.label is None: label = car.vin else: label = car.label myp: MyPSACC = config.myp el = [] buttons_row = [] if config.remote_control: try: preconditionning_state = car.status.preconditionning.air_conditioning.status != "Disabled" charging_state = car.status.get_energy( 'Electric').charging.status == "InProgress" cards = { "Battery": { "text": [ card_value_div( "battery_value", "%", value=convert_value_to_str( car.status.get_energy('Electric').level)) ], "src": "assets/images/battery-charge.svg" }, "Mileage": { "text": [ card_value_div( "mileage_value", "km", value=convert_value_to_str( car.status.timed_odometer.mileage)) ], "src": "assets/images/mileage.svg" } } el.append( dbc.Container(dbc.Row(children=create_card(cards)), fluid=True)) buttons_row.extend([ Button( REFRESH_SWITCH, car.vin, html.Img(src="assets/images/sync.svg", width="50px"), myp.remote_client.wakeup).get_html(), Switch(CHARGE_SWITCH, car.vin, "Charge", myp.remote_client.charge_now, charging_state).get_html(), Switch(PRECONDITIONING_SWITCH, car.vin, "Preconditioning", myp.remote_client.preconditioning, preconditionning_state).get_html() ]) except (AttributeError, TypeError): logger.exception("get_control_tabs:") if not config.offline: buttons_row.append( Switch(ABRP_SWITCH, car.vin, "Send data to ABRP", myp.abrp.enable_abrp, car.vin in config.myp.abrp.abrp_enable_vin).get_html()) tabs.append( dbc.Tab(label=label, id="tab-" + car.vin, children=[dbc.Row(buttons_row), *el])) return dbc.Tabs(id="control-tabs", children=tabs)