A one handed underwater spectrometer system using Ocean Optics ST-VIS spectrometers with a Raspberry Pi Zero 2W and Adafruit 2.8LCD display. Designed for field work in a compact, low-power package.
- Version 1.0 released
- Hardware Requirements
- Installing Ubuntu on the Raspberry Pi
- Setting Up WiFi
- Installing the Software
- Running the App
- App Settings Reference
- Capturing Reference Spectra (Calibration)
- Capturing Spectra
- Downloading Data to Your Computer
- Advanced: Editing config.py
- Data Format & Storage
- Hardware Information
- Troubleshooting
- Raspberry Pi Zero 2W
- PiTFT Plus Assembled 320x240 2.8" TFT + Resistive/Capacitive Touchscreen
- Ocean Optics ST-VIS spectrometer
- High-quality microSD card if flashing software (Samsung 128/256GB PRO Plus recommended)
- Adafruit MCP9808 High Accuracy I2C Temperature Sensor Breakout
- Hydrocean M10 Magnetic USB Penetrator
- FEX Heat Sink with Fan FEX40-40-21/T710/M2
- Blue Robotics leak sensor SOS Probes
- ORCA Open Spectro Pi Hat
- 4 x ORCA Magnetic Hall Effect Trigger Switches
- 8 x EPDM O-rings Metric: ~10.82mm ID X 1.78mm CS (plus spares)
WARNING: You can easily damage the hardware or cables if you are not very careful opening the housing.
The device is very carefully assembled. Read all three guides from Blue Robotics on enclosure assembley before attempting to open the case as these outline how their parts work. Take note of where the ports and cables are located in the payload.
To disassemble the device, both end caps need to carefully released, and all ports need to be unplugged in order to prevent damage.
- Completely unscrew the pressure relief valve. Ensure no dust or sand gets on any of the parts or O-rings.
- Remove both plastic locking cords on each end of the housing.
- Carefully open the penetrator bulkhead housing end of the tube (the side with all the cables). Open this just enough to access the battery bank plugs.
- Carefully reach into the housing to unplug both USB-C battery connections carefully.
- Carefully open the fibre optics bulkhead housing end of the tube just enough to access the3.2 spectrometer plug.
- Unplug the spectrometer USB-C port.
- Carefully reach into the housing and unplug the fan and temperature sensor from the Pi Hat (it helps if you have the housing rotated so the battery is parallel to the ground so it stays out of the way so you can access the plug).
- You can now access the SD card if you need to add additional WIFI accounts. See 3.2 Adding Additional WiFi Networks.
- Unscrew the 2 x M3 bolts holding the battery USB cable plate.
- Unscrew the M3 bolts holding the Pi Hat cover. Carefully remove the plate being careful not to damage the leak sensor plpugged into the Pi hat.
- Carefully remove the Pi Hat being sure not to damage the trigger plugs.
- Take note of the orientation of the USB-C plug on the Pi hat. Carefully remove the USB-C port of the Pi hat. Note: Orientation of this USB-C port is critical. Plugging it in in reverse will stop break the power switch working..
- Unplug the leak sensor, triggers, and power switch ports. Note: The triggers plugs are labelled and correspond to the labelled ports on the Pi hat PCB.
The enclosures uses Blue Robotics enclosures. All O-rings, seals, and components need to be maintained and checked regularly.
The Vacuum Plug allows you to vacuum test enclosures ensuring a watertight seal.
- All external bolts are stainless steel 316. Where stainless steel bolts coming into contact with aluminium housings, Tef-Gel should be applied to prevent galvanic corroision as noted in the Blue Robotics enclosures guide. This should be applied if using in saltwater (irrespective of dive duration). This only need to be applied once.
- The springs on the triggers need to use EPDM O-rings (Ethylene Propylene Diene Monomer). Blue Robotics Buna-N o-rings will work temporarily, but will not last very long in saltwater environments. Ensure two o-ring are installed on each trigger. These should be examined before each dive.
- Ensure all seals are clean and free from dust and contaminents. Apply Molykote 111 before assembly.
- Pressure test after reassembly.
- Ensure the device is left in clean freshwater after each use to prevent salt crystalisation. Saltwater that dries in 3D printed parts can crystalise, and cause cracking. All parts are printed with ASA or ABS with 100% infill. Sealing 3D-printed components with dichtol sealant can prevent saltware damage to 3D prints.
- Ensure the spectometer is not left to sit in the sun. UV light degrades 3D prints over time.
- All 3D printed parts can be replaced with machined aluminium components to increase lifespan. Ensure all aluminium parts are annodised.
These steps are required to create a new ORCA Open Spectrometer SD card to run the app on a Raspberry Pi Zero 2W. Please note: These steps are not required if you have a working device. For instructions on using the app, start from step 5.
These instructions are a general guide for setup. I have attempted to document the majority of installation steps and fixes I did to make the system work, but additional steps may be required.
# Ubuntu/Debian
sudo apt install rpi-imager
# Or download from: https://www.raspberrypi.com/software/- Open Raspberry Pi Imager
- Choose Device: Raspberry Pi Zero 2W
- Choose OS: Ubuntu 22.04 Server LTS
- Choose Storage: Select your SD card
- Click Edit Settings and configure:
| Setting | Value |
|---|---|
| Hostname | rpi |
| Username | pi |
| Password | spectro (or your choice) |
| Configure WiFi | Yes (see section 3 for adding additional wifi networks) |
| WiFi Country | Your country code (e.g., AU) |
| Timezone | Your timezone (e.g., Australia/Brisbane) |
| Enable SSH | Yes, with password authentication |
- Click Save, then Yes to apply settings
- Flash the image to the SD card
- Insert the SD card into the Raspberry Pi
- Connect power
- Wait 3-5 minutes for first boot (the Pi expands the filesystem)
- The Pi should automatically connect to your configured WiFi
Configure your primary WiFi during the imaging process (section 2.2). You should also add your mobile hotspot for easy field access to the data of configuration settings, along with any other WiFi networks you plan on connecting to at this stage.
This can be done remotely via SSH (Method B) if you are already connected to the Pi, or by editing the SD card directly if the device is disassembled (Method A). I would recommend adding multiple WiFi accounts (e.g. your own hotspot, and any WiFi accounts you may want to access the device on).
- Insert the SD card into your computer
- Navigate to the root filesystem
- Edit
/etc/netplan/50-cloud-init.yaml
Use this method when you are already connected to the Pi over SSH (e.g. via your own hotspot) and want to add another WiFi network without disassembling the device.
Step 1: SSH into the Pi
ssh pi@<IP_ADDRESS>Don't know the IP address? See section 3.3.
Step 2: Open the WiFi configuration file
sudo nano /etc/netplan/50-cloud-init.yamlStep 3: Add the new WiFi network
Use the arrow keys to scroll down to the access-points: section. You will see your existing WiFi networks listed. Add the new network directly below the last one, keeping the exact same indentation (spaces, not tabs).
Add these two lines, replacing the name and password with the actual values:
"New_WiFi_Name":
password: "wifi_password"Important: The indentation must be exactly 16 spaces before the WiFi name and 20 spaces before
password. Use spaces only, never tabs. Incorrect indentation will prevent WiFi from connecting.
Example: What the full file should look like
network:
version: 2
wifis:
renderer: networkd
wlan0:
access-points:
"Your_Hotspot":
password: "hotspot_password"
"Friends_Hotspot":
password: "friends_password"
"Lab_WiFi":
password: "lab_password"
dhcp4: true
optional: trueStep 4: Save and exit nano
- Press
Ctrl + O(the letter O) to save - Press
Enterto confirm the filename - Press
Ctrl + Xto exit
Step 5: Apply the changes
sudo netplan applyYour SSH connection may briefly drop while the network reconfigures. Wait a few seconds and reconnect if needed. The Pi will automatically connect to whichever configured network it finds.
An IP address is a unique number assigned to each device on a network (like 192.168.1.105 or 10.154.83.52). You need the Pi's IP address to connect to it remotely via SSH.
Ways to find the IP address:
- From the app: The IP is displayed in the spectrometer app menu under "IP". This is only visible after the complete installation and setup of the Open Spectro app.
- From your router: Check the connected devices list in your router or hotspot settings (see section 3.4 for details on how to do this).
- Using ping: From another computer on the same network, run
ping rpi.local. This is an easy way, but can sometimes be unreliable.
When connecting to your Pi through a mobile hotspot (useful for field work), you may need to find its IP address manually using nmap - a network scanning tool.
- Your mobile hotspot WiFi credentials are configured in the Pi's
/etc/netplan/50-cloud-init.yamlfile - Your laptop is connected to the same mobile hotspot
- The Pi is powered on and connected (check your phone shows 2+ devices connected)
sudo apt install nmapip addr show | grep "inet " # Search for local IP addresses
ifconfig # Alternative search optionLook for the IP address on your wireless interface (usually wlan0 or wlp...):
inet 10.154.83.49/24 brd 10.154.83.255 scope global dynamic wlp3s0
In this example, your laptop's IP is 10.154.83.49.
Use nmap to scan all devices on the same subnet. Replace the IP with yours, keeping .0/24 at the end:
sudo nmap -sn 10.154.83.0/24This scans all addresses from 10.154.83.1 to 10.154.83.254. Example output:
Nmap scan report for 10.154.83.1
Host is up (0.0050s latency).
Nmap scan report for 10.154.83.49
Host is up (0.00010s latency).
Nmap scan report for 10.154.83.52
Host is up (0.045s latency).
One of the IP addresses (not your laptop's, not .1 which is usually the hotspot) will be the Pi. Try connecting:
ssh -Y pi@10.154.83.52Tip: If you have multiple unknown devices, try each one until you find the Pi. The Pi will respond with a password prompt for user pi.
ssh pi@<IP_ADDRESS>
# Password: spectro (or your password)cd ~
git clone https://github.com/roboticsmick/ORCA_open_spectrometer.git
cd ORCA_open_spectrometer
chmod +x setup_pi.sh
sudo ./setup_pi.shThe setup script:
- Installs all system dependencies
- Creates a Python virtual environment
- Installs Python packages (pygame, seabreeze, etc.)
- Configures the display
- Sets up the app to run as a systemd service on boot
sudo rebootAfter reboot, the app should start automatically.
The app runs automatically as a systemd service when the Pi boots. No action required.
ssh pi@<IP_ADDRESS>
# Password: spectro (or your password)
# Check if the app is running
sudo systemctl status pysb-app.service
# Stop the app
sudo systemctl stop pysb-app.service
# Start the app
sudo systemctl start pysb-app.service
# Restart the app
sudo systemctl restart pysb-app.service
# View live logs
journalctl -u pysb-app.service -f# Stop the service first
sudo systemctl stop pysb-app.service
# Activate virtual environment and run
cd ~/ORCA_open_spectrometer/pysb-app
source pysb_venv/bin/activate
python3 main.pyThe app uses 4 buttons:
| Button | Menu Action | Live View Action |
|---|---|---|
| UP (X) | Previous item / Increase value | Open calibration menu |
| DOWN (Y) | Next item / Decrease value | Rescale Y-axis |
| A (ENTER) | Select / Confirm | Freeze spectrum |
| B (BACK) | Cancel / Go back | Return to menu |
pi@ada:/pysb-app/hardware$ sudo systemctl disable systemd-networkd-wait-online.service
[sudo] password for pi:
Removed /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service.
pi@ada:/pysb-app/hardware$ sudo systemctl mask systemd-networkd-wait-online.service
Created symlink /etc/systemd/system/systemd-networkd-wait-online.service → /dev/null.
Controls how long the sensor collects light per measurement.
| Parameter | Value |
|---|---|
| Default | 1000 ms |
| Minimum | 100 ms |
| Maximum | 6000 ms |
| Step | 50 ms |
General guidelines:
- Low light conditions: Increase integration time
- Bright light / saturation: Decrease integration time
- Use Auto-Integration (Section 7.4) to find the optimal value
| Mode | Description |
|---|---|
| RAW | Direct sensor readings as ADC counts (0-16383) |
| REFLECTANCE | pi@ada:~/pysb-app/hardware$ sudo systemctl disable systemd-networkd-wait-online.service |
| [sudo] password for pi: | |
| Removed /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service. | |
| pi@ada:~/pysb-app/hardware$ sudo systemctl mask systemd-networkd-wait-online.service | |
| Created symlink /etc/systemd/system/systemd-networkd-wait-online.service → /dev/null. | |
| Calibrated reflectance ratio (requires calibration) |
- Shows direct sensor values
- No calibration required
- Best for: testing, alignment, troubleshooting
- Calculates relative reflectance using dark and white references
- Requires calibration before use (see Section 7)
Reflectance Formula:
Reflectance = (Target - Dark) / (White - Dark)
Where:
- Target = Raw spectrum of your sample
- Dark = Raw spectrum with sensor covered (no light)
- White = Raw spectrum of a white reference standard (e.g., Spectralon or white PTFE panel)
Interpreting Values:
| Value | Meaning |
|---|---|
| 0.0 | No reflectance (absorbs all light) |
| 1.0 | Same reflectance as white reference (100%) |
Averages multiple scans to reduce noise.
| Parameter | Value |
|---|---|
| Default | 1 |
| Minimum | 0 |
| Maximum | 50 |
| Step | 1 |
Trade-off: Higher values = smoother data, but slower live updates.
Controls the X-axis range shown on the plot.
| Parameter | Value |
|---|---|
| Default Min | 400 nm |
| Default Max | 620 nm |
| Minimum Limit | 340 nm |
| Maximum Limit | 850 nm |
| Step | 20 nm |
Important: This only affects the display. The full spectrum is always saved to CSV.
Editing:
- Press A to start editing (MIN field highlighted in blue)
- Use UP/DOWN to adjust value
- Press A to move to MAX field
- Press A again to save
- Press B anytime to cancel
Sets the timestamp used in saved filenames. This creates a temporary offset from system time (not a permanent clock change).
Editing fields: Year → Month → Day → Hour → Minute
Controls the cooling fan activation temperature.
| Parameter | Value |
|---|---|
| Default | 0°C (always on) |
| Minimum | 0°C |
| Maximum | 60°C |
| Step | 5°C |
Display format: Fan: Threshold 40C (Current 32C)
| Setting | Behavior |
|---|---|
| 0°C | Fan always runs (maximum cooling) |
| 40°C | Fan runs only when temperature >= 40°C |
- WiFi: Current network name
- IP: Current IP address (use this for SSH)
Calibration is required for Reflectance mode. Both references must be captured at the same integration time and averaging settings.
- Enter live view (Menu → Start Capture)
- Press X (UP) to open calibration menu
CALIBRATION MENU
A: White Reference - Not set
X: Dark Reference - Not set
Y: Auto integration - Not complete
A:White | X:Dark | Y:Auto | B:Back
The dark reference captures sensor noise when no light reaches the sensor.
- Press X to start dark reference capture
- Cover the sensor completely (or close the shutter)
- The live view shows raw sensor data
- Press A to freeze when ready
- Press A to save, or B to discard and retake
The white reference captures maximum expected reflectance.
- Press A to start white reference capture
- Point at a white reference target (e.g., Spectralon, white tile)
- The live view shows raw sensor data
- Press A to freeze when ready
- Press A to save, or B to discard and retake
Automatically finds the optimal integration time by targeting 80-95% sensor saturation.
- Press Y to start auto-integration setup
- Point at your brightest expected sample (usually white reference)
- Press A to begin the algorithm
- Wait for iterations to complete (max 20)
- Review the proposed integration time
- Press A to apply, or B to cancel
Note: Applying auto-integration invalidates existing dark and white references. You must recapture them.
References are invalidated when you change:
- Integration time → Both dark and white invalidated
- Scans to average → Both dark and white invalidated
The app will display "CALIBRATE REQUIRED" if you try to use Reflectance mode with invalid references.
- From menu, select Start Capture
- Live spectrum updates at ~30 FPS
- Status bar shows:
RAW | INT:1000ms | AVG:1 | SCANS:0 | LIVE
- Press A to freeze the current spectrum
- Review the frozen plot (spectrometer pauses)
- Press A to save to file
- Press B to discard and return to live view
Files are saved to: ~/pysb-app/spectra_data/YYYY-MM-DD/
Each day creates a new folder with:
- CSV file containing all spectra
- PNG plot images for each capture
Press Y in live view to auto-scale the Y-axis based on current data.
| Platform | Requirements |
|---|---|
| Ubuntu/Linux | Terminal (built-in) |
| macOS | Terminal (built-in) |
| Windows | WSL (Windows Subsystem for Linux) |
Installing WSL on Windows:
WSL lets you open a Linux terminal you can use in Windows. This allows you to use the Ubuntu linux commands on your Windows PC.
Read the guidelines for installing WSL on windows here (How to install Linux on Windows with WSL )[https://learn.microsoft.com/en-us/windows/wsl/install].
rsync (remote sync) is a powerful command-line utility for efficiently transferring files and directories locally or over a network.
Download all data:
# Create local folder
mkdir -p ~/spectra_data
# Sync all data from Pi
rsync -av --progress pi@<IP_ADDRESS>:~/pysb-app/spectra_data/ ~/spectra_data/Download specific date:
rsync -av --progress pi@<IP_ADDRESS>:~/pysb-app/spectra_data/2025-12-15/ ~/spectra_data/2025-12-15/Resume interrupted transfer:
rsync -av --progress --partial pi@<IP_ADDRESS>:~/pysb-app/spectra_data/ ~/spectra_data/scp is simpler for one-off file copies.
Download single file:
scp pi@<IP_ADDRESS>:~/pysb-app/spectra_data/2025-12-15/2025-12-15_spectra_log.csv ./Download entire folder:
scp -r pi@<IP_ADDRESS>:~/pysb-app/spectra_data/2025-12-15/ ./2025-12-15/After downloading to WSL, access files in Windows Explorer:
\\wsl$\Ubuntu\home\yourusername\spectra_data
Or copy to Windows filesystem:
cp -r ~/spectra_data /mnt/c/Users/YourName/Desktop/Go menu → Connect to Server → sftp://pi@<IP_ADDRESS>
To customize default values or enable/disable hardware features, edit the config.py file.
ssh pi@<IP_ADDRESS>
sudo systemctl stop pysb-app.servicecd ~/ORCA_open_spectrometer/pysb-app
source pysb_venv/bin/activate
nano config.py # or vim config.pyHARDWARE = {
"USE_DISPLAY_HAT": False, # Pimoroni Display HAT. No longer used.
"USE_ADAFRUIT_PITFT": True, # Adafruit PiTFT 2.8"
"USE_GPIO_BUTTONS": False, # On-board GPIO buttons
"USE_HALL_EFFECT_BUTTONS": True, # External Hall effect buttons
"USE_LEAK_SENSOR": True, # Leak detection hardware
"USE_SPECTROMETER": True, # Ocean Optics spectrometer
"USE_TEMP_SENSOR_IF_AVAILABLE": True # MCP9808 sensor
}class SPECTROMETER:
DEFAULT_INTEGRATION_TIME_MS = 1000
MIN_INTEGRATION_TIME_MS = 100
MAX_INTEGRATION_TIME_MS = 6000
INTEGRATION_TIME_STEP_MS = 50
HW_MAX_ADC_COUNT = 16383 # 14-bit ADCFAN_ENABLE_PIN = 4 # GPIO pin for MOSFET gate
FAN_DEFAULT_THRESHOLD_C = 0 # 0 = always on
FAN_THRESHOLD_MIN_C = 0
FAN_THRESHOLD_MAX_C = 60
FAN_THRESHOLD_STEP_C = 5class PLOTTING:
USE_LIVE_SMOOTHING = True
LIVE_SMOOTHING_WINDOW_SIZE = 9
WAVELENGTH_RANGE_MIN_NM = 400.0 # Default display min
WAVELENGTH_RANGE_MAX_NM = 620.0 # Default display max
TARGET_DISPLAY_POINTS = 300 # Decimation for 30+ FPSclass AUTO_INTEGRATION:
TARGET_LOW_PERCENT = 80.0 # Lower saturation target
TARGET_HIGH_PERCENT = 95.0 # Upper saturation target
MAX_ITERATIONS = 20
PROPORTIONAL_GAIN = 0.8# Run manually to test
python3 main.py
# If working, restart service
sudo systemctl start pysb-app.serviceChanges to config.py persist across reboots. The service reads the config on startup.
~/pysb-app/spectra_data/
├── 2025-12-14/
│ ├── 2025-12-14_spectra_log.csv
│ ├── spectrum_RAW_FIBER_2025-12-14-103000.png
│ └── spectrum_REFLECTANCE_FIBER_2025-12-14-104500.png
└── 2025-12-15/
├── 2025-12-15_spectra_log.csv
└── spectrum_RAW_FIBER_2025-12-15-091500.png
Each row contains one spectrum:
| Column | Description |
|---|---|
| timestamp_utc | ISO format timestamp |
| spectra_type | RAW, REFLECTANCE, DARK, WHITE, RAW_REFLECTANCE |
| lens_type | FIBER, CABLE, or FIBER+CABLE |
| integration_time_ms | Integration time used |
| scans_to_average | Number of averaged scans |
| temperature_c | Housing temperature (if sensor available) |
| 340.12, 340.24, ... | Wavelength columns with intensity values |
| Type | Description |
|---|---|
| RAW | Direct sensor measurement in ADC counts |
| REFLECTANCE | Calibrated reflectance ratio |
| DARK | Dark reference capture |
| WHITE | White reference capture |
| RAW_REFLECTANCE | Raw target data saved alongside reflectance |
- Generated automatically for RAW and REFLECTANCE captures
- Calibration captures (DARK, WHITE) do not generate plots
- High resolution suitable for publications
The optional breakout PCB provides:
- USB-C power input
- Blue Robotics waterproof power switch
- Real-time clock (DS3231) with battery backup
- Leak sensor input (Blue Robotics SOS probes)
- External button inputs
- I2C and UART breakouts
See the /PCB folder for schematics and board files.
Fan Red Wire → 5V through MOSFET drain
Fan Black Wire → Ground
MOSFET Gate → GPIO 4
MCP9808 SDA → GPIO 2 (I2C data)
MCP9808 SCL → GPIO 3 (I2C clock)
MCP9808 VCC → 3.3V
MCP9808 GND → Ground
Leak Sensor → GPIO 26
With a 10,000mAh battery:
| Measurement | Value |
|---|---|
| Current (live capture) | ~0.6A |
| Voltage | 5.1V |
| Power | 3.06W |
| Expected runtime | ~10 hours (85% efficiency) |
# Check service status
sudo systemctl status pysb-app.service
# View detailed logs
journalctl -u pysb-app.service -n 50
# Restart service
sudo systemctl restart pysb-app.service# Check USB devices
lsusb | grep -i ocean
# Try unplugging and reconnecting the spectrometer
# Check cable connection- Check display ribbon cable connection
- Verify
USE_ADAFRUIT_PITFT: Truein config.py - Check framebuffer exists:
ls /dev/fb1
- Recapture dark and white references after changing integration time or averaging
- Both references must use the same settings
- Check
/etc/netplan/50-cloud-init.yamlsyntax - Verify SSID and password are correct
- Check WiFi country code matches your location
The app prints the status and processes out for easy debugging when connected via ssh. This should allow for easy detecting of errors.
# Stop the app service
sudo systemctl stop pysb-app.service
# Run manually to test
cd ~/pysb-app
python3 main.py
# Remember to restart the service after debugging has been complete
sudo systemctl start pysb-app.serviceExample debug printouts:
(pysb_venv) pi@ada:~/pysb-app$ python3 main.py
/home/pi/pysb-app/pysb_venv/lib/python3.10/site-packages/pygame/pkgdata.py:25: UserWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html. The pkg_resources package is slated for removal as early as 2025-11-30. Refrain from using this package or pin to Setuptools<81.
from pkg_resources import resource_stream, resource_exists
pygame 2.6.1 (SDL 2.28.4, Python 3.10.12)
Hello from the pygame community. https://www.pygame.org/contribute.html
Seabreeze libraries loaded successfully.
DataManager: Matplotlib loaded successfully (Agg backend).
Initializing standard Pygame display window...
Standard Pygame window initialized (320x240)
INFO: GPIO buttons initialized for pins: [20, 21, 19, 12]
INFO: Leak sensor initialized on GPIO pin 26 (interrupt-based)
Leak sensor thread started (waiting for interrupts).
NetworkInfo thread started.
SpectrometerController: Thread loop started
SpectrometerController thread started
DataManager: Thread loop started
DataManager thread started
Entering main application logic...
Showing splash screen...
DataManager: Data directory ready: /home/pi/pysb-app/spectra_data
Splash screen done.
Showing terms screen...
DEBUG: Button 'enter' pressed (GPIO 5)
Terms screen done.
Entering main loop...
Spectrometer initialized: ST
Serial: ST02348
Wavelength range: 348.3 - 809.2 nm
Pixels: 1516
Integration time limits: 3800 - 6000000 µs
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Entering live view
SpectrometerScreen: Set Y-axis for RAW mode: 1000.0
SpectrometerController: New session started (ID: 1)
SpectrometerScreen: Setting wavelengths (length: 1516)
DEBUG: Button 'up' pressed (GPIO 20)
SpectrometerScreen: Entering calibration menu
SpectrometerController: Session stopped (ID: 1)
DEBUG: Button 'down' pressed (GPIO 21)
SpectrometerScreen: Starting auto-integration setup
SpectrometerScreen: Cancelling auto-integration
SpectrometerScreen: Auto-integ initial test: 1000000 µs
SpectrometerScreen: Target ADC range: 13106 - 15564
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Auto-integ capture requested at 1000000 µs
SpectrometerController: New session started (ID: 2)
SpectrometerScreen: Iter 1: Peak=1125 Next=6000.0ms
SpectrometerScreen: Auto-integ capture requested at 6000000 µs
SpectrometerController: New session started (ID: 3)
SpectrometerScreen: Auto-integ complete: At max integration, still low. Proposed: 6000 ms
SpectrometerController: Session stopped (ID: 3)
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Applying auto-integration result
SpectrometerScreen: Sent CMD_UPDATE_SETTINGS with integration_time_ms=6000
SpectrometerScreen: New integration time: 6000 ms
SpectrometerScreen: Exiting calibration, returning to live view
SpectrometerScreen: Restored collection mode to RAW
SpectrometerController: Integration time updated to 6000 ms
SpectrometerController: New session started (ID: 4)
SpectrometerScreen: Setting wavelengths (length: 1516)
SpectrometerScreen: Rescaling Y-axis...
SpectrometerScreen: Y-axis rescaled to 9962.84
SpectrometerScreen: Auto-rescaled Y-axis after auto-integration
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Data frozen for capture
SpectrometerController: Session stopped (ID: 4)
DEBUG: Button 'back' pressed (GPIO 12)
SpectrometerScreen: Returning to live view
SpectrometerController: New session started (ID: 5)
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Data frozen for capture
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Save request sent (RAW)
DataManager: Processing save request (RAW)...
Timestamp: 2025-12-19 11:27:50.461775
Integration: 6000 ms
Scans averaged: 1
Session scan count: 1
SpectrometerScreen: Returning to live view
DataManager: Found 6 existing scans in today's log
DataManager: Saved RAW to CSV successfully
DataManager: Plot saved: /home/pi/pysb-app/spectra_data/2025-12-19/spectrum_RAW_FIBER_2025-12-19-112750.png
SpectrometerController: Session stopped (ID: 5)
SpectrometerController: New session started (ID: 6)
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Data frozen for capture
SpectrometerController: Session stopped (ID: 6)
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Save request sent (RAW)
DataManager: Processing save request (RAW)...
Timestamp: 2025-12-19 11:27:56.572918
Integration: 6000 ms
Scans averaged: 1
Session scan count: 2
SpectrometerScreen: Returning to live view
DataManager: Saved RAW to CSV successfully
SpectrometerController: New session started (ID: 7)
DataManager: Plot saved: /home/pi/pysb-app/spectra_data/2025-12-19/spectrum_RAW_FIBER_2025-12-19-112756.png
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Data frozen for capture
DEBUG: Button 'enter' pressed (GPIO 5)
SpectrometerScreen: Save request sent (RAW)
DataManager: Processing save request (RAW)...
Timestamp: 2025-12-19 11:28:22.606372
Integration: 6000 ms
Scans averaged: 1
Session scan count: 3
SpectrometerScreen: Returning to live view
DataManager: Saved RAW to CSV successfully
DataManager: Plot saved: /home/pi/pysb-app/spectra_data/2025-12-19/spectrum_RAW_FIBER_2025-12-19-112822.png
SpectrometerController: Session stopped (ID: 7)
SpectrometerController: New session started (ID: 8)
Special thanks to the PySeabreeze project for enabling Ocean Optics spectrometer support on ARM devices.
- Technical documentation: See pysb-app/app_guide.md






