This skill should be used when the user asks to "reverse engineer VMI", "capture BLE traffic", "analyze VMI protocol", "control VMI app via ADB", "pull btsnoop logs", or discusses Ventilairsec device protocol analysis.
This skill should be used when the user asks to "reverse engineer VMI", "capture BLE traffic", "analyze VMI protocol", "control VMI app via ADB", "pull btsnoop logs", or discusses Ventilairsec device protocol analysis.
VMI App Reverse Engineering
Control the Ventilairsec VMI+ app via ADB to capture and analyze BLE protocol traffic.
Quick Start
# 1. Enable BT snoop logging (one-time setup)
./scripts/capture/vmictl.py btsnoop-enable
# 2. Connect to device
./scripts/capture/vmictl.py connect
# 3. Start capture session
SESSION=$(./scripts/capture/vmictl.py session-start my_session)
# Navigate, take checkpoints, record values, then end session
./scripts/capture/vmictl.py session-end "$SESSION"
For phone setup, ADB connection, BT snoop logging details, and troubleshooting, see playbook.md section 1.
Full nav: home → menu → maintenance → available info → measurements
diagnostic
Available info → Diagnostic
Configuration Screens
Command
Description
special-modes
Configuration → Special modes (holiday, etc.)
special-modes-full
Full nav from home to Special modes
time-slots
Configuration → Time slot configuration
Schedule Controls (from Time Slot Configuration)
Command
Description
schedule-edition
Select EDITION tab
schedule-planning
Select PLANNING tab
schedule-hour <0-23>
Tap hour row in schedule table
Sensor Selection (from Sensor management)
Command
Description
sensor-probe1
Select Probe 1 (outlet)
sensor-probe2
Select Probe 2 (inlet)
sensor-remote
Select Remote Control
Fan Control (from home screen) ⚡
Command
Description
fan-min
Set to LOW (131 m³/h)
fan-mid
Set to MEDIUM (164 m³/h)
fan-max
Set to HIGH (201 m³/h)
boost
Activate BOOST mode
preheat-toggle
Toggle preheat ON/OFF
preheat-temp <n>
Set preheat temperature (12-18 or "mini")
summer-limit <n>
Set summer limit temperature (22-37)
Holiday Mode (from Special modes screen) ⚡
Command
Description
holiday-toggle
Toggle Holiday mode ON/OFF
holiday-days <n>
Set Holiday duration to n days
⚡ = modifies VMI state. These commands (plus airflow, airflow-min, airflow-max, preheat-temp, summer-limit, firmware-update) are automatically logged to data/captures/vmi_actions.log. If a capture session is active, an automatic checkpoint (screenshot + timestamp) is also taken — no need to call session-checkpoint manually.
Utility
Command
Description
screenshot [file]
Take screenshot
scroll
Scroll down
back
Press back button
ui
Dump UI hierarchy (XML)
resolution
Show detected resolution
battery
Show phone battery level and charging status
Bluetooth Capture
Command
Description
btsnoop-enable
Enable FULL BT snoop logging
btstart
Enable logging (basic, may be filtered)
btpull
Pull btsnoop logs via bugreport
session-start <name>
Start capture session, outputs directory path
session-checkpoint <dir> [note]
Take timestamped screenshot with optional note
session-end <dir>
End session, pull btsnoop logs
collect-sensors [--force]
Build timestamped UI+packet evidence session for sensor analysis
should-collect
Check if sensor collection is due
Screen Hierarchy
HOME (fan control buttons)
├── menu
│ ├── Configuration
│ │ ├── Simplified (airflow slider)
│ │ ├── Special modes (holiday, night vent, fixed airflow)
│ │ └── Time slot configuration
│ ├── Maintenance
│ │ └── Available info
│ │ ├── Equipment life (filter days, serial)
│ │ ├── Instantaneous measurements (temp/humidity)
│ │ └── Diagnostic (component health)
│ └── Sensor management (probe selection)
Capture Session Workflow
# 1. Start session (outputs directory path)
SESSION=$(./scripts/capture/vmictl.py session-start humidity_test)
# 2. Navigate to screen, take checkpoint (outputs screenshot path)
SCREENSHOT=$(./scripts/capture/vmictl.py session-checkpoint "$SESSION")
# 3. Read the screenshot to see values, then append to checkpoints.txt# 4. State-modifying commands auto-checkpoint when a session is active:
./scripts/capture/vmictl.py fan-max # auto-checkpoint with note "action=fan-max"# 5. End session and pull btsnoop logs
./scripts/capture/vmictl.py session-end "$SESSION"
After each checkpoint, append observed values to $SESSION/checkpoints.txt:
remote_temp=19
remote_humidity=55
probe1_temp=16
probe1_humidity=71
notes=after switching to Probe1 sensor
Note: State-modifying commands (fan-*, boost, preheat-toggle, preheat-temp, airflow*, holiday-*, firmware-update) automatically create a checkpoint when a session is active. You only need manual session-checkpoint calls for read-only observations (navigating to a screen to record displayed values).
Packet Analysis
# Basic extraction
python scripts/capture/extract_packets.py session/btsnoop.log
# With checkpoint correlation
python scripts/capture/extract_packets.py session/btsnoop.log \
--checkpoints session/checkpoints.txt --window 10
# Export status packets as hex
python scripts/capture/extract_packets.py session/btsnoop.log --status-hex
For packet type reference, field offsets, and encoding details, see protocol.md.
Instructions for Claude
When helping with reverse engineering:
Before capturing: Ensure BT snoop is enabled with btsnoop-enable
For new protocol fields: Use capture session with checkpoints
Record values: Read each checkpoint screenshot, append values to checkpoints.txt
Compare packets: Use --checkpoints flag to correlate bytes with app values
Navigation: Follow screen hierarchy - can't jump directly to submenus
Verify results: Check screenshots in session directory
Phone Battery Monitoring
The Fairphone used for reverse engineering is not plugged in and will eventually run out of battery. The vmictl script automatically checks battery level every 5 minutes and prints a warning to stderr when it's low.
You MUST relay battery warnings to the user. When you see output containing BATTERY WARNING or BATTERY CRITICAL from any vmictl command:
WARNING (<= 20%): Immediately tell the user: "The phone battery is at X% — it should be charged soon to avoid losing the session."
CRITICAL (<= 10%):Stop what you are doing and alert the user: "The phone battery is critically low (X%). It needs to be charged NOW or it will shut off and we'll lose BLE connectivity."
You can also check manually at any time with ./scripts/capture/vmictl.py battery.
Opportunistic Data Collection
At the start of any VMI debugging session, run the sensor collection command:
./scripts/capture/vmictl.py collect-sensors
This command:
Checks if 15+ minutes have passed since last collection (skip if too recent)
Navigates to Instantaneous Measurements screen
Takes a screenshot and pulls btsnoop logs
Extracts packet byte values and displays them for comparison
Use --force to collect even if less than 15 minutes have passed.
After running, read the screenshot and compare app values to packet bytes. If values differ, add a timestamped note in the current investigation issue/logbook.
Field
App Screen
Packet Location
Remote temp
Remote Control → Temperature
SCHEDULE (0x02) byte 11
Remote humidity
Remote Control → Humidity
SCHEDULE (0x02) byte 13
Probe 1 temp
Probe N°1 → Temperature
PROBE_SENSORS (0x03) byte 6
Probe 1 humidity
Probe N°1 → Humidity
PROBE_SENSORS (0x03) byte 8
Probe 2 temp
Probe N°2 → Temperature
PROBE_SENSORS (0x03) byte 11
Data is stored persistently in data/captures/ (gitignored, survives reboots).