mirror of
https://github.com/flobz/psa_car_controller.git
synced 2026-08-22 01:16:14 +00:00
add logger, fix typo
This commit is contained in:
+7
-5
@@ -4,8 +4,8 @@ from copy import copy
|
||||
from datetime import datetime, timedelta
|
||||
from hashlib import md5
|
||||
from time import sleep
|
||||
|
||||
from MyPSACC import MyPSACC
|
||||
from MyLogger import logger
|
||||
|
||||
class ChargeControls:
|
||||
def __init__(self):
|
||||
@@ -22,7 +22,7 @@ class ChargeControls:
|
||||
with open(name, "wb") as f:
|
||||
f.write(config_str)
|
||||
self._confighash = new_hash
|
||||
print("save config change")
|
||||
logger.info("save config change")
|
||||
|
||||
def load_config(psacc:MyPSACC, name="charge_config.json"):
|
||||
with open(name, "r") as f:
|
||||
@@ -50,6 +50,7 @@ class ChargeControl:
|
||||
self.set_stop_hour(stop_hour)
|
||||
self.psacc = psacc
|
||||
self.retry_count = 0
|
||||
self.thread = None
|
||||
|
||||
def set_stop_hour(self,stop_hour):
|
||||
if stop_hour == [0, 0]:
|
||||
@@ -72,7 +73,7 @@ class ChargeControl:
|
||||
stop_charge = False
|
||||
|
||||
if self.percentage_threshold != 100 or stop_charge:
|
||||
res = self.psacc.getVehiculeinfo(self.vin)
|
||||
res = self.psacc.get_vehicle_info(self.vin)
|
||||
if res is not None:
|
||||
status = res.energy[0]['charging']['status']
|
||||
print(f"charging status of {self.vin} is {status}")
|
||||
@@ -82,7 +83,7 @@ class ChargeControl:
|
||||
self.psacc.charge_now(self.vin,False)
|
||||
self.retry_count += 1
|
||||
sleep(45)
|
||||
res = self.psacc.getVehiculeinfo(self.vin)
|
||||
res = self.psacc.get_vehicle_info(self.vin)
|
||||
status = res.energy[0]['charging']['status']
|
||||
if status == "InProgress":
|
||||
print(f"retry to stop the charge of {self.vin}")
|
||||
@@ -97,7 +98,8 @@ class ChargeControl:
|
||||
self.retry_count = 0
|
||||
else:
|
||||
print(f"error when get vehicle info of {self.vin}")
|
||||
threading.Timer(periodicity, self.start).start()
|
||||
self.thread = threading.Timer(periodicity, self.start)
|
||||
self.thread.start()
|
||||
|
||||
def get_dict(self):
|
||||
chd = copy(self.__dict__)
|
||||
|
||||
+47
-41
@@ -13,6 +13,7 @@ from requests import Response
|
||||
import psa_connectedcar as psac
|
||||
from psa_connectedcar import ApiClient
|
||||
from psa_connectedcar.rest import ApiException
|
||||
from MyLogger import logger
|
||||
|
||||
oauhth_url = "https://idpcvs.peugeot.com/am/oauth2/access_token"
|
||||
remote_url = "https://api.groupe-psa.com/connectedcar/v4/virtualkey/remoteaccess/token?client_id="
|
||||
@@ -33,7 +34,7 @@ class OpenIdCredentialManager(CredentialManager):
|
||||
@staticmethod
|
||||
def _is_token_expired(response: Response) -> bool:
|
||||
if response.status_code == HTTPStatus.UNAUTHORIZED.value:
|
||||
print("token expired, renew")
|
||||
logger.info("token expired, renew")
|
||||
try:
|
||||
json_data = response.json()
|
||||
return json_data.get('moreInformation') == 'Token is invalid'
|
||||
@@ -42,8 +43,9 @@ class OpenIdCredentialManager(CredentialManager):
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
class Oauth2PSACCApiConfig(psac.Configuration):
|
||||
def set_refresh_callback(self,callback):
|
||||
def set_refresh_callback(self, callback):
|
||||
self.refresh_callback = callback
|
||||
|
||||
|
||||
@@ -54,15 +56,15 @@ class OauthAPIClient(ApiClient):
|
||||
response_type=None, auth_settings=None, async_req=None,
|
||||
_return_http_data_only=None, collection_formats=None,
|
||||
_preload_content=True, _request_timeout=None):
|
||||
for x in range(0,2):
|
||||
for x in range(0, 2):
|
||||
try:
|
||||
if not async_req:
|
||||
return self._ApiClient__call_api(resource_path, method,
|
||||
path_params, query_params, header_params,
|
||||
body, post_params, files,
|
||||
response_type, auth_settings,
|
||||
_return_http_data_only, collection_formats,
|
||||
_preload_content, _request_timeout)
|
||||
path_params, query_params, header_params,
|
||||
body, post_params, files,
|
||||
response_type, auth_settings,
|
||||
_return_http_data_only, collection_formats,
|
||||
_preload_content, _request_timeout)
|
||||
else:
|
||||
thread = self.pool.apply_async(self.__call_api, (resource_path,
|
||||
method, path_params, query_params,
|
||||
@@ -79,6 +81,7 @@ class OauthAPIClient(ApiClient):
|
||||
else:
|
||||
raise e
|
||||
|
||||
|
||||
def correlation_id(date):
|
||||
date_str = date.strftime("%Y%m%d%H%M%S%f")[:-3]
|
||||
uuid_str = str(uuid.uuid4()).replace("-", "")
|
||||
@@ -96,7 +99,8 @@ class MyPSACC:
|
||||
def connect(self, user, password):
|
||||
self.manager.init_with_user_credentials(user, password, realm)
|
||||
|
||||
def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, proxies=None, realm=realm):
|
||||
def __init__(self, refresh_token, client_id, client_secret, remote_refresh_token, customer_id, proxies=None,
|
||||
realm=realm):
|
||||
self.service_information = ServiceInformation('',
|
||||
oauhth_url,
|
||||
client_id,
|
||||
@@ -121,7 +125,7 @@ class MyPSACC:
|
||||
def refresh_token(self):
|
||||
self.manager._refresh_token()
|
||||
|
||||
def api(self) -> psac.VehiclesApi :
|
||||
def api(self) -> psac.VehiclesApi:
|
||||
self.api_config.access_token = self.manager._access_token
|
||||
api_instance = psac.VehiclesApi(OauthAPIClient(self.api_config))
|
||||
return api_instance
|
||||
@@ -135,11 +139,14 @@ class MyPSACC:
|
||||
self.api_config.proxy = proxies['http']
|
||||
self.manager.proxies = self._proxies
|
||||
|
||||
def getVehiculeinfo(self, vin):
|
||||
def get_vehicle_info(self, vin):
|
||||
res = self.api().get_vehicle_status(self.get_vehicle_id_with_vin(vin))
|
||||
# retry
|
||||
if res is None:
|
||||
res = self.api().get_vehicle_status(self.get_vehicle_id_with_vin(vin))
|
||||
return res
|
||||
|
||||
def newMonitor(self,vin,body):
|
||||
def newMonitor(self, vin, body):
|
||||
res = self.manager.post("https://api.groupe-psa.com/connectedcar/v4/user/vehicles/" + self.vehicles_list[vin][
|
||||
"id"] + "/status?client_id=" + self.client_id, headers=MyPSACC.headers, data=body)
|
||||
data = res.json()
|
||||
@@ -147,11 +154,11 @@ class MyPSACC:
|
||||
|
||||
def get_vehicles(self):
|
||||
|
||||
res =self.api().get_vehicles_by_device()
|
||||
res = self.api().get_vehicles_by_device()
|
||||
self.vehicles_list = {}
|
||||
for vehicle in res.embedded.vehicles:
|
||||
vin = vehicle.vin
|
||||
self.vehicles_list[vin] = {"id":vehicle.id}
|
||||
self.vehicles_list[vin] = {"id": vehicle.id}
|
||||
return self.vehicles_list
|
||||
|
||||
def get_vehicle_id_with_vin(self, vin):
|
||||
@@ -176,44 +183,44 @@ class MyPSACC:
|
||||
json={"grant_type": "refresh_token", "refresh_token": self.remote_refresh_token},
|
||||
headers=self.headers)
|
||||
data = res.json()
|
||||
print(data)
|
||||
logger.debug(f"refresh_remote_token: {data}")
|
||||
self.remote_access_token = data["access_token"]
|
||||
self.remote_refresh_token = data["refresh_token"]
|
||||
return data["access_token"], data["refresh_token"]
|
||||
|
||||
def on_mqtt_connect(self, client, userdata, rc, a):
|
||||
try:
|
||||
print("Connected with result code " + str(rc))
|
||||
topics = ["psa/RemoteServices/to/cid/" + self.customer_id + "/#" ]
|
||||
logger.info("Connected with result code " + str(rc))
|
||||
topics = ["psa/RemoteServices/to/cid/" + self.customer_id + "/#"]
|
||||
for vin in self.getVIN():
|
||||
topics.append("psa/RemoteServices/events/MPHRTServices/" + vin + "/#")
|
||||
for topic in topics:
|
||||
client.subscribe(topic)
|
||||
print("subscribe to "+topic)
|
||||
logger.info("subscribe to " + topic)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def on_mqtt_disconnect(self, client, userdata, rc):
|
||||
try:
|
||||
print("Disconnected with result code " + str(rc))
|
||||
logger.info("Disconnected with result code " + str(rc))
|
||||
# Subscribing in on_connect() means that if we lose the connection and
|
||||
# reconnect then subscriptions will be renewed.
|
||||
print(mqtt.error_string(rc))
|
||||
logger.info(mqtt.error_string(rc))
|
||||
except:
|
||||
traceback.print_exc()
|
||||
|
||||
def on_mqtt_message(self, client, userdata, msg):
|
||||
print(msg.topic + " " + str(msg.payload))
|
||||
logger.info(msg.topic + " " + str(msg.payload))
|
||||
try:
|
||||
data = json.loads(msg.payload)
|
||||
if data["return_code"] == 400:
|
||||
self.manager._refresh_token()
|
||||
self.refresh_remote_token()
|
||||
print("retry last request")
|
||||
logger.info("retry last request")
|
||||
except:
|
||||
print("mqtt msg hasn't return code")
|
||||
logger.info("mqtt msg hasn't return code")
|
||||
|
||||
def startmqtt(self):
|
||||
def start_mqtt(self):
|
||||
self.refresh_remote_token()
|
||||
self.mqtt_client = mqtt.Client(clean_session=True, protocol=mqtt.MQTTv311)
|
||||
self.mqtt_client.tls_set_context()
|
||||
@@ -224,6 +231,7 @@ class MyPSACC:
|
||||
self.mqtt_client.connect("mwa.mpsa.com", 8885, 60)
|
||||
self.mqtt_client.loop_start()
|
||||
return self.mqtt_client.is_connected()
|
||||
|
||||
def mqtt_request(self, vin, req_parameters):
|
||||
date = datetime.now()
|
||||
date_f = "%Y-%m-%dT%H:%M:%SZ"
|
||||
@@ -231,12 +239,12 @@ class MyPSACC:
|
||||
data = {"access_token": self.remote_access_token, "customer_id": self.customer_id,
|
||||
"correlation_id": correlation_id(date), "req_date": date_str, "vin": vin,
|
||||
"req_parameters": req_parameters}
|
||||
print(f"send mqtt msg: {data}")
|
||||
logger.info(f"send mqtt msg: {data}")
|
||||
return json.dumps(data)
|
||||
|
||||
def get_charge_hour(self, vin):
|
||||
reg = r"PT([0-9]{1,2})H([0-9]{1,2})?"
|
||||
data = self.getVehiculeinfo(vin)
|
||||
data = self.get_vehicle_info(vin)
|
||||
hour_str = data.energy[0]['charging']['nextDelayedTime']
|
||||
hour = re.findall(reg, hour_str)[0]
|
||||
h = int(hour[0])
|
||||
@@ -247,14 +255,14 @@ class MyPSACC:
|
||||
return h, m
|
||||
|
||||
def get_charge_status(self, vin):
|
||||
data = self.getVehiculeinfo(vin)
|
||||
data = self.get_vehicle_info(vin)
|
||||
status = data["energy"][0]['charging']['status']
|
||||
return status
|
||||
|
||||
def veh_charge_request(self, vin, hour, miinute, charge_type):
|
||||
# todo consider actual state before change the hour
|
||||
msg = self.mqtt_request(vin, {"program": {"hour": hour, "minute": miinute}, "type": charge_type})
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/VehCharge", msg)
|
||||
|
||||
def change_charge_hour(self, vin, hour, miinute):
|
||||
@@ -273,17 +281,17 @@ class MyPSACC:
|
||||
|
||||
def horn(self, vin, count):
|
||||
msg = self.mqtt_request(vin, {"nb_horn": count, "action": "activate"})
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/Horn", msg)
|
||||
|
||||
def lights(self, vin, duration: int):
|
||||
msg = self.mqtt_request(vin, {"action": "activate", "duration": duration})
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/Lights", msg)
|
||||
|
||||
def wakeup(self, vin):
|
||||
msg = self.mqtt_request(vin, {"action": "state"})
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/VehCharge/state", msg)
|
||||
return True
|
||||
|
||||
@@ -294,7 +302,7 @@ class MyPSACC:
|
||||
value = "unlock"
|
||||
|
||||
msg = self.mqtt_request(vin, {"action": value})
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/Doors", msg)
|
||||
return True
|
||||
|
||||
@@ -308,21 +316,20 @@ class MyPSACC:
|
||||
"program2": {"day": [0, 0, 0, 0, 0, 0, 0], "hour": 34, "minute": 7, "on": 0},
|
||||
"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}}})
|
||||
print(msg)
|
||||
logger.info(msg)
|
||||
self.mqtt_client.publish("psa/RemoteServices/from/cid/" + self.customer_id + "/ThermalPrecond", msg)
|
||||
return True
|
||||
|
||||
|
||||
def saveconfig(self,name="config.json",force=False):
|
||||
def save_config(self, name="config.json", force=False):
|
||||
config_str = json.dumps(self, cls=MyPuegeotEncoder, sort_keys=True, indent=4).encode("utf8")
|
||||
new_hash = md5(config_str).hexdigest()
|
||||
if force or self._confighash != new_hash :
|
||||
if force or self._confighash != new_hash:
|
||||
with open(name, "wb") as f:
|
||||
f.write(config_str)
|
||||
self._confighash = new_hash
|
||||
print("save config change")
|
||||
logger.info("save config change")
|
||||
|
||||
def loadconfig(name="config.json"):
|
||||
def load_config(name="config.json"):
|
||||
with open(name, "r") as f:
|
||||
str = f.read()
|
||||
return MyPSACC(**json.loads(str))
|
||||
@@ -334,9 +341,8 @@ class MyPuegeotEncoder(JSONEncoder):
|
||||
mpd["proxies"] = mpd["_proxies"]
|
||||
mpd["refresh_token"] = mp.manager.refresh_token
|
||||
mpd["client_secret"] = mp.service_information.client_secret
|
||||
for el in ["service_information", "manager", "mqtt_client", "vehicles_list", "_proxies", "remote_access_token","_confighash","api_config"]:
|
||||
for el in ["service_information", "manager", "mqtt_client", "vehicles_list", "_proxies", "remote_access_token",
|
||||
"_confighash", "api_config"]:
|
||||
if el in mpd:
|
||||
mpd.pop(el)
|
||||
return mpd
|
||||
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ We will retrieve those information:
|
||||
3. Test it
|
||||
|
||||
2.1 Get the car state :
|
||||
http://localhost:5000/get_vehiculeinfo/YOURVIN
|
||||
http://localhost:5000/get_vehicleinfo/YOURVIN
|
||||
|
||||
2.2 Stop charge
|
||||
http://localhost:5000/charge_now/YOURVIN/0
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ psacc = MyPSACC(None, client_id, client_secret, remote_refresh_token, customer_i
|
||||
psacc.connect(client_email, client_paswword)
|
||||
|
||||
os.chdir(current_dir)
|
||||
psacc.saveconfig(name="test.json")
|
||||
psacc.save_config(name="test.json")
|
||||
res = psacc.get_vehicles()
|
||||
print(f"\nYour vehicles: {res}")
|
||||
|
||||
|
||||
@@ -1,90 +1,104 @@
|
||||
import threading
|
||||
from datetime import timedelta
|
||||
from threading import Thread
|
||||
|
||||
from oauth2_client.credentials_manager import OAuthError
|
||||
|
||||
from ChargeControl import ChargeControls
|
||||
from MyLogger import my_logger
|
||||
from MyPSACC import *
|
||||
from flask import Flask, request, jsonify
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
from MyLogger import logger
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/getvehicules')
|
||||
|
||||
@app.route('/getvehicles')
|
||||
def getvehicules():
|
||||
return jsonify(myp.getVIN())
|
||||
|
||||
@app.route('/get_vehiculeinfo/<string:vin>')
|
||||
def getVehiculeInfo(vin):
|
||||
|
||||
@app.route('/get_vehicleinfo/<string:vin>')
|
||||
def get_vehicle_Info(vin):
|
||||
response = app.response_class(
|
||||
response=json.dumps(myp.getVehiculeinfo(vin).to_dict(),default=str),
|
||||
response=json.dumps(myp.get_vehicle_info(vin).to_dict(), default=str),
|
||||
status=200,
|
||||
mimetype='application/json'
|
||||
)
|
||||
return response
|
||||
|
||||
|
||||
@app.route('/charge_now/<string:vin>/<int:charge>')
|
||||
def chargeNow(vin,charge):
|
||||
return jsonify(myp.charge_now(vin,charge != 0 ))
|
||||
def charge_now(vin, charge):
|
||||
return jsonify(myp.charge_now(vin, charge != 0))
|
||||
|
||||
|
||||
@app.route('/charge_hour')
|
||||
def change_charge_hour():
|
||||
return jsonify(myp.change_charge_hour(request.form['vin'],request.form['hour'],request.form['minute']))
|
||||
return jsonify(myp.change_charge_hour(request.form['vin'], request.form['hour'], request.form['minute']))
|
||||
|
||||
|
||||
@app.route('/wakeup/<string:vin>')
|
||||
def wakeup(vin):
|
||||
return jsonify(myp.wakeup(vin))
|
||||
|
||||
|
||||
@app.route('/preconditioning/<string:vin>/<int:activate>')
|
||||
def preconditioning(vin, activate):
|
||||
return jsonify(myp.preconditioning(vin, activate))
|
||||
|
||||
def saveconfig(mypeugeot:MyPSACC):
|
||||
myp.saveconfig()
|
||||
threading.Timer(30, saveconfig, args=[mypeugeot]).start()
|
||||
|
||||
#Set a battery threshold and schedule an hour to stop the charge
|
||||
def save_config(mypeugeot: MyPSACC):
|
||||
myp.save_config()
|
||||
threading.Timer(30, save_config, args=[mypeugeot]).start()
|
||||
|
||||
|
||||
# Set a battery threshold and schedule an hour to stop the charge
|
||||
@app.route('/charge_control')
|
||||
def charge_control():
|
||||
print(request)
|
||||
logger.info(request)
|
||||
vin = request.args['vin']
|
||||
charge_control = chc.get(vin)
|
||||
if charge_control is None:
|
||||
return jsonify("error: VIN not in list")
|
||||
if 'hour' in request.args or 'minute' in request.args:
|
||||
charge_control.set_stop_hour([int(request.args["hour"]), int(request.args["minute"])])
|
||||
if 'percentage' in request.args :
|
||||
if 'percentage' in request.args:
|
||||
charge_control.percentage_threshold = int(request.args['percentage'])
|
||||
chc.saveconfig()
|
||||
chc.save_config()
|
||||
return jsonify(charge_control.get_dict())
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-f","--config", help="config file",type = argparse.FileType('r'))
|
||||
parser.add_argument("-c","--charge-control", help="enable charge control",const="charge_config.json", nargs='?')
|
||||
parser.add_argument("-f", "--config", help="config file", type=argparse.FileType('r'))
|
||||
parser.add_argument("-c", "--charge-control", help="enable charge control", const="charge_config.json", nargs='?')
|
||||
parser.add_argument("-d", "--debug", help="enable debug", const=10, default=20, nargs='?')
|
||||
parser.parse_args()
|
||||
return parser
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = parse_args()
|
||||
args = parser.parse_args()
|
||||
my_logger(handler_level=args.debug)
|
||||
logger.info("server start")
|
||||
if args.config:
|
||||
myp = MyPSACC.loadconfig(name=args.config.name)
|
||||
myp = MyPSACC.load_config(name=args.config.name)
|
||||
else:
|
||||
myp = MyPSACC.loadconfig()
|
||||
myp = MyPSACC.load_config()
|
||||
try:
|
||||
myp.manager._refresh_token()
|
||||
except OAuthError:
|
||||
client_email = input("mypeugeot email: ")
|
||||
client_paswword = input("mypeugeot password: ")
|
||||
myp.connect(client_email,client_paswword)
|
||||
print(myp.get_vehicles())
|
||||
myp.startmqtt()
|
||||
t1=Thread(target=app.run)
|
||||
myp.connect(client_email, client_paswword)
|
||||
logger.info(myp.get_vehicles())
|
||||
myp.start_mqtt()
|
||||
t1 = Thread(target=app.run)
|
||||
t1.start()
|
||||
saveconfig(myp)
|
||||
save_config(myp)
|
||||
if args.charge_control:
|
||||
chc = ChargeControls.load_config(myp,name=args.charge_control)
|
||||
chc = ChargeControls.load_config(myp, name=args.charge_control)
|
||||
chc.start()
|
||||
|
||||
Reference in New Issue
Block a user