mirror of
https://github.com/flobz/psa_car_controller.git
synced 2026-08-22 01:16:14 +00:00
catch error on charge control
fix position api, improve handle of token expiration add rate limit to wakeup fct fix encoder name, wakeup device to follow charging status wakeup device if it doesn't send info for 10 mins
This commit is contained in:
+40
-33
@@ -70,42 +70,49 @@ class ChargeControl:
|
||||
def start(self):
|
||||
periodicity = ChargeControl.periodicity
|
||||
now = datetime.now()
|
||||
if self._next_stop_hour is not None and self._next_stop_hour < now:
|
||||
stop_charge = True
|
||||
self._next_stop_hour += timedelta(days=1)
|
||||
logger.info("it's time to stop the charge")
|
||||
else :
|
||||
stop_charge = False
|
||||
try:
|
||||
if self._next_stop_hour is not None and self._next_stop_hour < now:
|
||||
stop_charge = True
|
||||
self._next_stop_hour += timedelta(days=1)
|
||||
logger.info("it's time to stop the charge")
|
||||
else :
|
||||
stop_charge = False
|
||||
|
||||
if self.percentage_threshold != 100 or stop_charge:
|
||||
res = None
|
||||
try:
|
||||
res = self.psacc.get_vehicle_info(self.vin)
|
||||
except ApiException:
|
||||
logger.error(traceback.format_exc())
|
||||
if res is not None:
|
||||
status = res.energy[0]['charging']['status']
|
||||
level = res.energy[0]["level"]
|
||||
logger.info(f"charging status of {self.vin} is {status}, battery level: {level}")
|
||||
if status == "InProgress":
|
||||
if (level >= self.percentage_threshold and self.retry_count < 2) or stop_charge:
|
||||
self.psacc.charge_now(self.vin,False)
|
||||
self.retry_count += 1
|
||||
sleep(ChargeControl.MQTT_TIMEOUT)
|
||||
res = self.psacc.get_vehicle_info(self.vin)
|
||||
status = res.energy[0]['charging']['status']
|
||||
if status == "InProgress":
|
||||
logger.warn(f"retry to stop the charge of {self.vin}")
|
||||
self.psacc.charge_now(self.vin, False)
|
||||
if self.percentage_threshold != 100 or stop_charge:
|
||||
res = None
|
||||
try:
|
||||
res = self.psacc.get_vehicle_info(self.vin)
|
||||
except ApiException:
|
||||
logger.error(traceback.format_exc())
|
||||
if res is not None:
|
||||
status = res.energy[0]['charging']['status']
|
||||
level = res.energy[0]["level"]
|
||||
logger.info(f"charging status of {self.vin} is {status}, battery level: {level}")
|
||||
if status == "InProgress":
|
||||
# force update if the car doesn't send info during 10 minutes
|
||||
last_update = datetime.strptime(res.energy[0]['updatedAt'], "%Y-%m-%dT%H:%M:%SZ")
|
||||
if (datetime.utcnow() - last_update).total_seconds() > 60 * 10:
|
||||
self.psacc.wakeup(self.vin)
|
||||
if (level >= self.percentage_threshold and self.retry_count < 2) or stop_charge:
|
||||
self.psacc.charge_now(self.vin,False)
|
||||
self.retry_count += 1
|
||||
if self._next_stop_hour is not None:
|
||||
next_in_second = (self._next_stop_hour- now).total_seconds()
|
||||
if next_in_second < periodicity:
|
||||
periodicity = next_in_second
|
||||
sleep(ChargeControl.MQTT_TIMEOUT)
|
||||
res = self.psacc.get_vehicle_info(self.vin)
|
||||
status = res.energy[0]['charging']['status']
|
||||
if status == "InProgress":
|
||||
logger.warn(f"retry to stop the charge of {self.vin}")
|
||||
self.psacc.charge_now(self.vin, False)
|
||||
self.retry_count += 1
|
||||
if self._next_stop_hour is not None:
|
||||
next_in_second = (self._next_stop_hour- now).total_seconds()
|
||||
if next_in_second < periodicity:
|
||||
periodicity = next_in_second
|
||||
else:
|
||||
self.retry_count = 0
|
||||
else:
|
||||
self.retry_count = 0
|
||||
else:
|
||||
logger.error(f"error when get vehicle info of {self.vin}")
|
||||
logger.error(f"error when get vehicle info of {self.vin}")
|
||||
except:
|
||||
logger.error(traceback.format_exc())
|
||||
self.thread = threading.Timer(periodicity, self.start)
|
||||
self.thread.start()
|
||||
|
||||
|
||||
+109
-24
@@ -7,6 +7,8 @@ from datetime import datetime
|
||||
from http import HTTPStatus
|
||||
from json import JSONEncoder
|
||||
from hashlib import md5
|
||||
from time import sleep
|
||||
|
||||
from oauth2_client.credentials_manager import CredentialManager, ServiceInformation
|
||||
import paho.mqtt.client as mqtt
|
||||
from requests import Response
|
||||
@@ -14,6 +16,9 @@ import psa_connectedcar as psac
|
||||
from psa_connectedcar import ApiClient
|
||||
from psa_connectedcar.rest import ApiException
|
||||
from MyLogger import logger
|
||||
from threading import Semaphore, Timer
|
||||
from functools import wraps
|
||||
|
||||
|
||||
oauhth_url = {"clientsB2CPeugeot":"https://idpcvs.peugeot.com/am/oauth2/access_token",
|
||||
"clientsB2CCitroen":"https://idpcvs.citroen.com/am/oauth2/access_token",
|
||||
@@ -25,6 +30,28 @@ authorize_service = "https://api.mpsa.com/api/connectedcar/v2/oauth/authorize"
|
||||
remote_url = "https://api.groupe-psa.com/connectedcar/v4/virtualkey/remoteaccess/token?client_id="
|
||||
scopes = ['openid profile']
|
||||
MQTT_SERVER = "mwa.mpsa.com"
|
||||
MQTT_REQ_TOPIC = "psa/RemoteServices/from/cid/"
|
||||
MQTT_RESP_TOPIC = "psa/RemoteServices/to/cid/"
|
||||
MQTT_EVENT_TOPIC = "psa/RemoteServices/events/MPHRTServices/"
|
||||
MQTT_TOKEN_TTL = 890
|
||||
|
||||
def rate_limit(limit, every):
|
||||
def limit_decorator(fn):
|
||||
semaphore = Semaphore(limit)
|
||||
|
||||
@wraps(fn)
|
||||
def wrapper(*args, **kwargs):
|
||||
semaphore.acquire()
|
||||
try:
|
||||
return fn(*args, **kwargs)
|
||||
finally: # don't catch but ensure semaphore release
|
||||
timer = Timer(every, semaphore.release)
|
||||
timer.setDaemon(True) # allows the timer to be canceled on exit
|
||||
timer.start()
|
||||
|
||||
return wrapper
|
||||
|
||||
return limit_decorator
|
||||
|
||||
class OpenIdCredentialManager(CredentialManager):
|
||||
def _grant_password_request(self, login: str, password: str, realm: str) -> dict:
|
||||
@@ -126,6 +153,9 @@ class MyPSACC:
|
||||
"x-introspect-realm": realm,
|
||||
"accept": "application/hal+json",
|
||||
}
|
||||
self.remote_token_last_update = None
|
||||
self._record_enabled = False
|
||||
|
||||
def refresh_token(self):
|
||||
self.manager._refresh_token()
|
||||
|
||||
@@ -148,6 +178,8 @@ class MyPSACC:
|
||||
# retry
|
||||
if res is None:
|
||||
res = self.api().get_vehicle_status(self.get_vehicle_id_with_vin(vin))
|
||||
if self._record_enabled:
|
||||
self.record_position(vin, res)
|
||||
return res
|
||||
|
||||
# monitor doesn't seem to work
|
||||
@@ -182,7 +214,12 @@ class MyPSACC:
|
||||
self.remote_refresh_token = data["refresh_token"]
|
||||
return res
|
||||
|
||||
def refresh_remote_token(self):
|
||||
def refresh_remote_token(self, force=False):
|
||||
self.manager._refresh_token()
|
||||
if not force and self.remote_token_last_update is not None:
|
||||
last_update: datetime = self.remote_token_last_update
|
||||
if (datetime.now()-last_update).total_seconds() < MQTT_TOKEN_TTL:
|
||||
return
|
||||
res = self.manager.post(remote_url + self.client_id,
|
||||
json={"grant_type": "refresh_token", "refresh_token": self.remote_refresh_token},
|
||||
headers=self.headers)
|
||||
@@ -190,14 +227,15 @@ class MyPSACC:
|
||||
logger.debug(f"refresh_remote_token: {data}")
|
||||
self.remote_access_token = data["access_token"]
|
||||
self.remote_refresh_token = data["refresh_token"]
|
||||
self.remote_token_last_update = datetime.now()
|
||||
return data["access_token"], data["refresh_token"]
|
||||
|
||||
def on_mqtt_connect(self, client, userdata, rc, a):
|
||||
try:
|
||||
logger.info("Connected with result code " + str(rc))
|
||||
topics = ["psa/RemoteServices/to/cid/" + self.customer_id + "/#"]
|
||||
topics = [MQTT_RESP_TOPIC + self.customer_id + "/#"]
|
||||
for vin in self.getVIN():
|
||||
topics.append("psa/RemoteServices/events/MPHRTServices/" + vin + "/#")
|
||||
topics.append(MQTT_EVENT_TOPIC+ vin + "/#")
|
||||
for topic in topics:
|
||||
client.subscribe(topic)
|
||||
logger.info("subscribe to " + topic)
|
||||
@@ -215,18 +253,24 @@ class MyPSACC:
|
||||
|
||||
def on_mqtt_message(self, client, userdata, msg):
|
||||
logger.info(f"mqtt msg {msg.topic} {str(msg.payload)}")
|
||||
try:
|
||||
data = json.loads(msg.payload)
|
||||
if data["return_code"] == "0":
|
||||
return
|
||||
elif data["return_code"] == "400":
|
||||
self.manager._refresh_token()
|
||||
self.refresh_remote_token()
|
||||
logger.info("retry last request")
|
||||
else:
|
||||
logger.error(f'{data["return_code"]} : {data["reason"]}')
|
||||
except:
|
||||
logger.debug("mqtt msg hasn't return code")
|
||||
data = json.loads(msg.payload)
|
||||
if msg.topic.startswith(MQTT_RESP_TOPIC):
|
||||
try:
|
||||
if data["return_code"] == "0":
|
||||
return
|
||||
elif data["return_code"] == "400":
|
||||
self.refresh_remote_token(force=True)
|
||||
logger.error("retry last request, token was expired")
|
||||
else:
|
||||
logger.error(f'{data["return_code"]} : {data["reason"]}')
|
||||
except:
|
||||
logger.debug("mqtt msg hasn't return code")
|
||||
elif msg.topic.startswith(MQTT_EVENT_TOPIC):
|
||||
# fix charge beginning without status api being updated
|
||||
if data["charging_state"]['remaining_time'] != 0 and data["charging_state"]['rate'] == 0:
|
||||
logger.info("charge begin")
|
||||
sleep(60)
|
||||
self.wakeup(data["vin"])
|
||||
|
||||
def start_mqtt(self):
|
||||
self.refresh_remote_token()
|
||||
@@ -241,7 +285,8 @@ class MyPSACC:
|
||||
return self.mqtt_client.is_connected()
|
||||
|
||||
def mqtt_request(self, vin, req_parameters):
|
||||
date = datetime.now()
|
||||
self.refresh_token()
|
||||
date = datetime.utcnow()
|
||||
date_f = "%Y-%m-%dT%H:%M:%SZ"
|
||||
date_str = date.strftime(date_f)
|
||||
data = {"access_token": self.remote_access_token, "customer_id": self.customer_id,
|
||||
@@ -271,7 +316,7 @@ class MyPSACC:
|
||||
# todo consider actual state before change the hour
|
||||
msg = self.mqtt_request(vin, {"program": {"hour": hour, "minute": miinute}, "type": charge_type})
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/VehCharge", msg)
|
||||
self.mqtt_client.publish(MQTT_REQ_TOPIC + self.customer_id + "/VehCharge", msg)
|
||||
|
||||
def change_charge_hour(self, vin, hour, miinute):
|
||||
# todo consider actual state before change the hour
|
||||
@@ -290,17 +335,19 @@ class MyPSACC:
|
||||
def horn(self, vin, count):
|
||||
msg = self.mqtt_request(vin, {"nb_horn": count, "action": "activate"})
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/Horn", msg)
|
||||
self.mqtt_client.publish(MQTT_REQ_TOPIC + self.customer_id + "/Horn", msg)
|
||||
|
||||
def lights(self, vin, duration: int):
|
||||
msg = self.mqtt_request(vin, {"action": "activate", "duration": duration})
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/Lights", msg)
|
||||
self.mqtt_client.publish(MQTT_REQ_TOPIC + self.customer_id + "/Lights", msg)
|
||||
|
||||
@rate_limit(3, 60 * 20)
|
||||
def wakeup(self, vin):
|
||||
logger.info("ask wakeup to "+vin)
|
||||
msg = self.mqtt_request(vin, {"action": "state"})
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/VehCharge/state", msg)
|
||||
self.mqtt_client.publish(MQTT_REQ_TOPIC + self.customer_id + "/VehCharge/state", msg)
|
||||
return True
|
||||
|
||||
def lock_door(self, vin, lock: bool):
|
||||
@@ -311,7 +358,7 @@ class MyPSACC:
|
||||
|
||||
msg = self.mqtt_request(vin, {"action": value})
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/Doors", msg)
|
||||
self.mqtt_client.publish(MQTT_REQ_TOPIC + self.customer_id + "/Doors", msg)
|
||||
return True
|
||||
|
||||
def preconditioning(self, vin, activate: bool):
|
||||
@@ -325,11 +372,11 @@ class MyPSACC:
|
||||
"program3": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0},
|
||||
"program4": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0}}})
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/ThermalPrecond", msg)
|
||||
self.mqtt_client.publish(MQTT_REQ_TOPIC + self.customer_id + "/ThermalPrecond", msg)
|
||||
return True
|
||||
|
||||
def save_config(self, name="config.json", force=False):
|
||||
config_str = json.dumps(self, cls=MyPuegeotEncoder, sort_keys=True, indent=4).encode("utf8")
|
||||
config_str = json.dumps(self, cls=MyPeugeotEncoder, sort_keys=True, indent=4).encode("utf8")
|
||||
new_hash = md5(config_str).hexdigest()
|
||||
if force or self._confighash != new_hash:
|
||||
with open(name, "wb") as f:
|
||||
@@ -337,13 +384,51 @@ class MyPSACC:
|
||||
self._confighash = new_hash
|
||||
logger.info("save config change")
|
||||
|
||||
@staticmethod
|
||||
def load_config(name="config.json"):
|
||||
with open(name, "r") as f:
|
||||
str = f.read()
|
||||
return MyPSACC(**json.loads(str))
|
||||
|
||||
def set_record(self,value:bool):
|
||||
self._record_enabled = value
|
||||
|
||||
class MyPuegeotEncoder(JSONEncoder):
|
||||
def record_position(self,vin, res:psac.models.status.Status):
|
||||
import sqlite3
|
||||
conn = sqlite3.connect('info.db')
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS position (Timestamp DATETIME PRIMARY KEY, VIN TEXT, longitude REAL, latitude REAL);")
|
||||
|
||||
longitude = res.last_position.geometry.coordinates[0]
|
||||
latitude = res.last_position.geometry.coordinates[1]
|
||||
date = res.last_position.properties.updated_at
|
||||
e = None
|
||||
try:
|
||||
conn.execute("INSERT INTO position(Timestamp,VIN,longitude,latitude) VALUES(?,?,?,?)",
|
||||
(date, vin, longitude, latitude))
|
||||
conn.commit()
|
||||
except sqlite3.IntegrityError:
|
||||
logger.debug("position already saved")
|
||||
finally:
|
||||
conn.close()
|
||||
|
||||
def get_recorded_position(self):
|
||||
import sqlite3
|
||||
from geojson import Feature, Point, FeatureCollection
|
||||
from geojson import dumps as geo_dumps
|
||||
conn = sqlite3.connect('info.db')
|
||||
conn.row_factory = sqlite3.Row
|
||||
res = conn.execute('SELECT * FROM position ORDER BY Timestamp');
|
||||
features_list = []
|
||||
for row in res:
|
||||
print(row)
|
||||
feature = Feature(geometry=Point((row["longitude"], row["latitude"])),
|
||||
properties={"vin": row["vin"], "date": row["Timestamp"]})
|
||||
features_list.append(feature)
|
||||
feature_collection = FeatureCollection(features_list)
|
||||
return geo_dumps(feature_collection, sort_keys=True)
|
||||
|
||||
class MyPeugeotEncoder(JSONEncoder):
|
||||
def default(self, mp: MyPSACC):
|
||||
data = copy(mp.__dict__)
|
||||
mpd = {}
|
||||
|
||||
@@ -31,58 +31,58 @@ class Position(object):
|
||||
and the value is json key in definition.
|
||||
"""
|
||||
swagger_types = {
|
||||
'created_at': 'datetime',
|
||||
'type': 'str',
|
||||
'geometry': 'Point',
|
||||
'properties': 'PositionProperties',
|
||||
'type': 'str'
|
||||
'properties': 'PositionProperties'
|
||||
}
|
||||
|
||||
attribute_map = {
|
||||
'created_at': 'createdAt',
|
||||
'type': 'type',
|
||||
'geometry': 'geometry',
|
||||
'properties': 'properties',
|
||||
'type': 'type'
|
||||
'properties': 'properties'
|
||||
}
|
||||
|
||||
def __init__(self, created_at=None, geometry=None, properties=None, type='Feature'): # noqa: E501
|
||||
def __init__(self, type='Feature', geometry=None, properties=None): # noqa: E501
|
||||
"""Position - a model defined in Swagger""" # noqa: E501
|
||||
|
||||
self._created_at = None
|
||||
self._type = None
|
||||
self._geometry = None
|
||||
self._properties = None
|
||||
self._type = None
|
||||
self.discriminator = None
|
||||
|
||||
if created_at is not None:
|
||||
self.created_at = created_at
|
||||
if geometry is not None:
|
||||
self.geometry = geometry
|
||||
self.properties = properties
|
||||
if type is not None:
|
||||
self.type = type
|
||||
if geometry is not None:
|
||||
self.geometry = geometry
|
||||
if properties is not None:
|
||||
self.properties = properties
|
||||
|
||||
@property
|
||||
def created_at(self):
|
||||
"""Gets the created_at of this Position. # noqa: E501
|
||||
def type(self):
|
||||
"""Gets the type of this Position. # noqa: E501
|
||||
|
||||
Date when the resource has been created. # noqa: E501
|
||||
|
||||
:return: The created_at of this Position. # noqa: E501
|
||||
:rtype: datetime
|
||||
:return: The type of this Position. # noqa: E501
|
||||
:rtype: str
|
||||
"""
|
||||
return self._created_at
|
||||
return self._type
|
||||
|
||||
@created_at.setter
|
||||
def created_at(self, created_at):
|
||||
"""Sets the created_at of this Position.
|
||||
@type.setter
|
||||
def type(self, type):
|
||||
"""Sets the type of this Position.
|
||||
|
||||
Date when the resource has been created. # noqa: E501
|
||||
|
||||
:param created_at: The created_at of this Position. # noqa: E501
|
||||
:type: datetime
|
||||
:param type: The type of this Position. # noqa: E501
|
||||
:type: str
|
||||
"""
|
||||
allowed_values = ["Feature"] # noqa: E501
|
||||
if type not in allowed_values:
|
||||
raise ValueError(
|
||||
"Invalid value for `type` ({0}), must be one of {1}" # noqa: E501
|
||||
.format(type, allowed_values)
|
||||
)
|
||||
|
||||
self._created_at = created_at
|
||||
self._type = type
|
||||
|
||||
@property
|
||||
def geometry(self):
|
||||
@@ -123,38 +123,9 @@ class Position(object):
|
||||
:param properties: The properties of this Position. # noqa: E501
|
||||
:type: PositionProperties
|
||||
"""
|
||||
if properties is None:
|
||||
raise ValueError("Invalid value for `properties`, must not be `None`") # noqa: E501
|
||||
|
||||
self._properties = properties
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
"""Gets the type of this Position. # noqa: E501
|
||||
|
||||
|
||||
:return: The type of this Position. # noqa: E501
|
||||
:rtype: str
|
||||
"""
|
||||
return self._type
|
||||
|
||||
@type.setter
|
||||
def type(self, type):
|
||||
"""Sets the type of this Position.
|
||||
|
||||
|
||||
:param type: The type of this Position. # noqa: E501
|
||||
:type: str
|
||||
"""
|
||||
allowed_values = ["Feature"] # noqa: E501
|
||||
if type not in allowed_values:
|
||||
raise ValueError(
|
||||
"Invalid value for `type` ({0}), must be one of {1}" # noqa: E501
|
||||
.format(type, allowed_values)
|
||||
)
|
||||
|
||||
self._type = type
|
||||
|
||||
def to_dict(self):
|
||||
"""Returns the model properties as a dict"""
|
||||
result = {}
|
||||
|
||||
@@ -33,21 +33,24 @@ class PositionProperties(object):
|
||||
swagger_types = {
|
||||
'heading': 'float',
|
||||
'signal_quality': 'float',
|
||||
'type': 'str'
|
||||
'type': 'str',
|
||||
'updated_at': 'datetime'
|
||||
}
|
||||
|
||||
attribute_map = {
|
||||
'heading': 'heading',
|
||||
'signal_quality': 'signalQuality',
|
||||
'type': 'type'
|
||||
'type': 'type',
|
||||
'updated_at': 'updatedAt'
|
||||
}
|
||||
|
||||
def __init__(self, heading=None, signal_quality=None, type=None): # noqa: E501
|
||||
def __init__(self, heading=None, signal_quality=None, type=None, updated_at=None): # noqa: E501
|
||||
"""PositionProperties - a model defined in Swagger""" # noqa: E501
|
||||
|
||||
self._heading = None
|
||||
self._signal_quality = None
|
||||
self._type = None
|
||||
self._updated_at = None
|
||||
self.discriminator = None
|
||||
|
||||
if heading is not None:
|
||||
@@ -56,6 +59,8 @@ class PositionProperties(object):
|
||||
self.signal_quality = signal_quality
|
||||
if type is not None:
|
||||
self.type = type
|
||||
if updated_at is not None:
|
||||
self.updated_at = updated_at
|
||||
|
||||
@property
|
||||
def heading(self):
|
||||
@@ -130,6 +135,27 @@ class PositionProperties(object):
|
||||
|
||||
self._type = type
|
||||
|
||||
@property
|
||||
def updated_at(self):
|
||||
"""Gets the updated_at of this PositionProperties. # noqa: E501
|
||||
|
||||
|
||||
:return: The updated_at of this PositionProperties. # noqa: E501
|
||||
:rtype: datetime
|
||||
"""
|
||||
return self._updated_at
|
||||
|
||||
@updated_at.setter
|
||||
def updated_at(self, updated_at):
|
||||
"""Sets the updated_at of this PositionProperties.
|
||||
|
||||
|
||||
:param updated_at: The updated_at of this PositionProperties. # noqa: E501
|
||||
:type: datetime
|
||||
"""
|
||||
|
||||
self._updated_at = updated_at
|
||||
|
||||
def to_dict(self):
|
||||
"""Returns the model properties as a dict"""
|
||||
result = {}
|
||||
|
||||
@@ -8,6 +8,7 @@ from ChargeControl import ChargeControls
|
||||
from MyLogger import my_logger
|
||||
from MyPSACC import *
|
||||
from flask import Flask, request, jsonify
|
||||
from flask import Response as FlaskResponse
|
||||
import argparse
|
||||
from MyLogger import logger
|
||||
|
||||
@@ -49,6 +50,11 @@ def wakeup(vin):
|
||||
def preconditioning(vin, activate):
|
||||
return jsonify(myp.preconditioning(vin, activate))
|
||||
|
||||
@app.route('/position/<string:vin>')
|
||||
def get_position(vin):
|
||||
res = myp.get_vehicle_info(vin)
|
||||
longitude, latitude = res.last_position.geometry.coordinates
|
||||
return jsonify({"longitude":longitude,"latitude":latitude,"url":f"http://maps.google.com/maps?q={latitude},{longitude}"})
|
||||
|
||||
def save_config(mypeugeot: MyPSACC):
|
||||
myp.save_config()
|
||||
@@ -70,6 +76,9 @@ def charge_control():
|
||||
chc.save_config()
|
||||
return jsonify(charge_control.get_dict())
|
||||
|
||||
@app.route('/positions')
|
||||
def get_recorded_position():
|
||||
return FlaskResponse(myp.get_recorded_position(), mimetype='application/json')
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
@@ -78,6 +87,7 @@ def parse_args():
|
||||
parser.add_argument("-d", "--debug", help="enable debug", const=10, default=20, nargs='?')
|
||||
parser.add_argument("-l", "--listen", help="change server listen address", default="127.0.0.1")
|
||||
parser.add_argument("-p", "--port", help="change server listen address", default="5000")
|
||||
parser.add_argument("-r", "--record-position", help="save vehicle position to db", action='store_true')
|
||||
parser.add_argument("--remote-disable",help="disable remote control")
|
||||
parser.parse_args()
|
||||
return parser
|
||||
@@ -85,7 +95,7 @@ def parse_args():
|
||||
|
||||
if __name__ == "__main__":
|
||||
if sys.version_info < (3, 6):
|
||||
raise RuntimeError("This application requres Python 3.6+")
|
||||
raise RuntimeError("This application requires Python 3.6+")
|
||||
parser = parse_args()
|
||||
args = parser.parse_args()
|
||||
my_logger(handler_level=args.debug)
|
||||
@@ -94,6 +104,8 @@ if __name__ == "__main__":
|
||||
myp = MyPSACC.load_config(name=args.config.name)
|
||||
else:
|
||||
myp = MyPSACC.load_config()
|
||||
if args.record_position:
|
||||
myp.set_record(True)
|
||||
try:
|
||||
myp.manager._refresh_token()
|
||||
except OAuthError:
|
||||
|
||||
Reference in New Issue
Block a user