Added buffer autosave and fixed slow comports() call by delocalizing to thread
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
# Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
|
# Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sys
|
import sys
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@@ -40,6 +41,7 @@ def _asset_path(relative_path: str) -> str:
|
|||||||
|
|
||||||
def run() -> None:
|
def run() -> None:
|
||||||
state: AppState = AppState()
|
state: AppState = AppState()
|
||||||
|
state.start_time = datetime.now()
|
||||||
|
|
||||||
# Create application context and viewport
|
# Create application context and viewport
|
||||||
dpg.create_context()
|
dpg.create_context()
|
||||||
@@ -91,6 +93,12 @@ def run() -> None:
|
|||||||
)
|
)
|
||||||
state.telemetry_thread.start()
|
state.telemetry_thread.start()
|
||||||
|
|
||||||
|
state.ports_thread_running = True
|
||||||
|
state.ports_thread = Thread(
|
||||||
|
target=dataflux.ui.worker.ports_worker, args=(state,), daemon=True
|
||||||
|
)
|
||||||
|
state.ports_thread.start()
|
||||||
|
|
||||||
dpg.start_dearpygui()
|
dpg.start_dearpygui()
|
||||||
|
|
||||||
dpg.destroy_context()
|
dpg.destroy_context()
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from dataflux.tags import (
|
|||||||
GRAPH_X_AXIS_SPEED,
|
GRAPH_X_AXIS_SPEED,
|
||||||
GRAPH_X_AXIS_TENG,
|
GRAPH_X_AXIS_TENG,
|
||||||
GRAPH_X_AXIS_VBAT,
|
GRAPH_X_AXIS_VBAT,
|
||||||
|
WINDOW_FILE_DIALOG_AUTOSAVE_BUFFERS,
|
||||||
WINDOW_LORA_CONNECTION_MENU,
|
WINDOW_LORA_CONNECTION_MENU,
|
||||||
WINDOW_FILE_DIALOG_DUMP_BUFFERS,
|
WINDOW_FILE_DIALOG_DUMP_BUFFERS,
|
||||||
WINDOW_SERIAL_CONNECTION_MENU,
|
WINDOW_SERIAL_CONNECTION_MENU,
|
||||||
@@ -27,8 +28,11 @@ def open_lora_connection_window(sender, app_data, user_data: AppState) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def open_serial_connection_window(sender, app_data, user_data: AppState) -> None:
|
def open_serial_connection_window(sender, app_data, user_data: AppState) -> None:
|
||||||
|
print("Handling serial window open callback")
|
||||||
dataflux.ui.routines.windows.update_window_serial_connection_menu_combo(user_data)
|
dataflux.ui.routines.windows.update_window_serial_connection_menu_combo(user_data)
|
||||||
|
print("Combo updated")
|
||||||
dpg.show_item(WINDOW_SERIAL_CONNECTION_MENU)
|
dpg.show_item(WINDOW_SERIAL_CONNECTION_MENU)
|
||||||
|
print("Window shown")
|
||||||
|
|
||||||
|
|
||||||
def menu_io_disconnect_lora(sender, app_data, user_data: AppState) -> None:
|
def menu_io_disconnect_lora(sender, app_data, user_data: AppState) -> None:
|
||||||
@@ -45,6 +49,10 @@ def menu_file_dump_buffers(sender, app_data, user_data: AppState) -> None:
|
|||||||
dpg.show_item(WINDOW_FILE_DIALOG_DUMP_BUFFERS)
|
dpg.show_item(WINDOW_FILE_DIALOG_DUMP_BUFFERS)
|
||||||
|
|
||||||
|
|
||||||
|
def menu_file_quit(sender, app_data, user_data) -> None:
|
||||||
|
dpg.stop_dearpygui()
|
||||||
|
|
||||||
|
|
||||||
def window_file_dialog_dump_buffers_ok(sender, app_data, user_data: AppState) -> None:
|
def window_file_dialog_dump_buffers_ok(sender, app_data, user_data: AppState) -> None:
|
||||||
user_data.buffer_dump_thread = Thread(
|
user_data.buffer_dump_thread = Thread(
|
||||||
target=dataflux.services.telemetry.buffer_dump,
|
target=dataflux.services.telemetry.buffer_dump,
|
||||||
@@ -54,6 +62,26 @@ def window_file_dialog_dump_buffers_ok(sender, app_data, user_data: AppState) ->
|
|||||||
user_data.buffer_dump_thread.start()
|
user_data.buffer_dump_thread.start()
|
||||||
|
|
||||||
|
|
||||||
|
def menu_file_autosave_buffers(sender, app_state, user_data: AppState) -> None:
|
||||||
|
if user_data.autosave_enabled:
|
||||||
|
user_data.autosave_enabled = False
|
||||||
|
user_data.autosave_buffer_thread = None
|
||||||
|
else:
|
||||||
|
dpg.show_item(WINDOW_FILE_DIALOG_AUTOSAVE_BUFFERS)
|
||||||
|
|
||||||
|
|
||||||
|
def window_file_dialog_autosave_buffers_ok(
|
||||||
|
sender, app_data, user_data: AppState
|
||||||
|
) -> None:
|
||||||
|
user_data.autosave_enabled = True
|
||||||
|
user_data.autosave_buffer_thread = Thread(
|
||||||
|
target=dataflux.services.telemetry.autosave_worker,
|
||||||
|
args=(user_data, app_data["file_path_name"]),
|
||||||
|
daemon=True,
|
||||||
|
)
|
||||||
|
user_data.autosave_buffer_thread.start()
|
||||||
|
|
||||||
|
|
||||||
def menu_window_select(sender, app_data, user_data: str) -> None:
|
def menu_window_select(sender, app_data, user_data: str) -> None:
|
||||||
dataflux.ui.routines.windows.toggle_window(user_data)
|
dataflux.ui.routines.windows.toggle_window(user_data)
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import dataflux.ui.routines
|
|||||||
|
|
||||||
from dataflux.state import AppState
|
from dataflux.state import AppState
|
||||||
from dataflux.tags import (
|
from dataflux.tags import (
|
||||||
BUTTON_SERIAL_CONSOLE_SEND,
|
|
||||||
INPUT_SERIAL_CONSOLE,
|
INPUT_SERIAL_CONSOLE,
|
||||||
TEXT_SERIAL_CONSOLE,
|
|
||||||
WINDOW_LORA_CONNECTION_MENU,
|
WINDOW_LORA_CONNECTION_MENU,
|
||||||
WINDOW_LORA_CONNECTION_MENU_COMBO,
|
WINDOW_LORA_CONNECTION_MENU_COMBO,
|
||||||
WINDOW_SERIAL_CONNECTION_MENU,
|
WINDOW_SERIAL_CONNECTION_MENU,
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ import dataflux.ui.routines
|
|||||||
from dataflux.state import AppState
|
from dataflux.state import AppState
|
||||||
|
|
||||||
|
|
||||||
def list_serial_ports() -> list[str]:
|
def list_serial_ports(state: AppState) -> list[str]:
|
||||||
ports = serial.tools.list_ports.comports()
|
|
||||||
valid_ports: list[str] = []
|
valid_ports: list[str] = []
|
||||||
for port in ports:
|
|
||||||
|
for port in state.ports:
|
||||||
if port.vid is not None and port.pid is not None:
|
if port.vid is not None and port.pid is not None:
|
||||||
valid_ports.append(port.device)
|
valid_ports.append(port.device)
|
||||||
|
|
||||||
@@ -224,5 +225,15 @@ def parse_uart_packet(body: bytes) -> dict | None:
|
|||||||
"speed": pkt.speed,
|
"speed": pkt.speed,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if lora.version == 3:
|
||||||
|
pkt = dataflux.telemetry_common.telemetry_common.unpack_packet3(payload)
|
||||||
|
return {
|
||||||
|
**base,
|
||||||
|
"type": "packet3",
|
||||||
|
"start_time": pkt.start_time,
|
||||||
|
"duration": pkt.duration,
|
||||||
|
"count": pkt.count,
|
||||||
|
}
|
||||||
|
|
||||||
print("Unknown payload")
|
print("Unknown payload")
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
|
# Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
from queue import Empty
|
from queue import Empty
|
||||||
from dataflux.state import AppState, Buffers
|
from dataflux.state import AppState, Buffers
|
||||||
import time
|
import time
|
||||||
@@ -19,54 +20,59 @@ def telemetry_worker(state: AppState):
|
|||||||
except Empty:
|
except Empty:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
state.latest_telemetry = dataframe
|
if dataframe["type"] == "packet2":
|
||||||
state.telemetry_valid = True
|
state.latest_telemetry = dataframe
|
||||||
|
state.telemetry_valid = True
|
||||||
|
with state.lock:
|
||||||
|
state.raw_buffers.timestamp.append(dataframe["time_stamp"])
|
||||||
|
state.raw_buffers.speed.append(dataframe["speed"])
|
||||||
|
state.raw_buffers.vbat.append(dataframe["vbat"])
|
||||||
|
state.raw_buffers.teng.append(dataframe["teng"])
|
||||||
|
state.raw_buffers.lat.append(dataframe["lat"])
|
||||||
|
state.raw_buffers.lng.append(dataframe["lng"])
|
||||||
|
|
||||||
with state.lock:
|
state.live_buffers_updated = True
|
||||||
state.raw_buffers.timestamp.append(dataframe["time_stamp"])
|
state.live_buffers.timestamp.clear()
|
||||||
state.raw_buffers.speed.append(dataframe["speed"])
|
state.live_buffers.speed.clear()
|
||||||
state.raw_buffers.vbat.append(dataframe["vbat"])
|
state.live_buffers.vbat.clear()
|
||||||
state.raw_buffers.teng.append(dataframe["teng"])
|
state.live_buffers.teng.clear()
|
||||||
state.raw_buffers.lat.append(dataframe["lat"])
|
state.live_buffers.lat.clear()
|
||||||
state.raw_buffers.lng.append(dataframe["lng"])
|
state.live_buffers.lng.clear()
|
||||||
|
|
||||||
state.live_buffers_updated = True
|
if not state.raw_buffers.timestamp:
|
||||||
state.live_buffers.timestamp.clear()
|
return
|
||||||
state.live_buffers.speed.clear()
|
|
||||||
state.live_buffers.vbat.clear()
|
|
||||||
state.live_buffers.teng.clear()
|
|
||||||
state.live_buffers.lat.clear()
|
|
||||||
state.live_buffers.lng.clear()
|
|
||||||
|
|
||||||
if not state.raw_buffers.timestamp:
|
last_timestamp = state.raw_buffers.timestamp[-1]
|
||||||
return
|
cutoff = last_timestamp - (state.live_buffer_len * 100)
|
||||||
|
|
||||||
last_timestamp = state.raw_buffers.timestamp[-1]
|
i = len(state.raw_buffers.timestamp) - 1
|
||||||
cutoff = last_timestamp - (state.live_buffer_len * 100)
|
|
||||||
|
|
||||||
i = len(state.raw_buffers.timestamp) - 1
|
while i >= 0 and state.raw_buffers.timestamp[i] >= cutoff:
|
||||||
|
elapsed_seconds = (
|
||||||
|
state.raw_buffers.timestamp[i] - last_timestamp
|
||||||
|
) / 100.0
|
||||||
|
state.live_buffers.timestamp.append(elapsed_seconds)
|
||||||
|
state.live_buffers.speed.append(state.raw_buffers.speed[i])
|
||||||
|
state.live_buffers.vbat.append(state.raw_buffers.vbat[i])
|
||||||
|
state.live_buffers.teng.append(state.raw_buffers.teng[i])
|
||||||
|
state.live_buffers.lat.append(state.raw_buffers.lat[i])
|
||||||
|
state.live_buffers.lng.append(state.raw_buffers.lng[i])
|
||||||
|
i -= 1
|
||||||
|
|
||||||
while i >= 0 and state.raw_buffers.timestamp[i] >= cutoff:
|
state.live_buffers.timestamp.reverse()
|
||||||
elapsed_seconds = (
|
state.live_buffers.speed.reverse()
|
||||||
state.raw_buffers.timestamp[i] - last_timestamp
|
state.live_buffers.vbat.reverse()
|
||||||
) / 100.0
|
state.live_buffers.teng.reverse()
|
||||||
state.live_buffers.timestamp.append(elapsed_seconds)
|
state.live_buffers.lat.reverse()
|
||||||
state.live_buffers.speed.append(state.raw_buffers.speed[i])
|
state.live_buffers.lng.reverse()
|
||||||
state.live_buffers.vbat.append(state.raw_buffers.vbat[i])
|
elif dataframe["type"] == "packet3":
|
||||||
state.live_buffers.teng.append(state.raw_buffers.teng[i])
|
print(dataframe["type"])
|
||||||
state.live_buffers.lat.append(state.raw_buffers.lat[i])
|
print(dataframe["start_time"])
|
||||||
state.live_buffers.lng.append(state.raw_buffers.lng[i])
|
print(dataframe["duration"])
|
||||||
i -= 1
|
print(dataframe["count"])
|
||||||
|
|
||||||
state.live_buffers.timestamp.reverse()
|
|
||||||
state.live_buffers.speed.reverse()
|
|
||||||
state.live_buffers.vbat.reverse()
|
|
||||||
state.live_buffers.teng.reverse()
|
|
||||||
state.live_buffers.lat.reverse()
|
|
||||||
state.live_buffers.lng.reverse()
|
|
||||||
|
|
||||||
|
|
||||||
def buffer_dump(state: AppState, path: str):
|
def buffer_dump(state: AppState, path: str) -> None:
|
||||||
save_path = Path(path)
|
save_path = Path(path)
|
||||||
if save_path.is_dir():
|
if save_path.is_dir():
|
||||||
save_path = save_path / "output.csv"
|
save_path = save_path / "output.csv"
|
||||||
@@ -97,3 +103,16 @@ def buffer_dump(state: AppState, path: str):
|
|||||||
writer.writerow(row)
|
writer.writerow(row)
|
||||||
|
|
||||||
state.buffer_dump_thread = None
|
state.buffer_dump_thread = None
|
||||||
|
|
||||||
|
|
||||||
|
def autosave_worker(state: AppState, path: str) -> None:
|
||||||
|
output_dir = Path(path)
|
||||||
|
ctr: int = 0
|
||||||
|
while state.autosave_enabled:
|
||||||
|
date_str = state.start_time.strftime("%m_%d_%Y_%H_%M")
|
||||||
|
filename = date_str + ".csv"
|
||||||
|
save_path = output_dir / filename
|
||||||
|
buffer_dump(state, save_path)
|
||||||
|
print(f"Autosave {ctr} complete")
|
||||||
|
ctr += 1
|
||||||
|
time.sleep(30)
|
||||||
|
|||||||
@@ -3,10 +3,13 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
from datetime import datetime
|
||||||
from threading import Lock, Thread
|
from threading import Lock, Thread
|
||||||
from serial import Serial
|
from serial import Serial
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
|
||||||
|
from serial.tools.list_ports_common import ListPortInfo
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Buffers:
|
class Buffers:
|
||||||
@@ -21,6 +24,11 @@ class Buffers:
|
|||||||
@dataclass
|
@dataclass
|
||||||
class AppState:
|
class AppState:
|
||||||
running: bool = True
|
running: bool = True
|
||||||
|
start_time: datetime = datetime.now()
|
||||||
|
|
||||||
|
ports: list[ListPortInfo] = field(default_factory=list)
|
||||||
|
ports_thread: Thread | None = None
|
||||||
|
ports_thread_running: bool = False
|
||||||
|
|
||||||
lora_port: Serial | None = None
|
lora_port: Serial | None = None
|
||||||
lora_thread: Thread | None = None
|
lora_thread: Thread | None = None
|
||||||
@@ -53,5 +61,7 @@ class AppState:
|
|||||||
live_buffer_len: int = 30
|
live_buffer_len: int = 30
|
||||||
|
|
||||||
buffer_dump_thread: Thread | None = None
|
buffer_dump_thread: Thread | None = None
|
||||||
|
autosave_buffer_thread: Thread | None = None
|
||||||
|
autosave_enabled: bool = False
|
||||||
|
|
||||||
lock: Lock = field(default_factory=Lock)
|
lock: Lock = field(default_factory=Lock)
|
||||||
|
|||||||
@@ -7,11 +7,13 @@ MENU_IO_CONNECT_SERIAL: str = "menu_io_connect_serial"
|
|||||||
MENU_IO_DISCONNECT_LORA: str = "menu_io_disconnect_lora"
|
MENU_IO_DISCONNECT_LORA: str = "menu_io_disconnect_lora"
|
||||||
MENU_IO_DISCONNECT_SERIAL: str = "menu_io_disconnect_serial"
|
MENU_IO_DISCONNECT_SERIAL: str = "menu_io_disconnect_serial"
|
||||||
MENU_FILE_DUMP_BUFFERS: str = "menu_file_dump_buffers"
|
MENU_FILE_DUMP_BUFFERS: str = "menu_file_dump_buffers"
|
||||||
|
MENU_FILE_AUTOSAVE_BUFFERS: str = "menu_file_autosave_buffers"
|
||||||
WINDOW_LORA_CONNECTION_MENU: str = "window_lora_connection_menu"
|
WINDOW_LORA_CONNECTION_MENU: str = "window_lora_connection_menu"
|
||||||
WINDOW_SERIAL_CONNECTION_MENU: str = "window_serial_connection_menu"
|
WINDOW_SERIAL_CONNECTION_MENU: str = "window_serial_connection_menu"
|
||||||
WINDOW_LORA_CONNECTION_MENU_COMBO: str = "window_lora_connection_menu_combo"
|
WINDOW_LORA_CONNECTION_MENU_COMBO: str = "window_lora_connection_menu_combo"
|
||||||
WINDOW_SERIAL_CONNECTION_MENU_COMBO: str = "window_serial_connection_menu_combo"
|
WINDOW_SERIAL_CONNECTION_MENU_COMBO: str = "window_serial_connection_menu_combo"
|
||||||
WINDOW_FILE_DIALOG_DUMP_BUFFERS: str = "window_file_dialog_dump_buffers"
|
WINDOW_FILE_DIALOG_DUMP_BUFFERS: str = "window_file_dialog_dump_buffers"
|
||||||
|
WINDOW_FILE_DIALOG_AUTOSAVE_BUFFERS: str = "window_file_dialog_autosave_buffers"
|
||||||
|
|
||||||
CHILD_WINDOW_SERIAL_CONSOLE: str = "child_window_serial_console"
|
CHILD_WINDOW_SERIAL_CONSOLE: str = "child_window_serial_console"
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@
|
|||||||
# Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
|
# Copyright (C) 2026 Association Exergie <association.exergie@gmail.com>
|
||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
STATUS_RED_DARK = (140, 35, 35, 255)
|
STATUS_RED_DARK = (140, 35, 35, 255)
|
||||||
STATUS_RED_BRIGHT = (205, 85, 85, 255)
|
STATUS_RED_BRIGHT = (205, 85, 85, 255)
|
||||||
|
|
||||||
STATUS_ORANGE_DARK = (160, 90, 20, 255)
|
STATUS_ORANGE_DARK = (160, 90, 20, 255)
|
||||||
STATUS_ORANGE_BRIGHT = (210, 140, 60, 255)
|
STATUS_ORANGE_BRIGHT = (210, 140, 60, 255)
|
||||||
|
|
||||||
STATUS_GREEN_DARK = (40, 130, 55, 255)
|
STATUS_GREEN_DARK = (40, 130, 55, 255)
|
||||||
STATUS_GREEN_BRIGHT = (95, 185, 115, 255)
|
STATUS_GREEN_BRIGHT = (95, 185, 115, 255)
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
import dearpygui.dearpygui as dpg
|
import dearpygui.dearpygui as dpg
|
||||||
|
|
||||||
import dataflux.config
|
|
||||||
from dataflux.services.serial import list_serial_ports
|
from dataflux.services.serial import list_serial_ports
|
||||||
from dataflux.state import AppState
|
from dataflux.state import AppState
|
||||||
from dataflux.tags import (
|
from dataflux.tags import (
|
||||||
@@ -18,7 +17,7 @@ from dataflux.tags import (
|
|||||||
|
|
||||||
|
|
||||||
def update_window_lora_connection_menu_combo(state: AppState) -> None:
|
def update_window_lora_connection_menu_combo(state: AppState) -> None:
|
||||||
ports: list[str] = list_serial_ports()
|
ports: list[str] = list_serial_ports(state)
|
||||||
if state.serial_port is not None and state.serial_thread_running:
|
if state.serial_port is not None and state.serial_thread_running:
|
||||||
port_name = state.serial_port.name
|
port_name = state.serial_port.name
|
||||||
|
|
||||||
@@ -28,7 +27,7 @@ def update_window_lora_connection_menu_combo(state: AppState) -> None:
|
|||||||
|
|
||||||
|
|
||||||
def update_window_serial_connection_menu_combo(state: AppState) -> None:
|
def update_window_serial_connection_menu_combo(state: AppState) -> None:
|
||||||
ports: list[str] = list_serial_ports()
|
ports: list[str] = list_serial_ports(state)
|
||||||
if state.lora_port is not None and state.lora_thread_running:
|
if state.lora_port is not None and state.lora_thread_running:
|
||||||
port_name = state.lora_port.name
|
port_name = state.lora_port.name
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ from dataflux.tags import (
|
|||||||
LIVE_DATA_VBAT_VALUE,
|
LIVE_DATA_VBAT_VALUE,
|
||||||
LIVE_DATA_VEHICLE_TIME_VALUE,
|
LIVE_DATA_VEHICLE_TIME_VALUE,
|
||||||
LIVE_DATA_SPEED_VALUE,
|
LIVE_DATA_SPEED_VALUE,
|
||||||
|
MENU_FILE_AUTOSAVE_BUFFERS,
|
||||||
MENU_IO_CONNECT_LORA,
|
MENU_IO_CONNECT_LORA,
|
||||||
MENU_IO_DISCONNECT_LORA,
|
MENU_IO_DISCONNECT_LORA,
|
||||||
MENU_FILE_DUMP_BUFFERS,
|
MENU_FILE_DUMP_BUFFERS,
|
||||||
@@ -43,6 +44,7 @@ from dataflux.tags import (
|
|||||||
THEME_STATUS_CONNECTED,
|
THEME_STATUS_CONNECTED,
|
||||||
THEME_STATUS_CONNECTED_BRIGHT,
|
THEME_STATUS_CONNECTED_BRIGHT,
|
||||||
THEME_STATUS_DISCONNECTED,
|
THEME_STATUS_DISCONNECTED,
|
||||||
|
WINDOW_FILE_DIALOG_AUTOSAVE_BUFFERS,
|
||||||
WINDOW_LORA_CONNECTION_MENU,
|
WINDOW_LORA_CONNECTION_MENU,
|
||||||
WINDOW_LORA_CONNECTION_MENU_COMBO,
|
WINDOW_LORA_CONNECTION_MENU_COMBO,
|
||||||
WINDOW_FILE_DIALOG_DUMP_BUFFERS,
|
WINDOW_FILE_DIALOG_DUMP_BUFFERS,
|
||||||
@@ -74,7 +76,18 @@ def build_windows(state: AppState) -> None:
|
|||||||
tag=MENU_FILE_DUMP_BUFFERS,
|
tag=MENU_FILE_DUMP_BUFFERS,
|
||||||
callback=dataflux.callbacks.menu.menu_file_dump_buffers,
|
callback=dataflux.callbacks.menu.menu_file_dump_buffers,
|
||||||
)
|
)
|
||||||
dpg.add_menu_item(label="Quit")
|
dpg.add_menu_item(
|
||||||
|
label="Autosave Buffers",
|
||||||
|
enabled=True,
|
||||||
|
check=True,
|
||||||
|
default_value=False,
|
||||||
|
tag=MENU_FILE_AUTOSAVE_BUFFERS,
|
||||||
|
callback=dataflux.callbacks.menu.menu_file_autosave_buffers,
|
||||||
|
user_data=state,
|
||||||
|
)
|
||||||
|
dpg.add_menu_item(
|
||||||
|
label="Quit", callback=dataflux.callbacks.menu.menu_file_quit
|
||||||
|
)
|
||||||
with dpg.menu(label="IO"):
|
with dpg.menu(label="IO"):
|
||||||
dpg.add_menu_item(
|
dpg.add_menu_item(
|
||||||
label="Connect LoRa",
|
label="Connect LoRa",
|
||||||
@@ -427,3 +440,15 @@ def build_windows(state: AppState) -> None:
|
|||||||
user_data=state,
|
user_data=state,
|
||||||
):
|
):
|
||||||
dpg.add_file_extension(".csv")
|
dpg.add_file_extension(".csv")
|
||||||
|
|
||||||
|
with dpg.file_dialog(
|
||||||
|
directory_selector=True,
|
||||||
|
show=False,
|
||||||
|
tag=WINDOW_FILE_DIALOG_AUTOSAVE_BUFFERS,
|
||||||
|
width=700,
|
||||||
|
height=400,
|
||||||
|
modal=True,
|
||||||
|
callback=dataflux.callbacks.menu.window_file_dialog_autosave_buffers_ok,
|
||||||
|
user_data=state,
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import dearpygui.dearpygui as dpg
|
|||||||
import datetime
|
import datetime
|
||||||
import time
|
import time
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
|
import serial.tools.list_ports
|
||||||
|
|
||||||
from dataflux.state import AppState
|
from dataflux.state import AppState
|
||||||
from dataflux.tags import (
|
from dataflux.tags import (
|
||||||
GRAPH_SERIES_SPEED,
|
GRAPH_SERIES_SPEED,
|
||||||
GRAPH_SERIES_TENG,
|
GRAPH_SERIES_TENG,
|
||||||
GRAPH_SERIES_VBAT,
|
GRAPH_SERIES_VBAT,
|
||||||
GRAPH_X_AXIS_SPEED,
|
|
||||||
LIVE_DATA_TENG_VALUE,
|
LIVE_DATA_TENG_VALUE,
|
||||||
LIVE_DATA_UTC_TIME_VALUE,
|
LIVE_DATA_UTC_TIME_VALUE,
|
||||||
LIVE_DATA_VBAT_VALUE,
|
LIVE_DATA_VBAT_VALUE,
|
||||||
@@ -23,6 +23,12 @@ from dataflux.tags import (
|
|||||||
from dataflux.ui.routines.serial import append_text_to_console
|
from dataflux.ui.routines.serial import append_text_to_console
|
||||||
|
|
||||||
|
|
||||||
|
def ports_worker(state: AppState) -> None:
|
||||||
|
while state.ports_thread_running:
|
||||||
|
state.ports = serial.tools.list_ports.comports()
|
||||||
|
time.sleep(5)
|
||||||
|
|
||||||
|
|
||||||
def ui_worker(state: AppState):
|
def ui_worker(state: AppState):
|
||||||
last_datetime: str = ""
|
last_datetime: str = ""
|
||||||
last_veh_time: str = ""
|
last_veh_time: str = ""
|
||||||
@@ -31,6 +37,10 @@ def ui_worker(state: AppState):
|
|||||||
last_teng: str = ""
|
last_teng: str = ""
|
||||||
no_data_written = False
|
no_data_written = False
|
||||||
while state.running:
|
while state.running:
|
||||||
|
# if state.autosave_enabled:
|
||||||
|
# dpg.set_value(MENU_FILE_AUTOSAVE_BUFFERS, True)
|
||||||
|
# else:
|
||||||
|
# dpg.set_value(MENU_FILE_AUTOSAVE_BUFFERS, False)
|
||||||
now = datetime.now(timezone.utc)
|
now = datetime.now(timezone.utc)
|
||||||
formatted = now.strftime("%H:%M:%S")
|
formatted = now.strftime("%H:%M:%S")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user