summaryrefslogtreecommitdiff
path: root/plugins
AgeCommit message (Collapse)Author
2026-09-19Redesign Signal/Channel naming and fix pin-remap breaking referencesChristian Kolset
Arduino analog Signal ids used to be the pin name itself, so fixing a wrong pin silently changed the id and orphaned any plot trace, control, or filter pipeline pointing at it. Analog Signal ids are now positional (ai0, ai1, ...) and decoupled from the underlying pin, matching how digital I/O already worked. More broadly, formalizes a Device -> Signal -> Channel -> Plot naming model (SignalConfig for physical device channels, Channel for derived/ computed ones) and adds core/reference_registry.py to propagate any Signal or Channel id rename through plot traces, controls, and filter pipelines instead of leaving them dangling. Signal ids are now editable in the Signals tab with the same propagation. .labui profile schema bumped to v2.0 with a transparent migration for old files, including remapping old pin-name Signal ids to the new positional ones. Removed six confirmed-dead files (two legacy device classes, four superseded top-level ui/ duplicates).
2026-08-17Fix motion capture UI freezes: throttling, async camera open/scan, stale pollChristian Kolset
Several compounding freeze sources in plugins/motion_capture/: - tracker.py: _run_real had no frame-rate cap independent of the camera's configured fps (up to 120fps/2560x1440 was possible), and no bound on consecutive failed reads — a camera that "opens" (cv2 isOpened() can lie, seen with Windows MSMF/obsensor) but never actually delivers frames would get hammered forever. Added a 20Hz processing cap, a real test-read before committing to a camera, and a give-up-after-30-failures fallback to simulation. - tracker.py/device.py: cv2.VideoCapture() opening a real camera is a slow, blocking call — CameraTracker.start() used to do this synchronously on the caller's thread, which froze the whole app when ProfileManager.apply() called it during profile load. Now runs on the background thread; status reporting (CameraDevice) moved to an on_result callback since the caller can no longer learn the outcome synchronously. - window.py: the Camera View preview ran a 30Hz GUI-thread timer doing a full-frame copy + QImage/QPixmap rebuild every tick unconditionally (no visibility check) — dropped to 10Hz and skips entirely when hidden. Camera enumeration (list_cameras(), up to 8 sequential cv2.VideoCapture probes) also ran inline in the window constructor, blocking it open the same way camera_panel.py's CameraScanThread already avoided for the Add Device dialog — moved to the same async pattern here. config_window.py: separately, ConfigWindow._dev_poll (device status label refresh) was stopped in closeEvent and never restarted, since MainWindow reuses the same ConfigWindow instance across opens — invisible before because connect() was synchronous, but with the above change a device can sit in CONNECTING for a while, and a stale poll made that look stuck forever after reopening the window. Restart it in showEvent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-13Removed tracking of temp files and updated esp32_stringPot.inoChristian Kolset
- Removed log file and plugin enabled states. - Updated esp32_stringPot.ino: added time delay for config screen and group declaration together.
2026-08-01Rename LabDAQ → LabUI and overhaul plugin systemChristian Kolset
Branding: - Rename app, window title, file extension (.labdaq → .labui), user data dirs (~/.labui/), spec file (labdaq.spec → labui.spec), and APP_NAME throughout all source, docs, and config files Plugin system: - Plugins no longer bundled in the PyInstaller build — installed at runtime by users via Settings → Plugins → Install Plugin (zip) - PluginManager now takes user_dir + extra_scan_dirs; user plugins live in ~/.labui/plugins/, dev scan additionally covers project plugins/ - install_from_zip / uninstall / is_user_installed added to PluginManager - vendor/ dir inside plugin zips: prepended to sys.path at load time so plugins can ship their own deps without requiring pip on end-user machine - source_url field in manifest.json: shown as Download button in the missing-plugins dialog when a profile requires an absent plugin - Frozen-app pip install now targets ~/.labui/plugin_packages/ using a real system Python (sys.executable is the exe in frozen builds) Profile loading: - Profile now stores plugins_manifest snapshot (id, name, version, source_url) alongside plugins_enabled - On load, missing or dep-broken plugins trigger MissingPluginsDialog before the rest of the profile is applied; user can install from zip or download via source_url in-dialog, or cancel the load - Plugin reconciliation only enables installed plugins — missing ones are not written to enabled.json UI: - Version label added to status bar (bottom-right, muted colour) - Settings → Plugins tab: Install Plugin… button, per-plugin Remove button for user-installed plugins, live list refresh after install/remove Docs: - New docs/building.md covers the full release pipeline - docs/plugin-development.md updated for new install flow, vendoring, source_url, profile behaviour, and distribution instructions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-29Merge branch 'feat/plugin-pip-install-prompt'Christian Kolset
2026-07-29Check plugin dependencies before loading, warn instead of silent console errorChristian Kolset
manifest.json already had an unused "requires" field (motion_capture's manifest lists opencv-python>=4.8.0) — PluginManifest never parsed it, so a missing dependency just crashed the import inside _load_plugin(), caught by the broad except and only ever printed to the console. Adds PluginManifest.requires, PluginManager.missing_requirements()/ get_missing_dependencies(), and an early check in _load_plugin() that skips the risky import entirely when a requirement is missing. main_window.plugin_enable() now checks this before calling PluginManager.enable() and shows a QMessageBox with the missing packages and a pip install command instead of failing silently. Checks by distribution name via importlib.metadata (what pip installed it as), not import name — those differ for packages like opencv-python (imports as cv2) or pyserial (imports as serial), so importlib.util. find_spec() would give false negatives. Also fixes a button-state bug this surfaces: SettingsWindow's plugin toggle optimistically flipped to "Disable" the instant Enable was clicked, before knowing whether enabling actually succeeds — pre-existing, but now trivially reproducible (any plugin missing a dependency). Enable no longer flips the button immediately; main_window calls the new sync_plugin_button() once the real outcome is known. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-29Add editable device display name, persist it across profile save/loadChristian Kolset
DeviceInfo.name existed but was hardcoded per device type and never operator-editable. Adds a Display Name field to Add Device and makes the Info-tab Name field in the device config dialog editable, and threads the name through get_save_config()/ProfileManager.apply() so a custom name survives a .labdaq save/reload instead of reverting to the type default. Name is applied post-construction rather than as a constructor kwarg, since no device factory declares a "name" param. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-28Update CML protocol documentation and improve command handling; adjust ↵Christian Kolset
motion_capture setting to false
2026-06-09Motion capture: profile support, FPS config, persistent tracking, window stateChristian Kolset
Profile integration: - CameraDevice.get_save_config() serialises camera_index, simulate, resolution, fps — cameras now persist in .labdaq profiles - ProfileManager.register/unregister_device_factory() lets plugins register their device classes for profile restoration without core → plugin dependency - MotionCapturePlugin registers CameraDevice factory on load/unload Camera configuration: - Add Frame Rate combo to CameraPanel (Default/15/24/30/60/120 fps) defaults to 30 fps; flows through to CAP_PROP_FPS on connect - tracker.start() accepts fps param alongside existing resolution Tracking persistence: - CameraTracker.is_running() — checks thread alive state - MotionCaptureWindow initialises _connected from tracker.is_running() so reopening the window resumes the live feed without restarting the camera or losing the active tracking state Window state: - Plugin saves px_per_mm + camera_idx when window closes - Reopened window restores saved values and syncs mode/shape UI from tracker state via restore_ui_state() (signals blocked to avoid resetting tracker) - Window type changed to Qt.WindowType.Window for independent close button on all Linux WMs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09Upgrade motion capture: template matching, frame-freeze selection, resolutionChristian Kolset
Tracking: - Add "template" mode (default) using snapshot + shape-masked matchTemplate - Add "csrt" mode as alternative for texture-rich targets - set_roi_rect(x, y, w, h, frame_rgb) initialises from exact selection rect - set_roi() delegates to set_roi_rect (centred square, backwards-compat) - start() accepts resolution=(w, h) to set camera capture resolution Selection UX: - Replace QLabel feed with FrameSelector widget (custom QWidget) - "Click to Track" freezes frame; user scrolls to zoom (anchored to cursor), right-drags to pan, left-drags to draw rubber-band selection - Shape preview: rectangle or inscribed ellipse depending on mode - "Confirm Selection" extracts template from frozen frame and starts tracking - "Clear" cancels selection or clears active tracking Configuration: - CameraPanel adds Resolution combo (Default / 640×480 / 720p / 1080p / 1440p) - CameraDevice stores and forwards resolution to tracker.start() - Template Match listed first in Mode combo; shape combo hidden for CSRT Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04Restore Motion Capture toolbar button with multi-camera supportChristian Kolset
get_toolbar_actions() returns a checkable 🎥 button. On click: - 0 camera devices → info message, button unchecks - 1 camera device → opens MotionCaptureWindow directly - N camera devices → QInputDialog picker, opens selected device's window Windows tracked per device_id; closing a window removes it from the map and unchecks the button when none remain. on_unload closes all open windows before deregistering the Camera panel. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-04Redesign motion capture plugin as Camera device typeChristian Kolset
Plugin now registers a "Camera" option in the Add Device dialog on load (removes it on unload) instead of auto-creating a single device. - camera_panel.py (new): CameraPanel with CameraScanThread that probes OpenCV indices 0–5, lists found cameras with resolution, shows "No cameras detected" when none available, simulation checkbox. build_device() returns CameraDevice for the selected index. - device.py: rewrite MotionCaptureDevice → CameraDevice. Each instance owns its own CameraTracker created in connect(). Status is CONNECTED or SIMULATED based on tracker.simulated. get_config_widget() shows source/status and an "Open Camera View" button that launches the existing MotionCaptureWindow for that device's tracker. Backward-compat alias MotionCaptureDevice = CameraDevice kept for saved profiles. - plugin.py: simplified to on_load/_PANELS registration + pixel_to_mm filter. No auto-devices, no toolbar button, no settings widget. Camera data flows through the standard Device → Signal → Channel → Plot pipeline like any other device. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Remove __pycache__ from trackingChristian Kolset
2026-06-03Fix settings/plugin window bugs; remove example pluginChristian Kolset
- Add missing QGroupBox import to settings_window (caused silent crash on open) - Remove Controls tab and _controls_tab() method from settings - Clamp child window positions to screen bounds so they don't go off-screen on Windows when main window is maximized - Apply same screen-clamp fix to Motion Capture plugin window - Delete example plugin; disable it in enabled.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Motion capture: camera selection dropdownChristian Kolset
Replace camera index spinbox with a combo listing detected cameras by name. On Linux enumerates /dev/video* and reads device names from sysfs (fast, no probing). Fallback probes cv2.VideoCapture indices 0-7 on other platforms. Simulation entry always appended as last option. Also adds explicit simulation mode (index -1) to tracker.start() and a rescan button (⟳) in both the main window and the Settings > Plugins widget. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Added Motion Capture pluginChristian Kolset
Tracks a user-selected point via webcam (OpenCV CSRT tracker) and streams x_pos / y_pos pixel coordinates as live channels into the acquisition pipeline. Falls back to a Lissajous figure simulation when opencv-python is not installed, so the plugin works immediately without hardware. - tracker.py: background thread, real camera + sim modes, thread-safe API - device.py: BaseDevice reading x/y from tracker, wires into engine - filter.py: custom pixel_to_mm filter (registered in FILTER_CLASSES) - window.py: floating tool window, live feed, click-to-track ROI selection - plugin.py: LabPlugin wiring all pieces together, toolbar button, settings widget, profile save/restore Also: PluginAction.button_ref_callback lets plugins store a ref to their toolbar button so they can uncheck it when their window closes. opencv-python install note added to requirements.txt. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03Added plugin/add-on systemChristian Kolset
Plugins live in plugins/<name>/ with a manifest.json and a LabPlugin subclass. Enabled/disabled in Settings > Plugins tab; state persists in plugins/enabled.json and in .labdaq profiles (loading a profile enables/disables plugins to match). Plugins can contribute toolbar buttons, BaseDevice instances (auto-wired into acquisition pipeline), custom signal filter classes, a settings widget, and profile state via get_save_state/apply_save_state. Load errors now report the exact failing stage (file not found, class missing, on_load crash). Includes example plugin skeleton and docs/plugin-development.md. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>