Core Module API
auth_manager.py
File: core\auth_manager.py
class AuthManager (line 11)
Manages user authentication and local account storage. Passwords are hashed with PBKDF2-HMAC-SHA256 and salt.
Public Methods:
* get_users_path(cls) — No docstring
* load_users(cls) — No docstring
* save_users(cls, users: Dict[str, dict]) — No docstring
* initialize(cls) — Ensure default admin user exists if no users.
* register(cls, username, password, role, users_dict) — Register a new user.
* login(cls, username, password) — Attempt login. Returns True if successful.
* logout(cls) — No docstring
* get_current_user(cls) — No docstring
* is_admin(cls) — No docstring
config_manager.py
File: core\config_manager.py
class ConfigManager (line 5)
Centralized configuration management. Stores settings in AppData/settings.json.
Public Methods:
* initialize(cls) — Load settings from disk.
* get(cls, key, default) — Get a setting value.
* set(cls, key, value) — Set a setting value and save.
* save(cls) — Save settings to disk.
* get_data_path(cls) — Return the user-configured data path, or default AppData path.
data_parser.py
File: core\data_parser.py
class DataParser (line 27)
Parses incoming serial data (Compact Protocol).
Handles both binary packets (V3.13) and text-based responses. Parsed data is pushed to a thread-safe queue for consumption by the UI.
Constructor: DataParser(data_queue: queue.Queue)
Initialize the parser.
Args: data_queue: Thread-safe queue for parsed data messages.
Public Methods:
* start_time() — Backward compatibility for start_time attribute.
* start_time(value: Optional[int]) — No docstring
* packet_pattern() — Backward compatibility for packet_pattern attribute.
* parse_binary_packet(raw_data: bytes) — Parse a 44-byte binary packet: [AA D0][Payload 41][CS 1]
Args:
raw_data: Raw 44-byte packet dat
* parse_line(line: str) — Parse a raw line from serial.
Args: line: Text line from serial port
Returns:
True if
* parse_json_response(line: str, extra_data: Any) — Compatibility shim for ExperimentManager.
* reset() — Reset parser state.
* get_column_names() — Get current column headers.
* update_headers(header_str: str) — Update headers from CSV string.
Args: header_str: Comma-separated header string
Returns:
experiment_manager.py
File: core\experiment_manager.py
class ExperimentManager (line 19)
Orchestrates the experiment: - Runs sweeps (SET_DAC -> Wait -> GET_SAMPLE) - Runs stability tests (SET_DAC -> Sample over time) - Polls status (GET_STATUS) when idle
Constructor: ExperimentManager(serial_controller)
Public Methods:
* register_pong() — Called by GUI when [ACK:PONG] is received.
* set_sensor(on: bool) — Send CMD_SET_SENSOR to hardware and update tracked state.
* set_fan(on: bool) — Send CMD_SET_FAN to hardware and update tracked state.
* start_monitoring() — Starts the background monitoring thread.
* stop_monitoring() — Stops the monitoring thread.
* start_sweep(start_val, end_val, step_val, samples_per_step) — Starts the sweep in a separate thread.
* start_stability_test(intensity, duration, interval_ms) — Starts the stability test in a separate thread.
export_manager.py
File: core\export_manager.py
class ExportManager (line 13)
Public Methods:
* export_to_csv(experiment_data: Dict[str, Any], filepath: Path) — Export a single experiment to CSV.
* export_batch_csv(experiments: List[Dict[str, Any]], output_dir: Path) — Export multiple experiments as individual CSV files in the output directory.
* export_combined_csv(experiments: List[Dict[str, Any]], filepath: Path) — Export multiple experiments into a single combined CSV file.
Adds an 'Experiment ID' and 'Label' col
* export_full_history_archive(history: Dict[str, Any], filepath: Path) — Create a ZIP archive containing all experiments as JSON files and a summary CSV.
firmware_manager.py
File: core\firmware_manager.py
class FirmwareManager (line 15)
Manage Arduino firmware compilation and upload.
Constructor: FirmwareManager()
Public Methods:
* is_cli_available() — Check if Arduino CLI is available.
* get_cli_version() — Get Arduino CLI version.
* get_embedded_firmware_path() — Get path to embedded firmware file.
* get_firmware_version_from_file(path: Path) — Extract firmware version from .ino file.
* list_connected_boards() — List connected Arduino boards.
* compile_firmware(firmware_path: Path) — Compile firmware without uploading.
Returns:
(success: bool, message: str)
* upload_firmware(port: str, firmware_path: Path) — Compile and upload firmware to device.
Args:
port: Serial port (e.g., "COM3")
firmware_path
* verify_device_version(serial_controller) — Check device firmware version and compare to embedded.
Returns: (device_version, needs_update)
Module Functions:
* get_firmware_manager() — No docstring
history_manager.py
File: core\history_manager.py
Module Functions:
* load_history() — Loads experiment history from the JSON file in AppData.
Returns an empty dictionary if the file does
* save_history(history: Dict[str, Any]) — Saves the entire experiment history to the JSON file.
Returns True on success.
* add_experiment(history: Dict[str, Any], exp_id: str, data: Dict[str, Any]) — Adds a single experiment to the history and saves it.
* delete_experiment(history: Dict[str, Any], exp_id: str) — Deletes a single experiment from the history and saves it.
* delete_experiments(history: Dict[str, Any], exp_ids: list[str]) — Deletes multiple experiments from the history and saves it.
* move_experiments(history: Dict[str, Any], exp_ids: list[str], target_folder: str) — Moves multiple experiments to a target folder.
* archive_experiments(history: Dict[str, Any], exp_ids: list[str], archive: bool) — Sets the archived status for multiple experiments.
* get_folders(history: Dict[str, Any]) — Returns a list of unique folders found in the history.
* get_experiment(history: Dict[str, Any], exp_id: str) — Gets a single experiment by ID.
* list_experiments(history: Dict[str, Any], sort_by, reverse, filter_folder) — Returns list of experiment IDs, optionally filtered and sorted.
* migrate_old_history(old_path: Path) — Migrate history from old local path to AppData.
Call this once at app startup.
mock_serial.py
File: core\mock_serial.py
class MockSerial (line 31)
Simulates the Acetone Motherboard V3.13 Firmware.
Provides synthetic data, responds to binary commands, and handles payloads. Used for testing and development without real hardware.
Constructor: MockSerial()
Public Methods:
* inject_error(code: int) — Forces the next command to return an error.
* set_noise_level(level: float) — Set noise multiplier for sensor readings.
* simulate_disconnect() — Simulate a disconnection.
* set_sim_battery(volts: float) — Set simulated battery voltage.
* set_sim_temp(temp: float) — Set simulated LED temperature.
* set_sim_sensor(volts: float) — Set simulated sensor voltage.
* close() — Close the mock connection.
* flush() — Flush buffers (no-op for mock).
* reset_input_buffer() — Clear input buffer and reset state machine.
* in_waiting() — Return number of bytes waiting.
* read(size: int) — Read bytes from the mock output buffer.
* write(data: bytes) — Process incoming data (commands from host).
profile_manager.py
File: core\profile_manager.py
class ProfileManager (line 5)
Manages loading, saving, and deleting experiment profiles. Profiles are stored in AppData via StorageManager. Format: {"Profile Name": {"start": 0, "end": 100, "step": 10}}
Constructor: ProfileManager(filepath)
Public Methods:
* load_profiles() — No docstring
* save_profile(name, start, end, step) — No docstring
* delete_profile(name) — No docstring
* get_profile_names() — No docstring
* get_profile(name) — No docstring
serial_controller.py
File: core\serial_controller.py
class SerialController (line 44)
Manages serial connection and synchronous command-response communication.
Thread-safe implementation for sending binary protocol commands and receiving responses from the Acetone Motherboard.
Constructor: SerialController(data_queue: Optional[queue.Queue], mock_mode: bool)
Initialize the serial controller.
Args: data_queue: Optional queue for parsed data messages. If None, a new queue is created. mock_mode: If True, enables mock serial ports for testing without hardware. App starts disconnected; user manually connects to MOCK_PORT.
Public Methods:
* find_ports() — Return list of available serial ports.
* is_connected() — Check if serial connection is open.
* is_mock() — Check if using mock serial connection.
* connect(port: str) — Connect to the specified serial port.
Args:
port: Serial port name (e.g., 'COM3', 'MOCK_PORT',
* disconnect() — Disconnect from the serial port.
* check_handshake() — Perform V3.2 Handshake: Send 0xAA -> Expect 0xBB (RESP_READY).
Returns:
True if handshake succe
* send_instruction(opcode: int, payload: bytes, timeout: float, retries: int) — Send a binary instruction and wait for response.
Protocol: [0xAA] [Opcode] [Payload] -> [0xAA] [Res
* read_binary(size: int, timeout: float) — Read a fixed number of bytes from the serial port.
Args: size: Number of bytes to read time
storage.py
File: core\storage.py
class StorageManager (line 13)
Manages all persistent storage in %APPDATA%/JameedLab/.
Public Methods:
* get_app_dir(cls) — Get the main application data directory.
* get_logs_dir(cls) — Get the logs directory.
* get_data_dir(cls) — Get the directory where user data (experiments, profiles) is stored.
* get_experiments_dir(cls) — Get the experiments data directory.
* get_history_path(cls) — Get the path to experiments history file.
* get_profiles_path(cls) — Get the path to user profiles file.
* get_settings_path(cls) — Get the path to application settings file.
* get_firmware_cache_dir(cls) — Get the firmware cache directory.
* load_json(cls, path: Path, default: dict | list) — Safely load JSON file with fallback to default.
* save_json(cls, path: Path, data: dict | list) — Safely save JSON file with backup.
* migrate_from_local(cls, local_history: Path, local_profiles: Path) — Migrate data from old local paths to AppData.
Module Functions:
* get_app_dir() — No docstring
* get_logs_dir() — No docstring
* get_history_path() — No docstring
theme_builder.py
File: core\theme_builder.py
class MaterialThemeBuilder (line 7)
Generates a Material 3 color scheme from a single seed color. Uses HSL adjustments to approximate tonal tonal palettes.
Public Methods:
* hex_to_rgb(hex_color) — No docstring
* rgb_to_hex(r, g, b) — No docstring
* get_tone(h, s, l_target) — Get a color with specific lightness (tone 0-100).
* generate_palette(cls, seed_hex) — Generate full light and dark schemes from seed.
theme_manager.py
File: core\theme_manager.py
class ThemeManager (line 9)
Public Methods:
* set_theme(cls, theme_name: str) — Set the application theme and notify listeners.
* add_listener(cls, callback: Callable[[str], None]) — Register a callback function to be called on theme change.
* remove_listener(cls, callback: Callable[[str], None]) — Unregister a callback function.
* get_current_theme(cls) — Get the current theme name.
* get_color(cls, color_tuple: Tuple[str, str]) — Get the correct color code from a (Light, Dark) tuple based on current theme.
Useful for non-ctk wid