Commit Graph
24 Commits
Author SHA1 Message Date
jensandClaude Sonnet 4.6 cd8367e5d0 Dashboard: fix display of flat phys fields (procedural domain)
The outer loop in DashboardTab.update assumed a 3-level hierarchy
(domain → object → fields).  Procedural fields sit one level higher
(domain → field directly).  Check _is_phys() first and render value /
unit into the correct columns instead of descending into the dict and
showing 'value' and 'unit' as separate rows.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 17:52:32 +02:00
jensandClaude Sonnet 4.6 e6c9f7d687 Plot tooltip: show cursor timestamp (HH:MM:SS) above trace values
Add a small dimmed timestamp label at the top of PlotTooltip.
set_values() now accepts ts_str as first argument; _on_mouse_move
formats the cursor x-position as HH:MM:SS and passes it through.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 17:05:13 +02:00
jensandClaude Sonnet 4.6 55719010da Docs: full README rewrite + gui_client.py module docstring update
README now covers:
- Updated diff-mode section (self-describing protocol, no _diff marker)
- Full GUI section with Connector/Dashboard/Plot tab descriptions
- Plot mouse interactions table (scroll, Shift+scroll, drag)
- Module reference for all server/, utils/, and gui_client classes
- --dry flag and all credential-file keys documented

gui_client.py module docstring updated to list tabs and mouse interactions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 17:01:42 +02:00
jensandClaude Sonnet 4.6 d0e4ec374c Plot tab: axis-selective wheel zoom (X default, Shift+wheel for Y)
Add PlotViewBox subclassing pg.ViewBox. Overrides wheelEvent to route
plain scroll to the X axis and Shift+scroll to the Y axis, both centred
on the cursor position. Passed as viewBox= to every PlotWidget so the
behaviour applies uniformly across all 8 plots.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 16:56:02 +02:00
jensandClaude Sonnet 4.6 ad3cbf4859 Plot tab: auto-zoom Y axis on first draw after connect / trace change
Track a _needs_autozoom flag per plot. Set True at startup, on
reconnect (clear_data), and when a trace is added or removed. In
_redraw, when the flag is set and visible data exists, fit the Y range
to the data (with 10% margin) then clear the flag — subsequent live
updates leave the user's manual Y zoom undisturbed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 16:50:14 +02:00
jensandClaude Sonnet 4.6 849473acc0 Plot tab: floating tooltip showing trace values at crosshair position
Add PlotTooltip — a frameless child widget that appears next to the
mouse cursor whenever it moves over a plot. It lists each active trace
with a colored bullet, short name, and the nearest y-value (unit
appended). The tooltip is repositioned on every mouse-move event and
clamped to stay within the plot widget bounds. Hidden on mouse-exit and
on clear_data (reconnect).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 16:42:32 +02:00
jensandClaude Sonnet 4.6 5e2aa3f17d Plot tab: HH:MM:SS x-axis ticks, date label in control bar
Replace pg.DateAxisItem with a custom TimeAxisItem that formats ticks
as HH:MM:SS, eliminating locale-dependent day/date prefixes on the axis.

Add a per-plot date label (right-aligned in the control bar) that shows
the date range of the visible window — single date when the view stays
within one day, "YYYY-MM-DD – YYYY-MM-DD" when it spans midnight.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 16:36:57 +02:00
jensandClaude Sonnet 4.6 ca5b284e9a Remove _diff marker: use self-describing jay_diff protocol
Server (network.py): send every record in diff mode starting from
prev={}, including the first — fixes history drop on new client connect.

Collect (collect.py): remove payload["_diff"] = True from live broadcast.

GUI client (gui_client.py): always call jay_merge_full in diff mode;
drop the _diff key check that gated reconstruction.

CLI client (client.py): fix `args.diff or True` guard that made --diff
irrelevant.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 16:08:33 +02:00
jensandClaude Sonnet 4.6 2adebf82ca gui_client: fix diff mode display corruption via deepcopy on emit
jay_merge_full/jay_merge_update mutates _state nested dicts in place.
The previously emitted dict(_state) was a shallow copy sharing those
nested dicts, so background-thread merges retroactively corrupted
already-emitted snapshots: timestamps were correct (strings are
immutable) but Y values all converged to the latest record's values.

Fix: emit copy.deepcopy(_state) so each snapshot is fully independent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 14:45:09 +02:00
jensandClaude Sonnet 4.6 56ed4ac265 Add opt-in diff mode for network transmission (--diff / Diff mode checkbox)
Server (collect.py --diff):
- History burst: first record sent full, subsequent as jay_diff_full diffs
- Live broadcast: each snapshot diffed against the previous one
- Diff payloads tagged with "_diff": true

Client (client.py --diff):
- Reconstructs full state via jay_merge_full before printing

GUI (Connector tab "Diff mode" checkbox):
- TcpReader.connect_to() accepts diff_mode; maintains _state dict
- Merges incoming diffs before emitting to Dashboard/Plot
- Checkbox state persisted to plot_settings.json

Both sides default to off; must be enabled consistently on server and client.
utils/__init__.py added so utils.jay_diff is importable as a package.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 14:34:34 +02:00
jensandClaude Sonnet 4.6 d4cbe110d6 gui_client: debounce plot redraws to speed up initial record import
Replace direct _redraw() calls in PlotTab.update() with a 100 ms
single-shot QTimer. During a burst of incoming records (e.g. 500
history records on connect) only the data is accumulated; a single
redraw fires 100 ms after the last record arrives instead of once
per record (~4000 pyqtgraph redraws avoided).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 14:07:50 +02:00
jensandClaude Sonnet 4.6 89810ce95b gui_client: clear plot data on connect/reconnect
Add PlotTab.clear_data() which resets _series and _units, then redraws.
Called in MainWindow._connect() before opening the socket so stale data
from a previous session never mingles with fresh history from the server.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 13:36:26 +02:00
jensandClaude Sonnet 4.6 efc21763a3 gui_client: fit x-axis to actual data when less than window size
Track the earliest timestamp across plotted traces (starting from None,
not cutoff) so setXRange uses the first real data point as the left
bound — no empty gap when data doesn't fill the full time window.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 13:31:40 +02:00
jensandClaude Sonnet 4.6 9052323baa gui_client: persist connection settings and fix plot history depth
- Save host/port to plot_settings.json on connect; restore on startup
- Raise MAX_PLOT_POINTS from 200 to 2880 so 24 h of data is retained
  even at 30 s polling intervals

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 09:04:04 +02:00
jensandClaude Sonnet 4.6 7d9d928bb1 Move time window to per-plot spinbox in control bar
Replaces the single global toolbar spinbox with one QSpinBox per plot,
placed between the '+' button and the trace chips. Each plot has an
independent 1–24 h window; values are persisted in plot_settings.json
under 'time_windows'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 23:55:00 +02:00
jensandClaude Sonnet 4.6 02814782bf Add global time window control to Plot tab (1–24 h)
A spinbox above the plot grid sets the visible x range for all 8 plots.
Data outside the window is excluded from each redraw; x axis is fixed to
[now - window, now]. Setting is persisted in plot_settings.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 23:40:41 +02:00
jensandClaude Sonnet 4.6 9d7561ba2f Apply nmea_client dark theme across all tabs and plots
Color palette taken directly from nmea_client/gui/plot_widget.py:
- Background #1a1a2e / #12121e, borders #2a2a4a/#3a3a5e,
  text #aaaacc/#ddddee, connected #4CAF50, error #F44336
- Trace colors: Material palette (blue, red, green, orange, …)
- Plot widget background overridden from "white" to #12121e
- pyqtgraph foreground set to #aaaacc

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:34:53 +02:00
jensandClaude Sonnet 4.6 8797c774e9 Plot tab: abbreviated names in combo, 8 plots with scroll, remove toolbar
- Trace selection combos show short labels (_trace_label) with full key
  stored as item data; width auto-adjusts to content (min 120 px)
- Extended plot grid from 4 to 8 (4×2) wrapped in QScrollArea
- Removed reset-zoom toolbar and cursor readout area

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 22:11:01 +02:00
jensandClaude Sonnet 4.6 8f1dc34991 Fix erratic axis scaling when hovering over plots
InfiniteLine was included in auto-range calculations, causing the view
to rescale on every cursor move. Add it with ignoreBounds=True in both
the initial setup and after each redraw.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 21:57:23 +02:00
jensandClaude Sonnet 4.6 9f0bdec9f1 Redesign plot tab: per-plot add/remove traces, persist settings, readable axes
- Replace static combo grid with a control bar above each plot:
  add-trace dropdown + "+" button; active traces shown as colored chips with
  "×" to remove (max 4 per plot)
- Save trace selection to ~/.config/we_monitor/plot_settings.json on every
  change; restore automatically once matching signals arrive from the server
- Remove tiny tick-font overrides so axis labels are readable at default size
- Show received record count in the status bar

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 21:51:39 +02:00
jensandClaude Sonnet 4.6 b38f8d052e Replace matplotlib with pyqtgraph in Plot tab
- pg.PlotWidget (2×2 grid) with DateAxisItem for proper time axis
- Built-in pan (left drag), zoom (right drag / scroll wheel), Reset zoom button
- pg.InfiniteLine cursor with pg.SignalProxy for smooth 30 fps tracking
- Cursor value label shows nearest-point values colour-coded per trace
- Legend auto-updated via pi.legend.clear() + named plot() calls
- matplotlib removed from requirements.txt

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 21:08:58 +02:00
jensandClaude Sonnet 4.6 2bbfcc7084 Scale plot tab to fill available window space at fullscreen
Removed the QScrollArea wrapper and fixed figure-height calculation.
FigureCanvasQTAgg now fills the tab with an Expanding size policy so
all 8 subplots fit in the visible area at 1920x1200 without scrolling.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 20:34:16 +02:00
jensandClaude Sonnet 4.6 1b0a8670e5 Fix spurious disconnect after first message in GUI client
create_connection(timeout=5) left a 5-second read timeout on the
socket. Any collection interval longer than 5 s caused recv() to
raise socket.timeout, which was caught as OSError and reported as
a lost connection. Switch to blocking mode with settimeout(None)
immediately after the connect handshake.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 20:25:33 +02:00
jensandClaude Sonnet 4.6 f0e0c9c6ae Add PyQt5 GUI client with Connector, Dashboard, and Plot tabs
- Connector tab: host/port fields, connect/disconnect button, status
- Dashboard tab: live QTreeWidget of the full snapshot hierarchy;
  physical values show value and unit in separate columns;
  expand state preserved across refreshes
- Plot tab: matplotlib time-series subplots (2 columns) for every
  physical {value, unit} field, scrollable, auto-layout on new keys
- TcpReader runs in a daemon thread and delivers messages via
  Qt signals so the UI never blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 20:06:50 +02:00