Add datalogger

This commit is contained in:
marios8543 2024-05-07 18:23:39 +03:00
parent 4a69871468
commit ee90fa861e
5 changed files with 235 additions and 81 deletions

View File

@ -1,85 +1,103 @@
from mod_utils import chkDirTree
from mod_db_manager import find_DBs
from mod_elm import ELM
from mod_scan_ecus import ScanEcus
from mod_optfile import optfile
from mod_ecu import ECU
from mod_ply import Calc
from flask import Flask, jsonify, request, send_file
from flask_socketio import SocketIO
from rendash_main import RenDash
from csv import writer, QUOTE_MINIMAL
from datetime import datetime
from pickle import dump, load
from time import sleep
import mod_globals
mod_globals.opt_demo = True
from flask import Flask, make_response, request
dash = RenDash("/dev/tty1")
web = Flask(__name__)
socket = SocketIO(web)
from typing import List
watched_datarefs = []
watched_ecu = ""
should_log = False
freeze = 0
running = False
class RenDash:
def __init__(self,
elm_port,
elm_speed=38400,
model_number=58,
rescan=False) -> None:
chkDirTree()
find_DBs()
bg_thread = None
self.elm = ELM(elm_port, elm_speed, "")
self.lang = optfile("Location/DiagOnCAN_GB.bqm", False)
self.ecus: List[ECU] = []
self.current_ecu = None
def mainloop():
global running, watched_datarefs, watched_ecu, should_log, freeze
if should_log:
log_filename = f'{datetime.now().strftime("%m/%d/%Y, %H:%M:%S")}.csv'
print("Creating log on file: " + log_filename)
with open(log_filename, "w+") as file:
csv_writer = writer(file,delimiter=' ', quotechar='|', quoting=QUOTE_MINIMAL)
csv_writer.writerow(["freeze"].extend(watched_datarefs))
self.web = Flask(__name__)
print("Starting data loop")
while running:
frame = [dash.get_ecu_dataref(watched_ecu, dataref) for dataref in watched_datarefs]
socket.emit("frame", {"frame": frame})
if should_log:
csv_writer.writerow([freeze].extend(frame))
freeze = 0
print(frame)
if rescan is False:
try:
self.ecus = load(open("frozen_ecus.p", "rb"))
except Exception as e:
pass
if not self.ecus:
ecu_scanner = ScanEcus(self.elm)
ecu_scanner.chooseModel(model_number)
ecu_scanner.scanAllEcus()
for ecu in ecu_scanner.detectedEcus:
self.ecus.append(ECU(ecu, self.lang.dict))
dump(self.ecus, open("frozen_ecus.p", "wb+"))
@socket.on("freeze")
def freeze_event():
global freeze
for ecu in self.ecus:
setattr(ecu, "calc", Calc())
freeze = 1
def get_ecu_names(self):
return [ecu.ecudata["doc"] for ecu in self.ecus]
@web.get("/ecus")
def get_ecus():
ecus = dash.get_ecu_names()
return jsonify(ecus)
@web.get("/ecus/<ecu_doc>/states")
def get_ecu_states(ecu_doc):
return jsonify(dash.get_ecu_states(ecu_doc))
@web.get("/ecus/<ecu_doc>/parameters")
def get_ecu_parameters(ecu_doc):
return jsonify(dash.get_ecu_parameters(ecu_doc))
@web.post("/ecus/<ecu_doc>/watch")
def ecu_watch(ecu_doc):
global watched_ecu, watched_datarefs
datarefs = request.get_json()
watched_datarefs = []
for dataref in datarefs:
if dataref in dash.get_ecu_parameters(ecu_doc) \
or dataref in dash.get_ecu_states(ecu_doc):
watched_datarefs.append(dataref)
else:
watched_datarefs = []
raise ValueError("Invalid dataref")
watched_ecu = ecu_doc
return jsonify({"ecu": watched_ecu, "datarefs": watched_datarefs})
@web.get("/start")
def start():
global should_log, bg_thread, running
log = request.args.get("log")
if log == "true":
should_log = True
else:
should_log = False
def get_ecu_by_doc(self, doc):
for ecu in self.ecus:
if ecu.ecudata["doc"] == doc:
if self.current_ecu is not ecu:
ecu.initELM(self.elm)
self.current_ecu = ecu
return ecu
def get_ecu_states(self, doc):
ecu = self.get_ecu_by_doc(doc)
return ecu.Parameters
def get_ecu_state(self, doc, state):
ecu = self.get_ecu_by_doc(doc)
datastr = ecu.get_st(state)
return datastr
def get_ecu_param(self, doc, param):
ecu = self.get_ecu_by_doc(doc)
datastr = ecu.get_pr(param)
return datastr
running = True
bg_thread = socket.start_background_task(mainloop)
return jsonify({"success": True})
@web.get("/stop")
def stop():
global bg_thread, running
running = False
bg_thread.join()
return jsonify({"success": True})
@web.get("/")
def index():
return send_file("index.html")
if __name__ == "__main__":
rd = RenDash("/dev/tty0")
while True:
clearScreen()
for ecu_doc, values in REQUIRED_ECU_STATES.items():
for val in values:
if val.startswith("E"):
print(rd.get_ecu_state(ecu_doc, val))
elif val.startswith("P"):
print(rd.get_ecu_param(ecu_doc, val))
sleep(0.1)
socket.run(web, "0.0.0.0", 5000)

130
pyren3/index.html Normal file
View File

@ -0,0 +1,130 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ecu Watcher</title>
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
</head>
<body>
<div id="app">
<h1>Ecu Watcher</h1>
<div v-if="!ecuSelected">
<h2>Select ECU</h2>
<select v-model="selectedEcu" @change="fetchStatesAndParameters">
<option v-for="ecu in ecuList" :value="ecu" :key="ecu">
{{ ecu }}
</option>
</select>
</div>
<div v-else-if="!watching">
<h2>Selected ECU: {{ selectedEcu }}</h2>
<div>
<h2>States and Parameters</h2>
<div v-for="(text, code) in statesAndParams" :key="code">
<input type="checkbox" v-model="selectedItems" :value="code" />{{
text }}
</div>
<button @click="watch">Watch</button>
</div>
</div>
<div v-if="watching">
<h2>Watching</h2>
<div v-for="item in selectedItems" :key="item">
{{ statesAndParams[item] }}: {{ itemValues[item] }}
</div>
<button @click="startWatch">Start</button>
<button @click="stopWatch">Stop</button>
<label>
Log:
<input type="checkbox" v-model="logging" />
</label>
</div>
</div>
<script>
const socket = io();
const app = Vue.createApp({
data() {
return {
ecuList: [],
selectedEcu: "",
ecuSelected: false,
statesAndParams: {},
selectedItems: [],
itemValues: {},
watching: false,
logging: false,
};
},
methods: {
async fetchEcuList() {
try {
const response = await fetch("/ecus");
this.ecuList = await response.json();
} catch (error) {
console.error("Error fetching ECU list", error);
}
},
async fetchStatesAndParameters() {
try {
const response = await fetch(`/ecus/${this.selectedEcu}/states`);
const states = await response.json();
this.statesAndParams = { ...states };
const paramResponse = await fetch(
`/ecus/${this.selectedEcu}/parameters`
);
const parameters = await paramResponse.json();
for (const param in parameters) {
this.statesAndParams[param] = parameters[param];
}
this.ecuSelected = true;
} catch (error) {
console.error("Error fetching states and parameters", error);
}
},
async watch() {
try {
const response = await fetch(`/ecus/${this.selectedEcu}/watch`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(this.selectedItems),
});
if (response.ok) {
this.watching = true;
} else {
console.error("Error starting watch");
}
} catch (error) {
console.error("Error starting watch", error);
}
},
async stopWatch() {
await fetch(`/stop`, {
method: "GET",
});
},
async startWatch() {
await fetch(`/start?log=${this.logging ? "true" : "false"}`, {
method: "GET",
});
},
},
mounted() {
this.fetchEcuList();
socket.on("frame", (msg) => {
const data = msg.frame;
for (let i = 0; i < this.selectedItems.length; i++) {
this.itemValues[this.selectedItems[i]] = data[i];
}
});
},
});
app.mount("#app");
</script>
</body>
</html>

View File

@ -42,7 +42,7 @@ def get_parameter( pr, mn, se, elm, calc, dataids = {} ):
tmpmin = ''
tmpmax = ''
return "%-6s %-50s %5s %10s %-10s %-5s"%(pr.codeMR,pr.label,tmpmin,pr.value,pr.unit,tmpmax), pr.helps, csv_data
return "%5s %10s %-10s %-5s"%(tmpmin,pr.value,pr.unit,tmpmax), pr.helps, csv_data
class ecu_parameter:

View File

@ -29,7 +29,7 @@ def get_state( st, mn, se, elm, calc, dataids = {} ):
csv_val = str(st.value)
st.value = " "*(16-len(st.value)//2) + str(st.value)
return "%-6s %-50s %-20s"%(st.codeMR,st.label,st.value), st.helps, csv_val
return "%-20s"%(st.value), st.helps, csv_val
class ecu_state:

View File

@ -64,21 +64,27 @@ class RenDash:
def get_ecu_states(self, doc):
ecu = self.get_ecu_by_doc(doc)
return ecu.States
return {key: value.label for key,value in ecu.States.items()}
def get_ecu_parameters(self, doc):
ecu = self.get_ecu_by_doc(doc)
return ecu.Parameters
return {key: value.label for key,value in ecu.Parameters.items()}
def get_ecu_state(self, doc, state):
ecu = self.get_ecu_by_doc(doc)
datastr, help, csvd = get_state(ecu.States[state], ecu.Mnemonics, ecu.Services, self.elm, ecu.calc)
return datastr
return ecu.get_st(state)
def get_ecu_param(self, doc, param):
ecu = self.get_ecu_by_doc(doc)
datastr, help, csvd = get_parameter(ecu.Parameters[param], ecu.Mnemonics, ecu.Services, self.elm, ecu.calc)
return datastr
return ecu.get_pr(param)
def get_ecu_dataref(self, doc, dataref: str):
if dataref.startswith("E"):
return self.get_ecu_state(doc, dataref)
elif dataref.startswith("P"):
return self.get_ecu_param(doc, dataref)
else:
raise ValueError("Invalid dataref")
if __name__ == "__main__":
rd = RenDash("/dev/ttyS5")