Implement a modular vehicle decoding system
- Add Komatsu specific rules - Possibility to expand to any brand
This commit is contained in:
@@ -11,6 +11,7 @@ import dash
|
||||
from dash import dcc, html, Input, Output, State
|
||||
import dash_bootstrap_components as dbc
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
from parser import parse_log, parse_csv
|
||||
from decoder import decode_j1939_frames
|
||||
@@ -20,6 +21,7 @@ from stats.frequency import calculate_frequency, plot_frequency
|
||||
from stats.correlation import calculate_correlation, plot_correlation_heatmap
|
||||
from stats.entropy import calculate_byte_entropy, plot_entropy_heatmap
|
||||
from logs.view import get_logs_table_component, prepare_logs_data
|
||||
from vehicle import get_vehicle_module
|
||||
|
||||
RAW_LOG_DIR = "data/logs"
|
||||
PAGE_SIZE = 25000
|
||||
@@ -131,6 +133,18 @@ app.layout = dbc.Container([
|
||||
dbc.Tab(label="Overview", tab_id="overview", children=[
|
||||
html.Div(id="overview-content")
|
||||
]),
|
||||
dbc.Tab(label="Vehicles", tab_id="vehicles", children=[
|
||||
dbc.Row([
|
||||
dbc.Col(html.Label("Select Vehicle:", className="mt-2"), width="auto"),
|
||||
dbc.Col(dcc.Dropdown(
|
||||
id='vehicles-vehicle-selector',
|
||||
options=[{'label': v, 'value': v} for v in DATA.keys()],
|
||||
value=list(DATA.keys())[0] if DATA else None,
|
||||
clearable=False
|
||||
), width=3, className="me-4"),
|
||||
], className="mb-3 mt-3", align="end"),
|
||||
html.Div(id='vehicles-content', className="mt-3")
|
||||
]),
|
||||
dbc.Tab(label="Logs", tab_id="logs", children=[
|
||||
dbc.Row([
|
||||
dbc.Col(html.Label("Select Vehicle:", className="mt-2"), width="auto"),
|
||||
@@ -391,5 +405,58 @@ def update_corr(method, target, vehicle, bus, tab):
|
||||
|
||||
return plot_correlation_heatmap(corr_df, target_id=target_id, title=title)
|
||||
|
||||
@app.callback(
|
||||
Output('vehicles-content', 'children'),
|
||||
Input('vehicles-vehicle-selector', 'value')
|
||||
)
|
||||
def render_vehicles(vehicle):
|
||||
"""Render small graph boxes for every decoded signal, combining both buses."""
|
||||
if not vehicle or vehicle not in DATA:
|
||||
return html.Div("No data available", className="text-muted")
|
||||
|
||||
brand = VEHICLE_META.get(vehicle, {}).get("brand", "")
|
||||
|
||||
vehicle_module = get_vehicle_module(brand)
|
||||
|
||||
dfs = []
|
||||
for bus_df in DATA[vehicle].values():
|
||||
dfs.append(bus_df)
|
||||
|
||||
if not dfs:
|
||||
return html.Div("No data available", className="text-muted")
|
||||
|
||||
df = pd.concat(dfs, ignore_index=True)
|
||||
|
||||
if 'Timestamp' in df.columns:
|
||||
df = df.sort_values('Timestamp', kind='stable').reset_index(drop=True)
|
||||
|
||||
cards = []
|
||||
for nid, frame_def in vehicle_module.DECODER_RULES.items():
|
||||
decoded = vehicle_module.decode_dataframe(df, frame_def.can_id)
|
||||
|
||||
for sig in frame_def.signals:
|
||||
unit_str = f" ({sig.unit})" if sig.unit else ""
|
||||
title = f"{frame_def.can_id} - {sig.name}{unit_str}"
|
||||
fig = vehicle_module.plot_signal(decoded, sig.name, title=title)
|
||||
|
||||
card = dbc.Card([
|
||||
dbc.CardBody([
|
||||
dcc.Graph(figure=fig, config={'displayModeBar': False},
|
||||
style={'height': '280px'})
|
||||
], className="p-2"),
|
||||
], className="shadow-sm border-0 h-100")
|
||||
|
||||
cards.append(
|
||||
dbc.Col(card, xs=12, sm=6, md=4, lg=3, className="mb-3")
|
||||
)
|
||||
|
||||
if not cards:
|
||||
return html.Div(
|
||||
"No decoded signals available. Add rules in the vehicle module.",
|
||||
className="text-muted"
|
||||
)
|
||||
|
||||
return dbc.Row(cards)
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=False)
|
||||
|
||||
Reference in New Issue
Block a user