BREAKING: rename item_id to qr_item_id everywhere (API, beacons, dashboard, GoPro web UI, clients). Pre-production unified schema. Sidecar schema (version 1.5): - Add capture_id (UUID per capture) - Add source (scicam-android / gopro) - Add device_name and device_id (ANDROID_ID on Android, persisted UUID on GoPro) - Add camera_file (original camera filename) - ISO 8601 UTC timestamps - Expanded camera_settings baseline: iso, exposure_time, aperture, focal_length, lens_mode, cx, fx, ae_locked, awb_locked (null if unknown) Android (scicam/): - MetadataLogger emits v1.5 sidecars with all new fields - MainActivity generates capture_id, isoTimestamp, reads ANDROID_ID - PresenceBeacon broadcasts qr_item_id, device_name, device_id - API /status and /settings use qr_item_id GoPro (clients/gopro-scicam/): - _fetch_camera_state_settings returns lens_mode, cx, fx - Sidecar generation uses v1.5 schema - API and beacon updated for qr_item_id, device fields - Persistent _DEVICE_UUID for device_id Dashboard (dashboard/): - DeviceStatus, discovery beacon, UI updated for qr_item_id - Display device_name and device_id in detail panel Docs: - api_spec.yaml: Sidecar schema added, State schema updated - AGENTS.md: Unified sidecar schema documented, beacon payload updated - CHANGELOG.md: reference updated Cleanup: - Remove unused clients/go-scicam and clients/web-scicam - Update .gitmodules accordingly
SciCam Logger
A minimal Android camera logging tool for scientific archiving and inventory.
Philosophy
One tool, one job. Capture the image, log the metadata, and get out of the way. No AI. No cloud. No unnecessary processing.
Features
- CameraX preview with tap-to-focus.
- Lock toggle freezes Auto-Exposure (AE) and Auto-White-Balance (AWB) for consistent color across a batch.
- Barcode / QR scanner (ZXing) to auto-fill
item_id. - Manual ID fallback — type an ID if no barcode is available.
- Tagging — comma-separated tags written to the sidecar.
- JSON sidecar per image containing:
item_idtagstimestampcamera_settings(ISO, exposure time, aperture, focal length, lock states)location(placeholdernullfor your archive API)
- Batch mode — UI retains the last
item_idso you can shoot multiple angles. - Public storage — images go to
Pictures/SciCam/, sidecars toDocuments/SciCam/(API 29+) or the same legacy public folders (API < 29), both visible over USB MTP.
Tech Stack
- Kotlin
- CameraX (preview + capture + manual control via Camera2 interop)
- ZXing Android Embedded (barcode scanning)
org.json(sidecar generation — no extra dependencies)
Build Instructions
Option 1: Android Studio
- Open the
scicam/folder in Android Studio. - Sync Gradle.
- Connect an Android device (API 24+) with USB debugging enabled.
- Click Run.
Option 2: Command Line (host toolchain)
Requires Android SDK (ANDROID_HOME set) and a connected device or emulator.
cd scicam
./gradlew assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk
Option 3: Docker (no local Android SDK needed)
Builds the APK in a container; adb runs on the Linux host for USB install.
cd scicam
./docker-build.sh
adb install app/build/outputs/apk/debug/app-debug.apk
Usage
- Launch SciCam Logger.
- Tap SCAN to read a barcode/QR code, or type an
Item IDmanually. - Enter comma-separated Tags (e.g.,
fragile, archive, 2024). - Tap the preview to focus.
- Tap LOCK to freeze exposure and white balance.
- Tap CAPTURE.
- The image is saved to
Pictures/SciCam/and the metadata sidecar toDocuments/SciCam/.
Output Example
Image
Pictures/SciCam/20250424_143052_ITEM-001.jpg
Sidecar
{
"item_id": "ITEM-001",
"timestamp": "20250424_143052",
"filename": "20250424_143052_ITEM-001.jpg",
"location": null,
"tags": ["fragile", "archive"],
"camera_settings": {
"iso": 100,
"exposure_time": "0.010000",
"aperture": "1.80",
"focal_length": "4.44",
"ae_locked": true,
"awb_locked": true
}
}
Folder Locations by API Level
| Android Version | Image Path | Sidecar Path |
|---|---|---|
| API 24–28 (Legacy) | /sdcard/Pictures/SciCam/ |
/sdcard/Documents/SciCam/ |
| API 29+ (Scoped Storage) | Pictures/SciCam/ via MediaStore |
Documents/SciCam/ via MediaStore |
Both are accessible via USB file transfer (MTP) without ADB.
Next Steps / Extending
- Location: Populate the
locationfield inMetadataLogger.ktonce your archive API schema is ready. - Custom grids / overlays: Add
PreviewViewoverlay drawables inactivity_main.xml. - Focus distance slider: Integrate
LENS_FOCUS_DISTANCEvia Camera2 interop and aSeekBar. - RAW capture: Upgrade
ImageCaptureto useImageCapture.CAPTURE_MODE_MINIMIZE_LATENCYwithsetOutputFormat(ImageCapture.OUTPUT_FORMAT_RAW)on supported devices.