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.
App Control Commands
Connection
| Command | Description |
|---|---|
connect | Full sequence: launch → scan → pair → dismiss update dialog |
launch | Just launch the app |
vmci | Tap VMCI device type |
pair | Tap PAIR on scan results |
dismiss | Dismiss update dialog |
Navigation (from home screen)
| Command | Description |
|---|---|
menu | Open hamburger menu |
config | Menu → Configuration |
simplified | Configuration → Simplified |
maintenance | Menu → Maintenance |
sensors | Menu → Sensor management |
Maintenance Screens
| Command | Description |
|---|---|
available-info | Maintenance → Available info |
equipment-life | Available info → Equipment life |
measurements | Available info → Measurements (temp/humidity) |
measurements-full | 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 |
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 |
Holiday Mode (from Special modes screen)
| Command | Description |
|---|---|
holiday-toggle | Toggle Holiday mode ON/OFF |
holiday-days <n> | Set Holiday duration to n days |
Utility
| Command | Description |
|---|---|
screenshot [file] | Take screenshot |
scroll | Scroll down |
back | Press back button |
ui | Dump UI hierarchy (XML) |
resolution | Show detected resolution |
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> | Take timestamped screenshot, outputs image path |
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. 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
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
--checkpointsflag to correlate bytes with app values - •Navigation: Follow screen hierarchy - can't jump directly to submenus
- •Verify results: Check screenshots in session directory
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 they differ, add a data point to GitHub issue #9.
| Field | App Screen | Packet Location |
|---|---|---|
| Remote temp | Remote Control → Temperature | STATUS byte 8 |
| Remote humidity | Remote Control → Humidity | STATUS byte 4 |
| Probe 1 temp | Probe N°1 → Temperature | HISTORY byte 6 |
| Probe 1 humidity | Probe N°1 → Humidity | HISTORY byte 8 |
| Probe 2 temp | Probe N°2 → Temperature | HISTORY byte 11 |
Data is stored persistently in data/captures/ (gitignored, survives reboots).