Feature abrp (#79)

* add ABRP connection

* update doc

* fix get_last_temp()

* add image

* update abrp

* fix abrpname

* fix no last postition

* add type point

* find model by vin

* add Spacetourer

* fix indent
This commit is contained in:
Florian BEZANNIER
2021-04-13 12:48:37 +02:00
committed by GitHub
parent e2327768b5
commit 25b86c0149
14 changed files with 342 additions and 108 deletions
+51
View File
@@ -0,0 +1,51 @@
import json
import traceback
from datetime import datetime
import requests
from Car import Car
from MyLogger import logger
class Abrp:
api_key = "1e28ad14-df16-49f0-97da-364c9154b44a"
url = "https://api.iternio.com/1/tlm/send"
def __init__(self, token: str = "", abrp_enable_vin=None):
if abrp_enable_vin is None:
abrp_enable_vin = list()
self.token = token
self.abrp_enable_vin = set(abrp_enable_vin)
self.proxies = None
def call(self, car: Car, ext_temp: float = None):
try:
if self.token is None or len(self.token) == 0:
logger.error("No 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.error(traceback.format_exc())
return False
def __iter__(self):
yield "abrp_enable_vin", list(self.abrp_enable_vin)
yield "token", self.token
+9
View File
@@ -46,3 +46,12 @@ def clean_position(conn):
logger.debug("Delete duplicate line")
conn.execute("DELETE FROM position where Timestamp=?;", (res[1]["Timestamp"],))
conn.commit()
def get_last_temp(vin):
conn = get_db()
res = conn.execute("SELECT temperature FROM position WHERE VIN=? ORDER BY Timestamp DESC limit 1",
(vin,)).fetchone()
if res is None:
return None
return res[0]
+2 -2
View File
@@ -173,10 +173,10 @@ def get_figures(trips: Trips, charging: Tuple[dict]):
y=consumption_by_temp_df["consumption_km"], name="Trips"))
consumption_fig_by_temp.update_layout(xaxis_title="average temperature in °C",
yaxis_title="Consumption kWh/100Km")
consumption_graph_by_temp = Graph(figure=consumption_fig_by_temp, id="consumption_fig_by_temp")
consumption_graph_by_temp = html.Div(Graph(figure=consumption_fig_by_temp), id="consumption_graph_by_temp")
else:
consumption_graph_by_temp = Graph(style={'display': 'none'})
consumption_graph_by_temp = html.Div(Graph(style={'display': 'none'}), id="consumption_graph_by_temp")
def __calculate_co2_per_kw(charging_data):
+59 -4
View File
@@ -2,9 +2,10 @@ import json
import traceback
from datetime import datetime, timezone
import dash_bootstrap_components as dbc
from dash.dependencies import Output, Input
from dash.dependencies import Output, Input, MATCH
import dash_core_components as dcc
import dash_html_components as html
import dash_daq as daq
from MyLogger import logger
from flask import jsonify, request, Response as FlaskResponse
@@ -16,6 +17,12 @@ from web import figures
from web.app import app, dash_app, myp, chc
import web.db
RESPONSE = "-response"
EMPTY_DIV = "empty-div"
ABRP_SWITCH = 'abrp-switch'
ERROR_DIV = dbc.Alert("No data to show, there is probably no trips recorded yet", color="danger")
trips: Trips
chargings: dict
@@ -25,7 +32,7 @@ min_date = max_date = min_millis = max_millis = step = marks = cached_layout = N
@dash_app.callback(Output('trips_map', 'figure'),
Output('consumption_fig', 'figure'),
Output('consumption_fig_by_speed', 'figure'),
Output('consumption_fig_by_temp', 'graph'),
Output('consumption_graph_by_temp', 'children'),
Output('consumption', 'children'),
Output('tab_trips', 'children'),
Output('tab_battery', 'children'),
@@ -49,6 +56,19 @@ def display_value(value):
figures.battery_table, max_millis, step, marks
@dash_app.callback(Output({'role': ABRP_SWITCH + RESPONSE, 'vin': MATCH}, 'children'),
Input({'role': ABRP_SWITCH, 'vin': MATCH}, 'id'),
Input({'role': ABRP_SWITCH, 'vin': MATCH}, 'value'))
def update_abrp(div_id, value):
vin = div_id["vin"]
if value:
myp.abrp.abrp_enable_vin.add(vin)
else:
myp.abrp.abrp_enable_vin.discard(vin)
myp.save_config()
return " "
@app.route('/get_vehicles')
def get_vehicules():
response = app.response_class(
@@ -127,6 +147,21 @@ def get_recorded_position():
return FlaskResponse(myp.get_recorded_position(), mimetype='application/json')
@app.route('/abrp')
def abrp():
vin = request.args.get('vin', None)
enable = request.args.get('enable', None)
token = request.args.get('token', None)
if vin is not None and enable is not None:
if enable == '1':
myp.abrp.abrp_enable_vin.add(vin)
else:
myp.abrp.abrp_enable_vin.discard(vin)
if token is not None:
myp.abrp.token = token
return jsonify(dict(myp.abrp))
@app.after_request
def after_request(response):
header = response.headers
@@ -160,6 +195,25 @@ def update_trips():
logger.error("update_trips (slider): %s", traceback.format_exc())
return
def __get_control_tabs():
tabs = []
for car in myp.vehicles_list:
if car.label is None:
label = car.vin
else:
label = car.label
tabs.append(dbc.Tab(label=label, id="tab-" + car.vin, children=[
daq.ToggleSwitch(
id={'role': ABRP_SWITCH, 'vin': car.vin},
value=car.vin in myp.abrp.abrp_enable_vin,
label="Send data to ABRP"
),
html.Div(id={'role': ABRP_SWITCH + RESPONSE, 'vin': car.vin})
]))
return tabs
def serve_layout():
global cached_layout
if cached_layout is None:
@@ -188,13 +242,14 @@ def serve_layout():
dbc.Tab(label="Charge", tab_id="charge", id="tab_charge", children=[figures.battery_table]),
dbc.Tab(label="Map", tab_id="map", children=[
dcc.Graph(figure=figures.trips_map, id="trips_map", style={"height": '90vh'})]),
dbc.Tab(label="Control", tab_id="control", children=dbc.Tabs(id="control-tabs",
children=__get_control_tabs()))
],
id="tabs",
active_tab="summary",
),
html.Div(id="tab-content", className="p-4"),
html.Div(id=EMPTY_DIV),
])])
except (IndexError, TypeError, NameError):
logger.warning("Failed to generate figure, there is probably not enough data yet")
logger.debug(traceback.format_exc())