From eb8895966017355774c72faff2aabc3c06afc16f Mon Sep 17 00:00:00 2001 From: Kirubakaran Date: Sat, 20 Sep 2025 21:14:30 +0530 Subject: [PATCH] fix: analytics page --- backend/main.py | 350 +++++++++++------- .../vec_payload_chgSt_pb2.cpython-313.pyc | Bin 6107 -> 6145 bytes backend/proto/vec_payload_chgSt.proto | 1 + backend/proto/vec_payload_chgSt_pb2.py | 30 +- backend/proto/vec_payload_chgSt_pb2.pyi | 2 + frontend/analytics.html | 40 +- frontend/js/analytics.js | 51 ++- frontend/js/auth.js | 2 +- frontend/js/common-header.js | 4 +- frontend/js/dashboard.js | 54 ++- frontend/js/logs.js | 342 +++++------------ frontend/js/station_selection.js | 6 +- frontend/station_selection.html | 2 +- 13 files changed, 439 insertions(+), 445 deletions(-) diff --git a/backend/main.py b/backend/main.py index 6bba16e..1765553 100644 --- a/backend/main.py +++ b/backend/main.py @@ -39,7 +39,7 @@ app = Flask(__name__) # CORS(app, resources={r"/api/*": {"origins": "http://127.0.0.1:5500"}}, supports_credentials=True, expose_headers='Content-Disposition') -CORS(app, resources={r"/api/*": {"origins": ["http://192.168.1.12:5500","http://127.0.0.1:5500"]}}, supports_credentials=True, expose_headers='Content-Disposition') +CORS(app, resources={r"/api/*": {"origins": ["http://10.10.1.183:5500","http://127.0.0.1:5500"]}}, supports_credentials=True, expose_headers='Content-Disposition') # CORS(app, resources={r"/api/*": {"origins": "http://localhost:5173"}}) , "http://127.0.0.1:5500" # This tells Flask: "For any route starting with /api/, allow requests @@ -66,52 +66,8 @@ mqtt_clients = {} last_message_timestamps = {} STATION_TIMEOUT_SECONDS = 10 -# --- MQTT Message Handling --- -def on_message_handler(station_id, topic, payload): + - message_type = topic.split('/')[-1] - - if message_type in ['PERIODIC']: - last_message_timestamps[station_id] = time.time() - - print(f"Main handler received message for station {station_id} on topic {topic}") - - decoded_data = None - message_type = topic.split('/')[-1] - - if message_type == 'PERIODIC': - decoded_data = decoder.decode_periodic(payload) - elif message_type == 'EVENTS': - decoded_data = decoder.decode_event(payload) - elif message_type == 'REQUEST': - decoded_data = decoder.decode_rpc_request(payload) - - if decoded_data: - # print("DECODED DATA TO BE SENT:", decoded_data) - try: - with app.app_context(): - log_entry = MqttLog( - station_id=station_id, - topic=topic, - topic_type=message_type, - payload=decoded_data - ) - db.session.add(log_entry) - db.session.commit() - print(f"Successfully wrote data for {station_id} to PostgreSQL.") - except Exception as e: - print(f"Error writing to PostgreSQL: {e}") - - socketio.emit('dashboard_update', { - 'stationId': station_id, - 'topic': topic, - 'data': decoded_data - }, room=station_id) - - # If the message is an EVENT or PERIODIC data, it could affect analytics. - if message_type in ['EVENTS', 'PERIODIC']: - print(f"Analytics-related data received ({message_type}). Notifying clients to refresh.") - socketio.emit('analytics_updated', room=station_id) # --- (WebSocket and API routes remain the same) --- @socketio.on('connect') @@ -310,15 +266,20 @@ def get_all_station_stats(): print(f"Error fetching daily stats: {e}") return jsonify({"message": "Could not fetch daily station stats."}), 500 - + @app.route('/api/logs/recent/', methods=['GET']) def get_recent_logs(station_id): """ - Fetches the 50 most recent logs for a given station from the database. + Fetches the 50 most recent non-periodic (EVENTS and REQUEST) logs for a + given station from the database. """ try: - # Query the MqttLog table, filter by station_id, order by timestamp descending, and take the first 50 - logs = MqttLog.query.filter_by(station_id=station_id).order_by(desc(MqttLog.timestamp)).limit(50).all() + # --- THIS IS THE FIX --- + # Query the MqttLog table, filtering for only EVENTS and REQUEST topic types. + logs = MqttLog.query.filter( + MqttLog.station_id == station_id, + MqttLog.topic_type.in_(['EVENTS', 'REQUEST']) + ).order_by(desc(MqttLog.timestamp)).limit(50).all() # We reverse the list so the oldest are first, for correct display order logs.reverse() @@ -348,9 +309,157 @@ ABORT_REASON_MAP = { } #--- Analytics Route --- +# @app.route('/api/analytics', methods=['GET']) +# def get_analytics_data(): +# # 1. Get and validate request parameters (same as before) +# station_id = request.args.get('station_id') +# start_date_str = request.args.get('start_date') +# end_date_str = request.args.get('end_date') + +# if not all([station_id, start_date_str, end_date_str]): +# return jsonify({"message": "Missing required parameters."}), 400 + +# try: +# start_date = datetime.strptime(start_date_str, '%Y-%m-%d').date() +# end_date = datetime.strptime(end_date_str, '%Y-%m-%d').date() +# start_datetime = datetime.combine(start_date, datetime.min.time()) +# end_datetime = datetime.combine(end_date, datetime.max.time()) +# except ValueError: +# return jsonify({"message": "Invalid date format. Please use YYYY-MM-DD."}), 400 + +# # 2. Query for EVENT logs (for swap calculations) +# try: +# event_logs = MqttLog.query.filter( +# MqttLog.station_id == station_id, +# MqttLog.topic_type == 'EVENTS', +# MqttLog.timestamp.between(start_datetime, end_datetime) +# ).order_by(MqttLog.timestamp.asc()).all() # <-- ADD THIS SORTING +# except Exception as e: +# return jsonify({"message": f"Could not query event logs: {e}"}), 500 + +# # --- NEW: Query for PERIODIC logs (for uptime calculation) --- +# try: +# periodic_logs = MqttLog.query.filter( +# MqttLog.station_id == station_id, +# MqttLog.topic_type == 'PERIODIC', +# MqttLog.timestamp.between(start_datetime, end_datetime) +# ).order_by(MqttLog.timestamp.asc()).all() +# except Exception as e: +# return jsonify({"message": f"Could not query periodic logs: {e}"}), 500 + +# # --- 3. REVISED: Process logs to calculate KPIs and chart data --- +# swap_starts = {} # Dictionary to store start times by sessionId +# completed_swap_times = [] + +# total_swaps, completed_swaps, aborted_swaps = 0, 0, 0 +# daily_completed, daily_aborted, hourly_swaps, abort_reason_counts = {}, {}, [0] * 24, {} +# slot_utilization_counts = {i: 0 for i in range(1, 10)} + +# print("\n--- STARTING SWAP ANALYSIS ---") # Add this line +# for log in event_logs: +# event_type = log.payload.get('eventType') +# session_id = log.payload.get('sessionId') +# log_date = log.timestamp.date() +# log_hour = log.timestamp.hour + +# if event_type == 'EVENT_SWAP_START': +# total_swaps += 1 +# hourly_swaps[log_hour] += 1 +# if session_id: +# swap_starts[session_id] = log.timestamp # Store start time +# print(f"Found START for session '{session_id}' at {log.timestamp}") # Add this line + +# elif event_type == 'EVENT_SWAP_ENDED': +# completed_swaps += 1 +# daily_completed[log_date] = daily_completed.get(log_date, 0) + 1 +# if session_id and session_id in swap_starts: +# # Calculate duration if we have a matching start event +# duration = (log.timestamp - swap_starts[session_id]).total_seconds() +# completed_swap_times.append(duration) +# print(f"Found MATCHING END for session '{session_id}'. Duration: {duration}s") # Add this line +# del swap_starts[session_id] # Remove to prevent reuse +# else: +# print(f"Found END event but could not find matching START for session '{session_id}'") # Add this line + +# elif event_type == 'EVENT_SWAP_ABORTED': +# aborted_swaps += 1 +# daily_aborted[log_date] = daily_aborted.get(log_date, 0) + 1 +# reason = log.payload.get('eventData', {}).get('swapAbortReason', 'ABORT_UNKNOWN') +# abort_reason_counts[reason] = abort_reason_counts.get(reason, 0) + 1 + +# elif event_type == 'EVENT_BATTERY_EXIT': +# slot_id = log.payload.get('eventData', {}).get('slotId') +# if slot_id and slot_id in slot_utilization_counts: +# slot_utilization_counts[slot_id] += 1 + +# print(f"--- ANALYSIS COMPLETE ---") # Add this line +# print(f"Calculated Durations: {completed_swap_times}") # Add this line + +# # --- NEW: 4. Calculate Station Uptime --- +# total_period_seconds = (end_datetime - start_datetime).total_seconds() +# total_downtime_seconds = 0 +# MAX_ONLINE_GAP_SECONDS = 30 # Assume offline if no message for over 30 seconds + +# if not periodic_logs: +# total_downtime_seconds = total_period_seconds +# else: +# # Check gap from start time to first message +# first_gap = (periodic_logs[0].timestamp - start_datetime).total_seconds() +# if first_gap > MAX_ONLINE_GAP_SECONDS: +# total_downtime_seconds += first_gap + +# # Check gaps between consecutive messages +# for i in range(1, len(periodic_logs)): +# gap = (periodic_logs[i].timestamp - periodic_logs[i-1].timestamp).total_seconds() +# if gap > MAX_ONLINE_GAP_SECONDS: +# total_downtime_seconds += gap + +# # Check gap from last message to end time +# last_gap = (end_datetime - periodic_logs[-1].timestamp).total_seconds() +# if last_gap > MAX_ONLINE_GAP_SECONDS: +# total_downtime_seconds += last_gap + +# station_uptime = 100 * (1 - (total_downtime_seconds / total_period_seconds)) +# station_uptime = max(0, min(100, station_uptime)) # Ensure value is between 0 and 100 + +# # 5. Prepare final data structures (KPI section is now updated) +# avg_swap_time_seconds = sum(completed_swap_times) / len(completed_swap_times) if completed_swap_times else 0 + +# # avg_swap_time_seconds = sum(completed_swap_times) / len(completed_swap_times) if completed_swap_times else None + +# kpi_data = { +# "total_swaps": total_swaps, "completed_swaps": completed_swaps, +# "aborted_swaps": aborted_swaps, "avg_swap_time_seconds": avg_swap_time_seconds, +# "station_uptime": round(station_uptime, 2) # Add uptime to the KPI object +# } + +# # (The rest of the chart data preparation is unchanged) +# date_labels, completed_data, aborted_data = [], [], [] +# current_date = start_date +# while current_date <= end_date: +# date_labels.append(current_date.strftime('%b %d')) +# completed_data.append(daily_completed.get(current_date, 0)) +# aborted_data.append(daily_aborted.get(current_date, 0)) +# current_date += timedelta(days=1) + +# swap_activity_data = {"labels": date_labels, "completed_data": completed_data, "aborted_data": aborted_data} +# hourly_distribution_data = {"labels": [f"{h % 12 if h % 12 != 0 else 12} {'AM' if h < 12 else 'PM'}" for h in range(24)], "swap_data": hourly_swaps} +# abort_reasons_data = {"labels": [ABORT_REASON_MAP.get(r, r) for r in abort_reason_counts.keys()], "reason_data": list(abort_reason_counts.values())} +# slot_utilization_data = {"counts": [slot_utilization_counts[i] for i in range(1, 10)]} # Return counts as a simple list [_ , _, ...] + +# # 6. Combine all data and return +# return jsonify({ +# "kpis": kpi_data, +# "swap_activity": swap_activity_data, +# "hourly_distribution": hourly_distribution_data, +# "abort_reasons": abort_reasons_data, +# "slot_utilization": slot_utilization_data # <-- ADD THIS NEW KEY +# }) + + @app.route('/api/analytics', methods=['GET']) def get_analytics_data(): - # 1. Get and validate request parameters (same as before) + # 1. Get and validate request parameters station_id = request.args.get('station_id') start_date_str = request.args.get('start_date') end_date_str = request.args.get('end_date') @@ -366,103 +475,66 @@ def get_analytics_data(): except ValueError: return jsonify({"message": "Invalid date format. Please use YYYY-MM-DD."}), 400 - # 2. Query for EVENT logs (for swap calculations) + # 2. Query for ALL relevant logs (EVENTS and REQUESTS) in one go try: - event_logs = MqttLog.query.filter( + logs = MqttLog.query.filter( MqttLog.station_id == station_id, - MqttLog.topic_type == 'EVENTS', + MqttLog.topic_type.in_(['EVENTS', 'REQUEST']), MqttLog.timestamp.between(start_datetime, end_datetime) - ).order_by(MqttLog.timestamp.asc()).all() # <-- ADD THIS SORTING - except Exception as e: - return jsonify({"message": f"Could not query event logs: {e}"}), 500 - - # --- NEW: Query for PERIODIC logs (for uptime calculation) --- - try: + ).order_by(MqttLog.timestamp.asc()).all() + periodic_logs = MqttLog.query.filter( MqttLog.station_id == station_id, MqttLog.topic_type == 'PERIODIC', MqttLog.timestamp.between(start_datetime, end_datetime) ).order_by(MqttLog.timestamp.asc()).all() except Exception as e: - return jsonify({"message": f"Could not query periodic logs: {e}"}), 500 + return jsonify({"message": f"Could not query logs: {e}"}), 500 - # # 3. Process EVENT logs for swap KPIs and charts - # total_swaps, completed_swaps, aborted_swaps = 0, 0, 0 - # completed_swap_times, daily_completed, daily_aborted, hourly_swaps, abort_reason_counts = [], {}, {}, [0] * 24, {} - # slot_utilization_counts = {i: 0 for i in range(1, 10)} # For the heatmap - - # for log in event_logs: - # # (This processing logic is unchanged) - # event_type = log.payload.get('eventType') - # log_date = log.timestamp.date() - # log_hour = log.timestamp.hour - # if event_type == 'EVENT_SWAP_START': - # total_swaps += 1 - # hourly_swaps[log_hour] += 1 - # elif event_type == 'EVENT_SWAP_ENDED': - # completed_swaps += 1 - # daily_completed[log_date] = daily_completed.get(log_date, 0) + 1 - # swap_time = log.payload.get('eventData', {}).get('swapTime') - # if swap_time is not None: - # completed_swap_times.append(swap_time) - # elif event_type == 'EVENT_SWAP_ABORTED': - # aborted_swaps += 1 - # daily_aborted[log_date] = daily_aborted.get(log_date, 0) + 1 - # reason = log.payload.get('eventData', {}).get('swapAbortReason', 'ABORT_UNKNOWN') - # abort_reason_counts[reason] = abort_reason_counts.get(reason, 0) + 1 - # elif event_type == 'EVENT_BATTERY_EXIT': - # slot_id = log.payload.get('eventData', {}).get('slotId') - # if slot_id and slot_id in slot_utilization_counts: - # slot_utilization_counts[slot_id] += 1 - - # --- 3. REVISED: Process logs to calculate KPIs and chart data --- - swap_starts = {} # Dictionary to store start times by sessionId + # 3. Initialize data structures for processing + swap_starts_map = {} completed_swap_times = [] - total_swaps, completed_swaps, aborted_swaps = 0, 0, 0 + total_initiations = 0 + total_starts = 0 + completed_swaps = 0 + aborted_swaps = 0 + daily_completed, daily_aborted, hourly_swaps, abort_reason_counts = {}, {}, [0] * 24, {} slot_utilization_counts = {i: 0 for i in range(1, 10)} - print("\n--- STARTING SWAP ANALYSIS ---") # Add this line - for log in event_logs: + # 4. Process the logs to calculate all KPIs and chart data + for log in logs: event_type = log.payload.get('eventType') + job_type = log.payload.get('jobType') session_id = log.payload.get('sessionId') log_date = log.timestamp.date() log_hour = log.timestamp.hour - if event_type == 'EVENT_SWAP_START': - total_swaps += 1 + if job_type == 'JOBTYPE_SWAP_AUTH_SUCCESS': + total_initiations += 1 + elif event_type == 'EVENT_SWAP_START': + total_starts += 1 hourly_swaps[log_hour] += 1 if session_id: - swap_starts[session_id] = log.timestamp # Store start time - print(f"Found START for session '{session_id}' at {log.timestamp}") # Add this line - + swap_starts_map[session_id] = log.timestamp elif event_type == 'EVENT_SWAP_ENDED': completed_swaps += 1 daily_completed[log_date] = daily_completed.get(log_date, 0) + 1 - if session_id and session_id in swap_starts: - # Calculate duration if we have a matching start event - duration = (log.timestamp - swap_starts[session_id]).total_seconds() + if session_id and session_id in swap_starts_map: + duration = (log.timestamp - swap_starts_map[session_id]).total_seconds() completed_swap_times.append(duration) - print(f"Found MATCHING END for session '{session_id}'. Duration: {duration}s") # Add this line - del swap_starts[session_id] # Remove to prevent reuse - else: - print(f"Found END event but could not find matching START for session '{session_id}'") # Add this line - + del swap_starts_map[session_id] elif event_type == 'EVENT_SWAP_ABORTED': aborted_swaps += 1 daily_aborted[log_date] = daily_aborted.get(log_date, 0) + 1 reason = log.payload.get('eventData', {}).get('swapAbortReason', 'ABORT_UNKNOWN') abort_reason_counts[reason] = abort_reason_counts.get(reason, 0) + 1 - elif event_type == 'EVENT_BATTERY_EXIT': slot_id = log.payload.get('eventData', {}).get('slotId') if slot_id and slot_id in slot_utilization_counts: slot_utilization_counts[slot_id] += 1 - print(f"--- ANALYSIS COMPLETE ---") # Add this line - print(f"Calculated Durations: {completed_swap_times}") # Add this line - # --- NEW: 4. Calculate Station Uptime --- total_period_seconds = (end_datetime - start_datetime).total_seconds() total_downtime_seconds = 0 @@ -490,35 +562,18 @@ def get_analytics_data(): station_uptime = 100 * (1 - (total_downtime_seconds / total_period_seconds)) station_uptime = max(0, min(100, station_uptime)) # Ensure value is between 0 and 100 - # if not periodic_logs: - # total_downtime_seconds = total_period_seconds - # else: - # first_gap = (periodic_logs[0].timestamp - start_datetime).total_seconds() - # if first_gap > MAX_ONLINE_GAP_SECONDS: - # total_downtime_seconds += first_gap - # for i in range(1, len(periodic_logs)): - # gap = (periodic_logs[i].timestamp - periodic_logs[i-1].timestamp).total_seconds() - # if gap > MAX_ONLINE_GAP_SECONDS: - # total_downtime_seconds += gap - # last_gap = (end_datetime - periodic_logs[-1].timestamp).total_seconds() - # if last_gap > MAX_ONLINE_GAP_SECONDS: - # total_downtime_seconds += last_gap - # station_uptime = 100 * (1 - (total_downtime_seconds / total_period_seconds)) - # station_uptime = max(0, min(100, station_uptime)) - - - # 5. Prepare final data structures (KPI section is now updated) - avg_swap_time_seconds = sum(completed_swap_times) / len(completed_swap_times) if completed_swap_times else 0 - - # avg_swap_time_seconds = sum(completed_swap_times) / len(completed_swap_times) if completed_swap_times else None - - kpi_data = { - "total_swaps": total_swaps, "completed_swaps": completed_swaps, - "aborted_swaps": aborted_swaps, "avg_swap_time_seconds": avg_swap_time_seconds, - "station_uptime": round(station_uptime, 2) # Add uptime to the KPI object - } + # 6. Prepare final data structures + avg_swap_time_seconds = sum(completed_swap_times) / len(completed_swap_times) if completed_swap_times else None - # (The rest of the chart data preparation is unchanged) + kpi_data = { + "total_swaps_initiated": total_initiations, + "total_swaps_started": total_starts, + "completed_swaps": completed_swaps, + "aborted_swaps": aborted_swaps, + "avg_swap_time_seconds": avg_swap_time_seconds, + "station_uptime": round(station_uptime, 2) + } + date_labels, completed_data, aborted_data = [], [], [] current_date = start_date while current_date <= end_date: @@ -532,13 +587,14 @@ def get_analytics_data(): abort_reasons_data = {"labels": [ABORT_REASON_MAP.get(r, r) for r in abort_reason_counts.keys()], "reason_data": list(abort_reason_counts.values())} slot_utilization_data = {"counts": [slot_utilization_counts[i] for i in range(1, 10)]} # Return counts as a simple list [_ , _, ...] - # 6. Combine all data and return + + # 7. Combine all data and return return jsonify({ "kpis": kpi_data, "swap_activity": swap_activity_data, "hourly_distribution": hourly_distribution_data, "abort_reasons": abort_reasons_data, - "slot_utilization": slot_utilization_data # <-- ADD THIS NEW KEY + "slot_utilization": slot_utilization_data }) # --- CSV Export route (UPDATED) --- @@ -564,6 +620,12 @@ def _format_periodic_row(payload, num_slots=9): for i in range(1, num_slots + 1): slot = slot_map.get(i) if slot: + # Convert boolean values to readable text + # door_status_text = "OPEN" if slot.get("doorStatus", 0) == 1 else "CLOSED" + # door_lock_status_text = "UNLOCKED" if slot.get("doorLockStatus", 0) == 1 else "LOCKED" + # battery_present_text = "YES" if slot.get("batteryPresent", 0) == 1 else "NO" + # charger_present_text = "YES" if slot.get("chargerPresent", 0) == 1 else "NO" + row.extend([ slot.get('batteryIdentification', ''), slot.get("batteryPresent", 0), @@ -836,5 +898,5 @@ if __name__ == '__main__': mqtt_thread = threading.Thread(target=start_mqtt_clients, daemon=True) mqtt_thread.start() - print(f"Starting Flask-SocketIO server on http://192.168.1.12:5000") - socketio.run(app, host='192.168.1.12', port=5000) + print(f"Starting Flask-SocketIO server on http://10.10.1.183:5000") + socketio.run(app, host='10.10.1.183', port=5000) diff --git a/backend/proto/__pycache__/vec_payload_chgSt_pb2.cpython-313.pyc b/backend/proto/__pycache__/vec_payload_chgSt_pb2.cpython-313.pyc index c6475c5a0e2f7504d640a948ffafcf02d711274c..d80a5a2222dd4d72d02a8c74fa5ae1f47d641033 100644 GIT binary patch delta 1045 zcmZA0%S#(U9Ki9N;93*2t5MVDp>BM?T8-7(H1^?|3=s)YoLwa#EIwiy8cdP&P%pt# z&obxIQfP0U_EHM{1KMNh$^Hd}LZM!J@V5#4MrIGg@R={e&MfC)Ljatn>Wy9trXoDH4s>$$UfK?X5<=%zIeZZkTneFssIz;8_SQj@AR#D|LNn zq6>rFmbyD=&^20HvIt;Q3S($u!#G&K)D57CZV=3nx&)f&8bg4?QaFMp!cnj>sT)TV z-2~XA)J>s@ZW?Sx_0E6es_(WCOoaEqW~B}1&_tI6o0q!#XrfyHTg0w)|Lg&x2$#Sf zV%YpnEQKbzM__5GTSgPzW3VSu_q2g1!e?MBQfQ)yZWSyeby+m*%6eI!qNhf#bX+>w ztCtQFFHdUq+Ci}wUyfqINWc-Z>feF4=PH4Yih*JsKXuPqkE*a6QgG^5MAF` zwThe6VLRrgW7^i5!|Y6kGS>aZeWCyNE$#airE&t*Eflw?$u?-F^rw~~<4K{<}-#yV;G}Z;dLR>e8 z#=3d11+H5xAhK`?Y?%vJ&{(H{g}H7O4ZD<-lKR&!{E_5w@^mksJPe$i=JL6NTsE+O zX53e$NWid*e#?)oG%POGkh@YwswSnPLQOxJ{)|pF zMbjyGJN$9!E*Q$r1l?9*N;n$V;;KTUo3QGz!D_wn)!^}6o6}nu%5{kiWiz5H5mnoX rsZhatxSeknk~BWuL8D0yl8~__pIa|=@+}CCE4}nC4_K;Z;YNM|Z03^% diff --git a/backend/proto/vec_payload_chgSt.proto b/backend/proto/vec_payload_chgSt.proto index 521b42c..01f62ff 100644 --- a/backend/proto/vec_payload_chgSt.proto +++ b/backend/proto/vec_payload_chgSt.proto @@ -25,6 +25,7 @@ enum jobType_e { JOBTYPE_REBOOT = 0x104; JOBTYPE_SWAP_DENY = 0x105; JOBTYPE_LANGUAGE_UPDATE = 0x106; + JOBTYPE_SWAP_AUTH_SUCCESS = 0x107; } enum jobResult_e { diff --git a/backend/proto/vec_payload_chgSt_pb2.py b/backend/proto/vec_payload_chgSt_pb2.py index a18742f..ca7c13f 100644 --- a/backend/proto/vec_payload_chgSt_pb2.py +++ b/backend/proto/vec_payload_chgSt_pb2.py @@ -2,7 +2,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: vec_payload_chgSt.proto -# Protobuf Python Version: 6.32.0 +# Protobuf Python Version: 6.31.1 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -12,8 +12,8 @@ from google.protobuf.internal import builder as _builder _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, 6, - 32, - 0, + 31, + 1, '', 'vec_payload_chgSt.proto' ) @@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17vec_payload_chgSt.proto\"\x82\x03\n\x10slotLevelPayload\x12\x16\n\x0e\x62\x61tteryPresent\x18\x01 \x01(\r\x12\x16\n\x0e\x63hargerPresent\x18\x02 \x01(\r\x12\x16\n\x0e\x64oorLockStatus\x18\x03 \x01(\r\x12\x12\n\ndoorStatus\x18\x04 \x01(\r\x12\x0f\n\x07voltage\x18\x05 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x06 \x01(\x05\x12\x18\n\x10\x62\x61tteryFaultCode\x18\x07 \x01(\r\x12\x18\n\x10\x63hargerFaultCode\x18\x08 \x01(\r\x12\x16\n\x0e\x62\x61tteryMaxTemp\x18\t \x01(\x05\x12\x16\n\x0e\x63hargerMaxTemp\x18\n \x01(\x05\x12\x1d\n\x15\x62\x61tteryIdentification\x18\x0b \x01(\t\x12\x13\n\x0b\x62\x61tteryMode\x18\x0c \x01(\r\x12\x13\n\x0b\x63hargerMode\x18\r \x01(\r\x12\x17\n\x0fslotTemperature\x18\x0e \x01(\x05\x12\x11\n\tgasSensor\x18\x0f \x01(\r\x12\x0b\n\x03soc\x18\x10 \x01(\r\x12\n\n\x02ts\x18\x11 \x01(\r\"\xe8\x01\n\x0bmainPayload\x12\n\n\x02ts\x18\x01 \x02(\r\x12\x10\n\x08\x64\x65viceId\x18\x02 \x02(\t\x12\x11\n\tsessionId\x18\x03 \x02(\t\x12+\n\x10slotLevelPayload\x18\x04 \x03(\x0b\x32\x11.slotLevelPayload\x12\x1a\n\x12\x62\x61\x63kupSupplyStatus\x18\x05 \x01(\r\x12\x14\n\x0cswitchStatus\x18\x06 \x03(\r\x12\x15\n\rstationStatus\x18\x07 \x01(\r\x12\x1d\n\x15stationDiagnosticCode\x18\x08 \x01(\r\x12\x13\n\x0b\x63oordinates\x18\t \x03(\x02\"=\n\x0cnfcPayload_s\x12\x19\n\x11manufacturingData\x18\x01 \x02(\t\x12\x12\n\ncustomData\x18\x02 \x02(\t\"\xe1\x01\n\x0b\x65ventData_s\x12\x1e\n\x07nfcData\x18\x01 \x01(\x0b\x32\r.nfcPayload_s\x12\x1d\n\x15\x62\x61tteryIdentification\x18\x02 \x01(\t\x12\x1d\n\x15\x61\x63tivityFailureReason\x18\x03 \x01(\r\x12+\n\x0fswapAbortReason\x18\x04 \x01(\x0e\x32\x12.swapAbortReason_e\x12\x10\n\x08swapTime\x18\x05 \x01(\r\x12\x11\n\tfaultCode\x18\x06 \x01(\r\x12\x12\n\ndoorStatus\x18\x07 \x01(\r\x12\x0e\n\x06slotId\x18\x08 \x01(\r\"\x81\x01\n\x0c\x65ventPayload\x12\n\n\x02ts\x18\x01 \x02(\r\x12\x10\n\x08\x64\x65viceId\x18\x02 \x02(\t\x12\x1f\n\teventType\x18\x03 \x02(\x0e\x32\x0c.eventType_e\x12\x11\n\tsessionId\x18\x04 \x02(\t\x12\x1f\n\teventData\x18\x05 \x01(\x0b\x32\x0c.eventData_s\"1\n\trpcData_s\x12\x11\n\tsessionId\x18\x01 \x01(\t\x12\x11\n\tslotsData\x18\x02 \x03(\r\".\n\rslotControl_s\x12\x0e\n\x06slotId\x18\x01 \x02(\r\x12\r\n\x05state\x18\x02 \x02(\r\"&\n\x15getJobStatusByJobId_s\x12\r\n\x05jobId\x18\x01 \x02(\t\"\x84\x02\n\nrpcRequest\x12\n\n\x02ts\x18\x01 \x02(\r\x12\r\n\x05jobId\x18\x02 \x02(\t\x12\x1b\n\x07jobType\x18\x03 \x02(\x0e\x32\n.jobType_e\x12\x1b\n\x07rpcData\x18\x04 \x01(\x0b\x32\n.rpcData_s\x12 \n\x08slotInfo\x18\x05 \x01(\x0b\x32\x0e.slotControl_s\x12#\n\x08swapDeny\x18\x08 \x01(\x0e\x32\x11.swapDenyReason_e\x12\x33\n\x13getJobStatusByJobId\x18\t \x01(\x0b\x32\x16.getJobStatusByJobId_s\x12%\n\x0clanguageType\x18\n \x01(\x0e\x32\x0f.languageType_e\"m\n\x1ajobStatusByJobIdResponse_s\x12\r\n\x05jobId\x18\x01 \x02(\t\x12\x1f\n\tjobStatus\x18\x02 \x02(\x0e\x32\x0c.jobStatus_e\x12\x1f\n\tjobResult\x18\x03 \x02(\x0e\x32\x0c.jobResult_e\"\xbb\x01\n\x0brpcResponse\x12\n\n\x02ts\x18\x01 \x02(\r\x12\x10\n\x08\x64\x65viceId\x18\x02 \x02(\t\x12\r\n\x05jobId\x18\x03 \x02(\t\x12\x1f\n\tjobStatus\x18\x04 \x02(\x0e\x32\x0c.jobStatus_e\x12\x1f\n\tjobResult\x18\x05 \x02(\x0e\x32\x0c.jobResult_e\x12=\n\x18jobStatusByJobIdResponse\x18\x06 \x01(\x0b\x32\x1b.jobStatusByJobIdResponse_s*\xc8\x02\n\x0b\x65ventType_e\x12\x15\n\x10\x45VENT_SWAP_START\x10\x80\x04\x12\x18\n\x13\x45VENT_BATTERY_ENTRY\x10\x81\x04\x12\x17\n\x12\x45VENT_BATTERY_EXIT\x10\x82\x04\x12\x1a\n\x15\x45VENT_ACTIVITY_FAILED\x10\x83\x04\x12\x17\n\x12\x45VENT_SWAP_ABORTED\x10\x84\x04\x12\x19\n\x14\x45VENT_BATFAULT_ALARM\x10\x85\x04\x12\x1d\n\x18\x45VENT_SLOT_LOCK_ENEGAGED\x10\x86\x04\x12\x15\n\x10\x45VENT_SWAP_ENDED\x10\x87\x04\x12\x19\n\x14\x45VENT_CHGFAULT_ALARM\x10\x88\x04\x12\x13\n\x0e\x45VENT_NFC_SCAN\x10\x89\x04\x12 \n\x1b\x45VENT_SLOT_LOCK_DISENEGAGED\x10\x8a\x04\x12\x17\n\x12\x45VENT_REVERSE_SWAP\x10\x8b\x04*\x85\x02\n\tjobType_e\x12\x10\n\x0cJOBTYPE_NONE\x10\x00\x12\x1f\n\x1bJOBTYPE_GET_STATUS_OF_A_JOB\x10\x01\x12\x17\n\x12JOBTYPE_SWAP_START\x10\x80\x02\x12#\n\x1eJOBTYPE_CHARGER_ENABLE_DISABLE\x10\x81\x02\x12\x1c\n\x17JOBTYPE_GATE_OPEN_CLOSE\x10\x82\x02\x12\x1e\n\x19JOBTYPE_TRANSACTION_ABORT\x10\x83\x02\x12\x13\n\x0eJOBTYPE_REBOOT\x10\x84\x02\x12\x16\n\x11JOBTYPE_SWAP_DENY\x10\x85\x02\x12\x1c\n\x17JOBTYPE_LANGUAGE_UPDATE\x10\x86\x02*n\n\x0bjobResult_e\x12\x16\n\x12JOB_RESULT_UNKNOWN\x10\x00\x12\x16\n\x12JOB_RESULT_SUCCESS\x10\x01\x12\x17\n\x13JOB_RESULT_REJECTED\x10\x02\x12\x16\n\x12JOB_RESULT_TIMEOUT\x10\x03*m\n\x0bjobStatus_e\x12\x13\n\x0fJOB_STATUS_IDLE\x10\x00\x12\x16\n\x12JOB_STATUS_PENDING\x10\x01\x12\x18\n\x14JOB_STATUS_EXECUTING\x10\x02\x12\x17\n\x13JOB_STATUS_EXECUTED\x10\x03*\xea\x01\n\x11swapAbortReason_e\x12\x11\n\rABORT_UNKNOWN\x10\x00\x12\x1a\n\x16\x41\x42ORT_BAT_EXIT_TIMEOUT\x10\x01\x12\x1b\n\x17\x41\x42ORT_BAT_ENTRY_TIMEOUT\x10\x02\x12\x1c\n\x18\x41\x42ORT_DOOR_CLOSE_TIMEOUT\x10\x03\x12\x1b\n\x17\x41\x42ORT_DOOR_OPEN_TIMEOUT\x10\x04\x12\x17\n\x13\x41\x42ORT_INVALID_PARAM\x10\x05\x12\x1a\n\x16\x41\x42ORT_REMOTE_REQUESTED\x10\x06\x12\x19\n\x15\x41\x42ORT_INVALID_BATTERY\x10\x07*p\n\x10swapDenyReason_e\x12\x1e\n\x1aSWAP_DENY_INSUFFICIENT_BAL\x10\x01\x12\x19\n\x15SWAP_DENY_INVALID_NFC\x10\x02\x12!\n\x1dSWAP_DENY_BATTERY_UNAVAILABLE\x10\x03*y\n\x0elanguageType_e\x12\x19\n\x15LANGUAGE_TYPE_ENGLISH\x10\x01\x12\x17\n\x13LANGUAGE_TYPE_HINDI\x10\x02\x12\x19\n\x15LANGUAGE_TYPE_KANNADA\x10\x03\x12\x18\n\x14LANGUAGE_TYPE_TELUGU\x10\x04') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x17vec_payload_chgSt.proto\"\x82\x03\n\x10slotLevelPayload\x12\x16\n\x0e\x62\x61tteryPresent\x18\x01 \x01(\r\x12\x16\n\x0e\x63hargerPresent\x18\x02 \x01(\r\x12\x16\n\x0e\x64oorLockStatus\x18\x03 \x01(\r\x12\x12\n\ndoorStatus\x18\x04 \x01(\r\x12\x0f\n\x07voltage\x18\x05 \x01(\r\x12\x0f\n\x07\x63urrent\x18\x06 \x01(\x05\x12\x18\n\x10\x62\x61tteryFaultCode\x18\x07 \x01(\r\x12\x18\n\x10\x63hargerFaultCode\x18\x08 \x01(\r\x12\x16\n\x0e\x62\x61tteryMaxTemp\x18\t \x01(\x05\x12\x16\n\x0e\x63hargerMaxTemp\x18\n \x01(\x05\x12\x1d\n\x15\x62\x61tteryIdentification\x18\x0b \x01(\t\x12\x13\n\x0b\x62\x61tteryMode\x18\x0c \x01(\r\x12\x13\n\x0b\x63hargerMode\x18\r \x01(\r\x12\x17\n\x0fslotTemperature\x18\x0e \x01(\x05\x12\x11\n\tgasSensor\x18\x0f \x01(\r\x12\x0b\n\x03soc\x18\x10 \x01(\r\x12\n\n\x02ts\x18\x11 \x01(\r\"\xe8\x01\n\x0bmainPayload\x12\n\n\x02ts\x18\x01 \x02(\r\x12\x10\n\x08\x64\x65viceId\x18\x02 \x02(\t\x12\x11\n\tsessionId\x18\x03 \x02(\t\x12+\n\x10slotLevelPayload\x18\x04 \x03(\x0b\x32\x11.slotLevelPayload\x12\x1a\n\x12\x62\x61\x63kupSupplyStatus\x18\x05 \x01(\r\x12\x14\n\x0cswitchStatus\x18\x06 \x03(\r\x12\x15\n\rstationStatus\x18\x07 \x01(\r\x12\x1d\n\x15stationDiagnosticCode\x18\x08 \x01(\r\x12\x13\n\x0b\x63oordinates\x18\t \x03(\x02\"=\n\x0cnfcPayload_s\x12\x19\n\x11manufacturingData\x18\x01 \x02(\t\x12\x12\n\ncustomData\x18\x02 \x02(\t\"\xe1\x01\n\x0b\x65ventData_s\x12\x1e\n\x07nfcData\x18\x01 \x01(\x0b\x32\r.nfcPayload_s\x12\x1d\n\x15\x62\x61tteryIdentification\x18\x02 \x01(\t\x12\x1d\n\x15\x61\x63tivityFailureReason\x18\x03 \x01(\r\x12+\n\x0fswapAbortReason\x18\x04 \x01(\x0e\x32\x12.swapAbortReason_e\x12\x10\n\x08swapTime\x18\x05 \x01(\r\x12\x11\n\tfaultCode\x18\x06 \x01(\r\x12\x12\n\ndoorStatus\x18\x07 \x01(\r\x12\x0e\n\x06slotId\x18\x08 \x01(\r\"\x81\x01\n\x0c\x65ventPayload\x12\n\n\x02ts\x18\x01 \x02(\r\x12\x10\n\x08\x64\x65viceId\x18\x02 \x02(\t\x12\x1f\n\teventType\x18\x03 \x02(\x0e\x32\x0c.eventType_e\x12\x11\n\tsessionId\x18\x04 \x02(\t\x12\x1f\n\teventData\x18\x05 \x01(\x0b\x32\x0c.eventData_s\"1\n\trpcData_s\x12\x11\n\tsessionId\x18\x01 \x01(\t\x12\x11\n\tslotsData\x18\x02 \x03(\r\".\n\rslotControl_s\x12\x0e\n\x06slotId\x18\x01 \x02(\r\x12\r\n\x05state\x18\x02 \x02(\r\"&\n\x15getJobStatusByJobId_s\x12\r\n\x05jobId\x18\x01 \x02(\t\"\x84\x02\n\nrpcRequest\x12\n\n\x02ts\x18\x01 \x02(\r\x12\r\n\x05jobId\x18\x02 \x02(\t\x12\x1b\n\x07jobType\x18\x03 \x02(\x0e\x32\n.jobType_e\x12\x1b\n\x07rpcData\x18\x04 \x01(\x0b\x32\n.rpcData_s\x12 \n\x08slotInfo\x18\x05 \x01(\x0b\x32\x0e.slotControl_s\x12#\n\x08swapDeny\x18\x08 \x01(\x0e\x32\x11.swapDenyReason_e\x12\x33\n\x13getJobStatusByJobId\x18\t \x01(\x0b\x32\x16.getJobStatusByJobId_s\x12%\n\x0clanguageType\x18\n \x01(\x0e\x32\x0f.languageType_e\"m\n\x1ajobStatusByJobIdResponse_s\x12\r\n\x05jobId\x18\x01 \x02(\t\x12\x1f\n\tjobStatus\x18\x02 \x02(\x0e\x32\x0c.jobStatus_e\x12\x1f\n\tjobResult\x18\x03 \x02(\x0e\x32\x0c.jobResult_e\"\xbb\x01\n\x0brpcResponse\x12\n\n\x02ts\x18\x01 \x02(\r\x12\x10\n\x08\x64\x65viceId\x18\x02 \x02(\t\x12\r\n\x05jobId\x18\x03 \x02(\t\x12\x1f\n\tjobStatus\x18\x04 \x02(\x0e\x32\x0c.jobStatus_e\x12\x1f\n\tjobResult\x18\x05 \x02(\x0e\x32\x0c.jobResult_e\x12=\n\x18jobStatusByJobIdResponse\x18\x06 \x01(\x0b\x32\x1b.jobStatusByJobIdResponse_s*\xc8\x02\n\x0b\x65ventType_e\x12\x15\n\x10\x45VENT_SWAP_START\x10\x80\x04\x12\x18\n\x13\x45VENT_BATTERY_ENTRY\x10\x81\x04\x12\x17\n\x12\x45VENT_BATTERY_EXIT\x10\x82\x04\x12\x1a\n\x15\x45VENT_ACTIVITY_FAILED\x10\x83\x04\x12\x17\n\x12\x45VENT_SWAP_ABORTED\x10\x84\x04\x12\x19\n\x14\x45VENT_BATFAULT_ALARM\x10\x85\x04\x12\x1d\n\x18\x45VENT_SLOT_LOCK_ENEGAGED\x10\x86\x04\x12\x15\n\x10\x45VENT_SWAP_ENDED\x10\x87\x04\x12\x19\n\x14\x45VENT_CHGFAULT_ALARM\x10\x88\x04\x12\x13\n\x0e\x45VENT_NFC_SCAN\x10\x89\x04\x12 \n\x1b\x45VENT_SLOT_LOCK_DISENEGAGED\x10\x8a\x04\x12\x17\n\x12\x45VENT_REVERSE_SWAP\x10\x8b\x04*\xa5\x02\n\tjobType_e\x12\x10\n\x0cJOBTYPE_NONE\x10\x00\x12\x1f\n\x1bJOBTYPE_GET_STATUS_OF_A_JOB\x10\x01\x12\x17\n\x12JOBTYPE_SWAP_START\x10\x80\x02\x12#\n\x1eJOBTYPE_CHARGER_ENABLE_DISABLE\x10\x81\x02\x12\x1c\n\x17JOBTYPE_GATE_OPEN_CLOSE\x10\x82\x02\x12\x1e\n\x19JOBTYPE_TRANSACTION_ABORT\x10\x83\x02\x12\x13\n\x0eJOBTYPE_REBOOT\x10\x84\x02\x12\x16\n\x11JOBTYPE_SWAP_DENY\x10\x85\x02\x12\x1c\n\x17JOBTYPE_LANGUAGE_UPDATE\x10\x86\x02\x12\x1e\n\x19JOBTYPE_SWAP_AUTH_SUCCESS\x10\x87\x02*n\n\x0bjobResult_e\x12\x16\n\x12JOB_RESULT_UNKNOWN\x10\x00\x12\x16\n\x12JOB_RESULT_SUCCESS\x10\x01\x12\x17\n\x13JOB_RESULT_REJECTED\x10\x02\x12\x16\n\x12JOB_RESULT_TIMEOUT\x10\x03*m\n\x0bjobStatus_e\x12\x13\n\x0fJOB_STATUS_IDLE\x10\x00\x12\x16\n\x12JOB_STATUS_PENDING\x10\x01\x12\x18\n\x14JOB_STATUS_EXECUTING\x10\x02\x12\x17\n\x13JOB_STATUS_EXECUTED\x10\x03*\xea\x01\n\x11swapAbortReason_e\x12\x11\n\rABORT_UNKNOWN\x10\x00\x12\x1a\n\x16\x41\x42ORT_BAT_EXIT_TIMEOUT\x10\x01\x12\x1b\n\x17\x41\x42ORT_BAT_ENTRY_TIMEOUT\x10\x02\x12\x1c\n\x18\x41\x42ORT_DOOR_CLOSE_TIMEOUT\x10\x03\x12\x1b\n\x17\x41\x42ORT_DOOR_OPEN_TIMEOUT\x10\x04\x12\x17\n\x13\x41\x42ORT_INVALID_PARAM\x10\x05\x12\x1a\n\x16\x41\x42ORT_REMOTE_REQUESTED\x10\x06\x12\x19\n\x15\x41\x42ORT_INVALID_BATTERY\x10\x07*p\n\x10swapDenyReason_e\x12\x1e\n\x1aSWAP_DENY_INSUFFICIENT_BAL\x10\x01\x12\x19\n\x15SWAP_DENY_INVALID_NFC\x10\x02\x12!\n\x1dSWAP_DENY_BATTERY_UNAVAILABLE\x10\x03*y\n\x0elanguageType_e\x12\x19\n\x15LANGUAGE_TYPE_ENGLISH\x10\x01\x12\x17\n\x13LANGUAGE_TYPE_HINDI\x10\x02\x12\x19\n\x15LANGUAGE_TYPE_KANNADA\x10\x03\x12\x18\n\x14LANGUAGE_TYPE_TELUGU\x10\x04') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -34,17 +34,17 @@ if not _descriptor._USE_C_DESCRIPTORS: _globals['_EVENTTYPE_E']._serialized_start=1778 _globals['_EVENTTYPE_E']._serialized_end=2106 _globals['_JOBTYPE_E']._serialized_start=2109 - _globals['_JOBTYPE_E']._serialized_end=2370 - _globals['_JOBRESULT_E']._serialized_start=2372 - _globals['_JOBRESULT_E']._serialized_end=2482 - _globals['_JOBSTATUS_E']._serialized_start=2484 - _globals['_JOBSTATUS_E']._serialized_end=2593 - _globals['_SWAPABORTREASON_E']._serialized_start=2596 - _globals['_SWAPABORTREASON_E']._serialized_end=2830 - _globals['_SWAPDENYREASON_E']._serialized_start=2832 - _globals['_SWAPDENYREASON_E']._serialized_end=2944 - _globals['_LANGUAGETYPE_E']._serialized_start=2946 - _globals['_LANGUAGETYPE_E']._serialized_end=3067 + _globals['_JOBTYPE_E']._serialized_end=2402 + _globals['_JOBRESULT_E']._serialized_start=2404 + _globals['_JOBRESULT_E']._serialized_end=2514 + _globals['_JOBSTATUS_E']._serialized_start=2516 + _globals['_JOBSTATUS_E']._serialized_end=2625 + _globals['_SWAPABORTREASON_E']._serialized_start=2628 + _globals['_SWAPABORTREASON_E']._serialized_end=2862 + _globals['_SWAPDENYREASON_E']._serialized_start=2864 + _globals['_SWAPDENYREASON_E']._serialized_end=2976 + _globals['_LANGUAGETYPE_E']._serialized_start=2978 + _globals['_LANGUAGETYPE_E']._serialized_end=3099 _globals['_SLOTLEVELPAYLOAD']._serialized_start=28 _globals['_SLOTLEVELPAYLOAD']._serialized_end=414 _globals['_MAINPAYLOAD']._serialized_start=417 diff --git a/backend/proto/vec_payload_chgSt_pb2.pyi b/backend/proto/vec_payload_chgSt_pb2.pyi index 64a2210..2668898 100644 --- a/backend/proto/vec_payload_chgSt_pb2.pyi +++ b/backend/proto/vec_payload_chgSt_pb2.pyi @@ -33,6 +33,7 @@ class jobType_e(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): JOBTYPE_REBOOT: _ClassVar[jobType_e] JOBTYPE_SWAP_DENY: _ClassVar[jobType_e] JOBTYPE_LANGUAGE_UPDATE: _ClassVar[jobType_e] + JOBTYPE_SWAP_AUTH_SUCCESS: _ClassVar[jobType_e] class jobResult_e(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): __slots__ = () @@ -92,6 +93,7 @@ JOBTYPE_TRANSACTION_ABORT: jobType_e JOBTYPE_REBOOT: jobType_e JOBTYPE_SWAP_DENY: jobType_e JOBTYPE_LANGUAGE_UPDATE: jobType_e +JOBTYPE_SWAP_AUTH_SUCCESS: jobType_e JOB_RESULT_UNKNOWN: jobResult_e JOB_RESULT_SUCCESS: jobResult_e JOB_RESULT_REJECTED: jobResult_e diff --git a/frontend/analytics.html b/frontend/analytics.html index 287e336..fafd6d4 100644 --- a/frontend/analytics.html +++ b/frontend/analytics.html @@ -184,7 +184,43 @@ -
+
+
+

Total Swaps Initiated

+

...

+
+
+

Total Swaps Started

+

...

+
+
+

Completed Swaps

+

+ ... + (...%) +

+
+
+

Aborted Swaps

+

+ ... + (...%) +

+
+
+

Avg. Swap Time

+

+ ... + sec +

+
+
+

Station Uptime

+

... %

+
+
+ +
diff --git a/frontend/js/analytics.js b/frontend/js/analytics.js index 5c8a3c4..fae1a4c 100644 --- a/frontend/js/analytics.js +++ b/frontend/js/analytics.js @@ -1,7 +1,7 @@ // document.addEventListener('DOMContentLoaded', () => { // // --- CONFIGURATION --- -// const SOCKET_URL = "http://192.168.1.12:5000"; -// const API_BASE = "http://192.168.1.12:5000/api"; +// const SOCKET_URL = "http://10.10.1.183:5000"; +// const API_BASE = "http://10.10.1.183:5000/api"; // // --- DOM ELEMENT REFERENCES --- // const stationNameEl = document.getElementById('station-name'); @@ -122,11 +122,12 @@ document.addEventListener('DOMContentLoaded', () => { // --- CONFIGURATION --- - const API_BASE = "http://192.168.1.12:5000/api"; + const API_BASE = "http://10.10.1.183:5000/api"; // --- DOM ELEMENT REFERENCES --- // KPI Tiles - const totalSwapsEl = document.getElementById('total-swaps'); + const totalInitiatedEl = document.getElementById('total-swaps-initiated'); + const totalStartedEl = document.getElementById('total-swaps-started'); const completedSwapsEl = document.getElementById('completed-swaps'); const successRateEl = document.getElementById('success-rate'); const abortedSwapsEl = document.getElementById('aborted-swaps'); @@ -159,6 +160,8 @@ document.addEventListener('DOMContentLoaded', () => { const resetBtn = document.getElementById('station-reset-btn'); const logoutBtn = document.getElementById('logout-btn'); + let socket; + // --- CONSTANTS --- const chartDefaults = { @@ -188,7 +191,8 @@ document.addEventListener('DOMContentLoaded', () => { */ const updateStatTiles = (data) => { if (!data) { // Used for loading state or on error - totalSwapsEl.textContent = '...'; + totalInitiatedEl.textContent = '...'; + totalStartedEl.textContent = '...'; completedSwapsEl.textContent = '...'; successRateEl.textContent = '(...%)'; abortedSwapsEl.textContent = '...'; @@ -198,28 +202,32 @@ document.addEventListener('DOMContentLoaded', () => { return; } - const total = data.total_swaps ?? 0; + // Assign new data from the backend + totalInitiatedEl.textContent = data.total_swaps_initiated ?? 0; + totalStartedEl.textContent = data.total_swaps_started ?? 0; + const completed = data.completed_swaps ?? 0; const aborted = data.aborted_swaps ?? 0; - - totalSwapsEl.textContent = total; + completedSwapsEl.textContent = completed; abortedSwapsEl.textContent = aborted; - const successRate = total > 0 ? ((completed / total) * 100).toFixed(1) : 0; + // Use total_swaps_started for calculating success/abort rates + const totalStarts = data.total_swaps_started ?? 0; + const successRate = totalStarts > 0 ? ((completed / totalStarts) * 100).toFixed(1) : 0; successRateEl.textContent = `(${successRate}%)`; - const abortRate = total > 0 ? ((aborted / total) * 100).toFixed(1) : 0; + const abortRate = totalStarts > 0 ? ((aborted / totalStarts) * 100).toFixed(1) : 0; abortRateEl.textContent = `(${abortRate}%)`; - const avgTimeInMinutes = data.avg_swap_time_seconds != null ? (data.avg_swap_time_seconds / 60).toFixed(1) : '—'; - - avgSwapTimeValueEl.textContent = avgTimeInMinutes; + const avgTimeInSeconds = data.avg_swap_time_seconds != null ? Math.round(data.avg_swap_time_seconds) : '—'; + avgSwapTimeValueEl.textContent = avgTimeInSeconds; stationUptimeEl.textContent = `${data.station_uptime ?? '...'} %`; }; + // --- CHART.JS VISUALIZATION CODE --- /** @@ -470,6 +478,23 @@ document.addEventListener('DOMContentLoaded', () => { toDatePicker.setDate(todayStr, false); fetchAnalyticsData(todayStr, todayStr); + connectSocket(); + + // --- ADD THIS BLOCK FOR AUTO-REFRESH --- + setInterval(() => { + console.log("Auto-refreshing analytics data..."); + // Use .selectedDates[0] to get the date object + const startDateObj = fromDatePicker.selectedDates[0]; + const endDateObj = toDatePicker.selectedDates[0]; + + if (startDateObj && endDateObj) { + // Use the formatDate utility to get the string in the correct format + const startDate = flatpickr.formatDate(startDateObj, "Y-m-d"); + const endDate = flatpickr.formatDate(endDateObj, "Y-m-d"); + fetchAnalyticsData(startDate, endDate); + } + }, 30000); // Refreshes every 30 seconds (30000 milliseconds) + // --- EVENT LISTENERS --- applyRangeBtn.addEventListener('click', () => { const startDate = fromDateInput.value; diff --git a/frontend/js/auth.js b/frontend/js/auth.js index 065cc38..c9c9a43 100644 --- a/frontend/js/auth.js +++ b/frontend/js/auth.js @@ -11,7 +11,7 @@ document.addEventListener('DOMContentLoaded', () => { const password = document.getElementById('password').value; try { - const response = await fetch('http://192.168.1.12:5000/api/login', { + const response = await fetch('http://10.10.1.183:5000/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username, password }), diff --git a/frontend/js/common-header.js b/frontend/js/common-header.js index 488fd5e..d9c4603 100644 --- a/frontend/js/common-header.js +++ b/frontend/js/common-header.js @@ -1,8 +1,8 @@ // frontend/js/common-header.js document.addEventListener('DOMContentLoaded', () => { // --- CONFIGURATION --- - const SOCKET_URL = "http://192.168.1.12:5000"; - const API_BASE = "http://192.168.1.12:5000/api"; + const SOCKET_URL = "http://10.10.1.183:5000"; + const API_BASE = "http://10.10.1.183:5000/api"; // --- STATE & SELECTED STATION --- let selectedStation = null; diff --git a/frontend/js/dashboard.js b/frontend/js/dashboard.js index 0609010..dae42fd 100644 --- a/frontend/js/dashboard.js +++ b/frontend/js/dashboard.js @@ -1,7 +1,7 @@ document.addEventListener('DOMContentLoaded', () => { // --- CONFIGURATION --- - const SOCKET_URL = "http://192.168.1.12:5000"; - const API_BASE = "http://192.168.1.12:5000/api"; // Added for API calls + const SOCKET_URL = "http://10.10.1.183:5000"; + const API_BASE = "http://10.10.1.183:5000/api"; // Added for API calls // --- DOM ELEMENT REFERENCES --- const grid = document.getElementById('chambersGrid'); @@ -38,6 +38,21 @@ document.addEventListener('DOMContentLoaded', () => { "Earth Leakage" ]; + const BATTERY_FAULT_MAP = { + 8: "UT", // Under Temperature + 4: "OV", // Over Voltage + 2: "OT", // Over Temperature + 1: "OC" // Over Current + }; + + const CHARGER_FAULT_MAP = { + 1: "OV", // Over Voltage + 2: "UV", // Under Voltage + 4: "OT", // Over Temperature + 8: "CAN Failure" + // Add other charger fault codes here + }; + // --- NEW: SWAP PROCESS ELEMENTS & LOGIC --- const swapIdleText = document.getElementById('swap-idle-text'); const swapPairsList = document.getElementById('swap-pairs-list'); @@ -150,6 +165,29 @@ document.addEventListener('DOMContentLoaded', () => { logTextArea.value = newLog + logTextArea.value; }; + + /** + * Decodes a fault bitmask into a human-readable string using a given map. + * @param {number} faultCode The fault code number. + * @param {object} faultMap The map to use for decoding (e.g., BATTERY_FAULT_MAP). + * @returns {string} A comma-separated string of active faults, or "—" if none. + */ + const decodeFaults = (faultCode, faultMap) => { + if (!faultCode || faultCode === 0) { + return "—"; // No fault + } + + const activeFaults = []; + for (const bit in faultMap) { + if ((faultCode & bit) !== 0) { + activeFaults.push(faultMap[bit]); + } + } + + return activeFaults.length > 0 ? activeFaults.join(', ') : "—"; + }; + + const updateChamberUI = (card, slot) => { if (!card || !slot) return; @@ -177,18 +215,24 @@ document.addEventListener('DOMContentLoaded', () => { card.querySelector('.soc').textContent = `${slot.soc || 0}%`; card.querySelector('.voltage').textContent = `${((slot.voltage || 0) / 1000).toFixed(1)} V`; card.querySelector('.bat-temp').textContent = `${((slot.batteryMaxTemp || 0) / 10).toFixed(1)} °C`; - card.querySelector('.bat-fault').textContent = slot.batteryFaultCode || '—'; + // card.querySelector('.bat-fault').textContent = slot.batteryFaultCode || '—'; + + card.querySelector('.bat-fault').textContent = decodeFaults(slot.batteryFaultCode, BATTERY_FAULT_MAP); + + // card.querySelector('.bat-fault').textContent = decodeBatteryFaults(slot.batteryFaultCode); card.querySelector('.current').textContent = `${((slot.current || 0) / 1000).toFixed(1)} A`; card.querySelector('.slot-temp').textContent = `${((slot.slotTemperature || 0) / 10).toFixed(1)} °C`; - card.querySelector('.chg-fault').textContent = slot.chargerFaultCode || '—'; + card.querySelector('.chg-temp').textContent = `${((slot.chargerMaxTemp || 0) / 10).toFixed(1)} °C`; + // card.querySelector('.chg-fault').textContent = slot.chargerFaultCode || '—'; + card.querySelector('.chg-fault').textContent = decodeFaults(slot.chargerFaultCode, CHARGER_FAULT_MAP); const batPill = card.querySelector('.battery-status-pill'); batPill.innerHTML = ` Present`; batPill.className = 'battery-status-pill chip chip-emerald'; const chgPill = card.querySelector('.charger-status-pill'); - if (slot.chargerMode === 1) { + if (slot.chargingStatus === 1) { chgPill.innerHTML = ` Charging`; chgPill.className = 'charger-status-pill chip chip-sky'; } else { diff --git a/frontend/js/logs.js b/frontend/js/logs.js index 6563dea..c5fc9ce 100644 --- a/frontend/js/logs.js +++ b/frontend/js/logs.js @@ -1,166 +1,7 @@ -// document.addEventListener('DOMContentLoaded', () => { -// // --- CONFIGURATION --- -// const SOCKET_URL = "http://192.168.1.12:5000"; -// const API_BASE = "http://192.168.1.12:5000/api"; - -// // --- DOM ELEMENT REFERENCES --- -// const stationNameEl = document.getElementById('station-name'); -// const stationLocationEl = document.getElementById('station-location'); -// const deviceIdEl = document.getElementById('device-id'); -// const lastUpdateEl = document.getElementById('last-update-status'); -// const connChip = document.getElementById('connection-status-chip'); -// const requestLogArea = document.getElementById('request-log-area'); -// const eventLogArea = document.getElementById('event-log-area'); -// const clearReqBtn = document.getElementById('clear-req'); -// const clearEvtBtn = document.getElementById('clear-evt'); -// const clearAllBtn = document.getElementById('clear-all'); -// const refreshBtn = document.getElementById('refreshBtn'); -// const downloadBtn = document.getElementById('downloadBtn'); -// const logoutBtn = document.getElementById('logout-btn'); -// const resetBtn = document.getElementById('station-reset-btn'); - -// // --- STATE --- -// let selectedStation = null; -// let socket; -// let statusPollingInterval; - -// // --- HELPER FUNCTIONS --- -// // **MODIFIED** to accept the 'topic' -// const prependLog = (textarea, data, topic) => { -// if (!textarea) return; -// const timestamp = new Date().toLocaleTimeString(); -// const formattedJson = JSON.stringify(data, null, 2); -// // **MODIFIED** to include the topic string -// const newLog = `[${timestamp}] - Topic: ${topic}\n${formattedJson}\n\n---------------------------------\n\n`; -// textarea.value = newLog + textarea.value; -// }; - -// // --- NEW: LOG PERSISTENCE HELPERS --- -// const saveLogs = () => { -// if (!selectedStation) return; -// sessionStorage.setItem(`request_logs_${selectedStation.id}`, requestLogArea.value); -// sessionStorage.setItem(`event_logs_${selectedStation.id}`, eventLogArea.value); -// }; - -// const loadLogs = () => { -// if (!selectedStation) return; -// requestLogArea.value = sessionStorage.getItem(`request_logs_${selectedStation.id}`) || ''; -// eventLogArea.value = sessionStorage.getItem(`event_logs_${selectedStation.id}`) || ''; -// }; - -// const sendCommand = (command, data = null) => { -// if (!selectedStation || !socket || !socket.connected) { -// console.error(`Cannot send command '${command}', not connected.`); -// return; -// } -// const payload = { station_id: selectedStation.id, command: command, data: data }; -// socket.emit('rpc_request', payload); -// }; - -// const checkStationStatus = async () => { -// // ... (This function is unchanged) -// if (!selectedStation) return; -// try { -// const response = await fetch(`${API_BASE}/stations`); -// if (!response.ok) return; -// const stations = await response.json(); -// const thisStation = stations.find(s => s.id === selectedStation.id); -// if (thisStation) { -// stationNameEl.textContent = thisStation.name; -// stationLocationEl.textContent = thisStation.location; -// if (thisStation.status === 'Online') { -// connChip.innerHTML = ` Online`; -// connChip.className = 'cham_chip cham_chip-emerald'; -// } else { -// connChip.innerHTML = ` Offline`; -// connChip.className = 'cham_chip cham_chip-rose'; -// } -// } -// } catch (error) { console.error("Failed to fetch station status:", error); } -// }; - -// // --- INITIALIZATION --- -// try { -// selectedStation = JSON.parse(localStorage.getItem('selected_station')); -// if (!selectedStation || !selectedStation.id) { -// throw new Error('No station selected. Please go back to the selection page.'); -// } -// deviceIdEl.textContent = selectedStation.id; -// } catch (e) { -// document.body.innerHTML = `
${e.message}Go Back
`; -// return; -// } - -// // --- SOCKET.IO CONNECTION --- -// socket = io(SOCKET_URL); -// socket.on('connect', () => { -// console.log("Connected to WebSocket for logs."); -// socket.emit('join_station_room', { station_id: selectedStation.id }); -// }); - -// socket.on('dashboard_update', (message) => { -// const { stationId, topic, data } = message; -// if (stationId !== selectedStation.id) return; - -// lastUpdateEl.textContent = 'Last Recv ' + new Date().toLocaleTimeString(); - -// // **MODIFIED** to pass the 'topic' to prependLog -// if (topic.endsWith('EVENTS')) { -// prependLog(eventLogArea, data, topic); -// } else if (topic.endsWith('REQUEST')) { -// prependLog(requestLogArea, data, topic); -// } - -// // **NEW**: Save the logs after every update -// saveLogs(); -// }); - -// // --- BUTTON EVENT LISTENERS --- -// // **MODIFIED** to clear sessionStorage -// if(clearReqBtn) clearReqBtn.addEventListener('click', () => { -// requestLogArea.value = ''; -// sessionStorage.removeItem(`request_logs_${selectedStation.id}`); -// }); -// if(clearEvtBtn) clearEvtBtn.addEventListener('click', () => { -// eventLogArea.value = ''; -// sessionStorage.removeItem(`event_logs_${selectedStation.id}`); -// }); -// if(clearAllBtn) clearAllBtn.addEventListener('click', () => { -// requestLogArea.value = ''; -// eventLogArea.value = ''; -// sessionStorage.removeItem(`request_logs_${selectedStation.id}`); -// sessionStorage.removeItem(`event_logs_${selectedStation.id}`); -// }); - -// // (The rest of your button listeners are unchanged) -// if(logoutBtn) logoutBtn.addEventListener('click', () => { -// localStorage.clear(); -// window.location.href = 'index.html'; -// }); -// if(refreshBtn) refreshBtn.addEventListener('click', () => location.reload()); -// if(resetBtn) resetBtn.addEventListener('click', () => { -// if (confirm('Are you sure you want to reset the station?')) { -// sendCommand('STATION_RESET'); -// } -// }); - -// // --- STARTUP --- -// checkStationStatus(); -// statusPollingInterval = setInterval(checkStationStatus, 10000); -// loadLogs(); // **NEW**: Load saved logs from this session on startup -// if (typeof lucide !== 'undefined') { -// lucide.createIcons(); -// } -// }); - - - - - document.addEventListener('DOMContentLoaded', () => { // --- CONFIGURATION --- - const SOCKET_URL = "http://192.168.1.12:5000"; - const API_BASE = "http://192.168.1.12:5000/api"; + const SOCKET_URL = "http://10.10.1.183:5000"; + const API_BASE = "http://10.10.1.183:5000/api"; // --- DOM ELEMENT REFERENCES --- const stationNameEl = document.getElementById('station-name'); @@ -169,72 +10,42 @@ document.addEventListener('DOMContentLoaded', () => { const productIdEl = document.getElementById('product-id'); const requestLogArea = document.getElementById('request-log-area'); const eventLogArea = document.getElementById('event-log-area'); + const connChip = document.getElementById('connection-status-chip'); const clearReqBtn = document.getElementById('clear-req'); const clearEvtBtn = document.getElementById('clear-evt'); const clearAllBtn = document.getElementById('clear-all'); const refreshBtn = document.getElementById('refreshBtn'); - const resetBtn = document.getElementById('station-reset-btn'); const logoutBtn = document.getElementById('logout-btn'); // --- STATE --- let selectedStation = null; let socket; + let statusPollingInterval; - // --- HELPER FUNCTIONS --- + // --- HELPER FUNCTIONS -- const appendLog = (textarea, data, topic, timestampStr) => { if (!textarea) return; + const timestamp = new Date(timestampStr).toLocaleTimeString(); const formattedJson = JSON.stringify(data, null, 2); - const newLog = `[${timestamp}] - Topic: ${topic}\n${formattedJson}\n\n---------------------------------\n\n`; - // Append the new log to the end of the existing text + // Clean up the topic for better display + const topicParts = topic.split('/'); + const shortTopic = topicParts.slice(-2).join('/'); // Gets the last two parts, e.g., "RPC/REQUEST" or ".../EVENTS" + + const newLog = `[${timestamp}] - Topic: ${shortTopic}\n${formattedJson}\n\n---------------------------------\n\n`; + textarea.value += newLog; - - // Auto-scroll to the bottom to always show the newest log textarea.scrollTop = textarea.scrollHeight; }; - const sendCommand = (command, data = null) => { - if (!selectedStation || !socket || !socket.connected) { - console.error(`Cannot send command '${command}', not connected.`); - return; - } - const payload = { station_id: selectedStation.id, command: command, data: data }; - socket.emit('rpc_request', payload); - }; - - const checkStationStatus = async () => { - if (!selectedStation) return; - try { - const response = await fetch(`${API_BASE}/stations`); - if (!response.ok) return; - const stations = await response.json(); - const thisStation = stations.find(s => s.id === selectedStation.id); - if (thisStation) { - stationNameEl.textContent = thisStation.name; - stationLocationEl.textContent = thisStation.location; - if (thisStation.status === 'Online') { - connChip.innerHTML = ` Online`; - connChip.className = 'cham_chip cham_chip-emerald'; - } else { - connChip.innerHTML = ` Offline`; - connChip.className = 'cham_chip cham_chip-rose'; - } - } - } catch (error) { console.error("Failed to fetch station status:", error); } - }; - - // --- NEW: Fetch recent logs from the database --- - const fetchAndRenderLogs = async () => { + const fetchRecentLogs = async () => { try { const response = await fetch(`${API_BASE}/logs/recent/${selectedStation.id}`); - if (!response.ok) { - throw new Error('Failed to fetch recent logs'); - } + if (!response.ok) throw new Error('Failed to fetch recent logs'); const logs = await response.json(); - // Clear text areas before populating requestLogArea.value = ''; eventLogArea.value = ''; @@ -246,70 +57,83 @@ document.addEventListener('DOMContentLoaded', () => { } }); console.log(`Successfully fetched and rendered ${logs.length} recent logs.`); - } catch (error) { console.error(error); } }; - // --- INITIALIZATION --- - try { - selectedStation = JSON.parse(localStorage.getItem('selected_station')); - if (!selectedStation || !selectedStation.id) { - throw new Error('No station selected.'); + // --- INITIALIZATION AND EVENT HANDLERS --- + function init() { + console.log("1. Starting initialization..."); + + // Step 1: Load the station from localStorage. + try { + const stationData = localStorage.getItem('selected_station'); + console.log("2. Fetched from localStorage:", stationData); + + if (!stationData) { + throw new Error('No station data found in localStorage.'); + } + + selectedStation = JSON.parse(stationData); + console.log("3. Parsed station data:", selectedStation); + + if (!selectedStation || !selectedStation.id) { + throw new Error('Parsed station data is invalid or missing an ID.'); + } + + } catch (e) { + console.error("ERROR during station loading:", e); + // window.location.href = './station_selection.html'; // Temporarily disable redirect for debugging + return; } + + // Step 2: Populate the header. + console.log("4. Populating header..."); + stationNameEl.textContent = selectedStation.name; + stationLocationEl.textContent = selectedStation.location; deviceIdEl.textContent = selectedStation.id; - productIdEl.textContent = selectedStation.product_id; - } catch (e) { - document.body.innerHTML = `
${e.message}Go Back
`; - return; + productIdEl.textContent = selectedStation.product_id; + console.log("5. Header populated."); + + // Step 3: Set up button event listeners. + if(clearReqBtn) clearReqBtn.addEventListener('click', () => requestLogArea.value = ''); + if(clearEvtBtn) clearEvtBtn.addEventListener('click', () => eventLogArea.value = ''); + if(clearAllBtn) clearAllBtn.addEventListener('click', () => { + requestLogArea.value = ''; + eventLogArea.value = ''; + }); + if(logoutBtn) logoutBtn.addEventListener('click', () => { + localStorage.clear(); + window.location.href = 'index.html'; + }); + if(refreshBtn) refreshBtn.addEventListener('click', () => location.reload()); + console.log("6. Event listeners attached."); + + // Step 4: Fetch initial data now that everything is set up. + console.log("7. Calling fetchRecentLogs()..."); + fetchRecentLogs(); + + // Step 5: Start WebSocket connection for live updates. + socket = io(SOCKET_URL); + socket.on('connect', () => { + console.log("Logs Page: Connected to WebSocket."); + socket.emit('join_station_room', { station_id: selectedStation.id }); + }); + socket.on('dashboard_update', (message) => { + const { stationId, topic, data } = message; + if (stationId !== selectedStation.id) return; + const now = new Date().toISOString(); + if (topic.endsWith('EVENTS')) { + appendLog(eventLogArea, data, topic, now); + } else if (topic.endsWith('REQUEST')) { + appendLog(requestLogArea, data, topic, now); + } + }); } - // --- SOCKET.IO FOR LIVE UPDATES --- - socket = io(SOCKET_URL); - socket.on('connect', () => { - console.log("Connected to WebSocket for live logs."); - socket.emit('join_station_room', { station_id: selectedStation.id }); - }); - socket.on('dashboard_update', (message) => { - const { stationId, topic, data } = message; - if (stationId !== selectedStation.id) return; - - // Just prepend live messages as they arrive - const now = new Date().toISOString(); - if (topic.endsWith('EVENTS')) { - appendLog(eventLogArea, data, topic, now); - } else if (topic.endsWith('REQUEST')) { - appendLog(requestLogArea, data, topic, now); - } - }); - - // --- BUTTON EVENT LISTENERS --- - if(clearReqBtn) clearReqBtn.addEventListener('click', () => requestLogArea.value = ''); - if(clearEvtBtn) clearEvtBtn.addEventListener('click', () => eventLogArea.value = ''); - if(clearAllBtn) clearAllBtn.addEventListener('click', () => { - requestLogArea.value = ''; - eventLogArea.value = ''; - }); - // (The rest of your button listeners are unchanged) - if(logoutBtn) logoutBtn.addEventListener('click', () => { - localStorage.clear(); - window.location.href = 'index.html'; - }); - if(refreshBtn) refreshBtn.addEventListener('click', () => location.reload()); - if(resetBtn) resetBtn.addEventListener('click', () => { - if (confirm('Are you sure you want to reset the station?')) { - sendCommand('STATION_RESET'); - } - }); - - // --- STARTUP --- - fetchAndRenderLogs(); // Fetch historical logs on page load - checkStationStatus(); - - if (typeof lucide !== 'undefined') { - lucide.createIcons(); - } -}); + // --- START THE APPLICATION --- + init(); +}); \ No newline at end of file diff --git a/frontend/js/station_selection.js b/frontend/js/station_selection.js index 2b5cd75..949848d 100644 --- a/frontend/js/station_selection.js +++ b/frontend/js/station_selection.js @@ -140,7 +140,7 @@ // // --- DATA FETCHING & STATUS POLLING --- // const loadAndPollStations = async () => { // try { -// const response = await fetch('http://192.168.1.12:5000/api/stations'); +// const response = await fetch('http://10.10.1.183:5000/api/stations'); // if (!response.ok) throw new Error('Failed to fetch stations'); // const stations = await response.json(); @@ -178,7 +178,7 @@ // } // try { -// const response = await fetch(`http://192.168.1.12:5000/api/stations/${stationId}`, { +// const response = await fetch(`http://10.10.1.183:5000/api/stations/${stationId}`, { // method: 'DELETE', // }); @@ -214,7 +214,7 @@ document.addEventListener('DOMContentLoaded', () => { const stationCountEl = document.getElementById('station-count'); // Make sure you have an element with this ID in your HTML // --- CONFIG & STATE --- - const API_BASE = 'http://192.168.1.12:5000/api'; + const API_BASE = 'http://10.10.1.183:5000/api'; let allStations = []; // Master list of stations from the API let pollingInterval = null; diff --git a/frontend/station_selection.html b/frontend/station_selection.html index 5b94e1a..393532e 100644 --- a/frontend/station_selection.html +++ b/frontend/station_selection.html @@ -225,7 +225,7 @@