Automated Motorcycle Dashcam Backup with openHAB, Shelly & Raspberry Pi — Triggered by Battery Charger Detection
TL;DR: When I plug in my motorcycle battery charger, openHAB detects it (via BLE or voltage), powers on the dashcam through a Shelly-controlled MOSFET relay, and a Raspberry Pi automatically downloads all new footage to my NAS — SHA-256 verified — then powers everything off. Zero manual intervention.
The Problem
I have an INNOVV K7 dual-channel dashcam on my motorcycle. It records front and rear video continuously while riding. The K7 has a WiFi access point for viewing footage, but:
- No remote access — The K7 WiFi is only available when it’s powered on
- No cloud backup — Footage lives only on the K7’s SD card
- Loop recording — Oldest files are automatically deleted when the SD fills up
- No power control — The K7 only powers on via the motorcycle’s ignition circuit
I wanted my footage automatically backed up to my NAS whenever I come home from a ride — without having to remember to do anything.
The Solution
A fully automated pipeline using openHAB as the brain:
Plug in charger
│
▼
Charger detected (BLE or Voltage)
│
▼
openHAB state machine confirms (60s stabilisation)
│
▼
Shelly relay ON → MOSFET switches 12V → K7 powers on
│
▼
K7 boots → broadcasts WiFi AP
│
▼
Raspberry Pi detects K7 WiFi → connects → downloads all files to NAS
│
▼
Every file SHA-256 verified (download + NAS read-back)
│
▼
Dump complete → Relay OFF → K7 shuts down
│
▼
Charger disconnected → system re-arms to PARKED
I typically come home, put the bike on the charger, and walk inside. By the time I take off my gear, all footage is on the NAS and the K7 is off again.
Architecture Overview
┌─────────────────────────────────────────┐
│ openHAB (GraalJS rules) │
│ │
GPS Tracker ────────────> vehicle-motorcycle-k7-power.js │
(Ignition state) │ ┌───────────────────────────────────┐ │
Shelly ADC ─────────────>│ │ State Machine (10 JSRules) │ │
(Battery voltage) │ │ │ │
Victron BLE ────────────>│ │ DUAL-SENSOR charger detection: │ │
(Charger state) │ │ PRIMARY: BLE charger state │ │
│ │ FALLBACK: Shelly ADC voltage │ │
│ │ │ │
│ │ PARKED→CHARGING→TRANSFERRING │ │
│ │ →COOLDOWN→DUMP_DONE→PARKED │ │
K7_Dump_Status ─────────>│ └───────────┬───────────────────────┘ │
(from Pi REST API) │ │ sendCommand(ON/OFF) │
└──────────────┼─────────────────────────┘
│
▼ Shelly Binding (native)
┌───────────────────────────┐
│ Shelly Plus Uni │
│ ADC: battery voltage │
│ Relay: MOSFET gate drive │
│ Script: local failsafe │
└───────────┬────────────────┘
│
▼ Relay drives MOSFET gate
┌───────────────────────────┐
│ IRFP9140N P-ch MOSFET │
│ High-side switch │
│ 10K pull-up (fail-safe) │
└───────────┬────────────────┘
│ Switched 12V
▼
┌───────────────────────────┐
│ INNOVV K7 Dashcam │
│ WiFi AP (5 GHz) │
└───────────┬────────────────┘
│ WiFi
┌───────────┴────────────────┐
│ Raspberry Pi │
│ Downloads → SHA-256 verify │
│ → Delete from K7 │
│ → Reports status to openHAB│
└────────────────────────────┘
Hardware
| Component | Model | Purpose |
|---|---|---|
| Shelly Plus Uni | SNSN-0043X (Gen 2) | Relay output + ADC voltage sensing + on-device failsafe script |
| IRFP9140N | P-channel MOSFET, TO-247 | High-side power switch for the K7 (fail-safe OFF via 10K pull-up) |
| Raspberry Pi | Model 3B+ or 4 | Runs the dump service (downloads footage) + Victron BLE monitor |
| ALFA AWUS036ACM | MT7612U, USB 3.0 | External 5 GHz WiFi adapter to connect to K7’s access point |
| Victron charger | Blue Smart IP65 12/10 | BLE-enabled battery charger — primary charger detection sensor |
| INNOVV K7 | Dual-channel dashcam | Front + rear recording, WiFi AP, HTTP API for file access |
| 1N4007 diode | Silicon rectifier | Blocks MOSFET back-feed into motorcycle ignition circuit |
| 10K + 100Ω resistors | 1/4W | Gate pull-up (fail-safe) + gate inrush limiter |
Optional: GPS tracker (e.g., Teltonika) for ignition state awareness. The system works without it — ignition detection just adds intelligence to the state machine (e.g., suppressing false triggers while riding).
Cost
The electronics cost is minimal — the Shelly Plus Uni, MOSFET, resistors, and diode together are under €25. The Pi and WiFi adapter are the bigger investment, but many of us already have a Pi available.
MOSFET Power Switching Circuit
The Shelly’s relay drives a P-channel MOSFET as a high-side switch. This is the core trick that gives us remote power control over the K7:
Battery +12V (always-on, fused 3A)
│
├──── Shelly Plus Uni POWER
├──── Shelly ADC input (Voltmeter:100)
│
├──── IRFP9140N Source (pin 3)
│ │
│ 10K resistor (pull-up → fail-safe MOSFET OFF)
│ │
│ IRFP9140N Gate (pin 1) ── 100Ω ── Shelly Relay COM
│ │
│ Shelly Relay NO ──┤
│ │
│ Battery GND
│
└──── IRFP9140N Drain (pin 2) ─────────┐
├──> K7 ignition input
Motorcycle ignition 12V ──►|── 1N4007 ────┘
(Blocks MOSFET back-feed)
Battery GND ──────────────────────> K7 ground
| Relay State | Gate Voltage | MOSFET | K7 |
|---|---|---|---|
| OPEN (OFF) | Pulled to +12V via 10K | OFF | No power |
| CLOSED (ON) | Pulled to GND via relay | Fully ON | Powered |
Why a MOSFET instead of using the relay directly? The IRFP9140N is rated for 23A continuous — massively overkill for the K7’s ~0.5A, but it means zero mechanical wear, near-zero power loss, and a rock-solid fail-safe: if the Shelly loses power or crashes, the 10K pull-up holds the gate high and the MOSFET stays OFF. The K7 will never drain your battery by accident.
Wiring tip: Heat-shrink the MOSFET + resistors into a compact pack and zip-tie it to the wiring harness under the seat. Three wires come out: RED (+12V), BLACK (GND), ORANGE (switched output to K7).
Dual-Sensor Charger Detection
This is where it gets interesting. Detecting “charger connected” sounds simple, but voltage alone is surprisingly unreliable on a motorcycle:
- The charger’s Storage stage (~13.0V) sits right at the detection threshold
- Battery voltage lingers above 13.0V for minutes after the charger is unplugged
- Engine running produces 13.5-14.5V — looks identical to a charger
The solution: two independent sensors
| Sensor | Role | How it works |
|---|---|---|
| Victron BLE (primary) | Reads the actual charger state | Pi daemon connects via BLE GATT every 30s, reads Bulk/Absorption/Float/Storage/Idle/Off |
| Shelly ADC (fallback) | Voltage threshold detection | >13.0V = charger connecting, <12.7V = charger removed |
The BLE daemon on the Pi connects to the Victron charger’s Bluetooth and reads the exact charge state. This is 100% reliable — no threshold guessing. The voltage fallback kicks in only when BLE is unavailable.
Three detection tiers (in priority order):
isBLECharging()— Active charging: Bulk / Absorption / Float / ReconditionisBLEConnected()— Charger on mains: includes Storage / Idle (full battery)Voltage > 13.0V— Fallback when BLE is offline
Note: If you don’t have a BLE-capable charger, the system still works with voltage-only detection. You’ll just want to tune the thresholds for your specific charger and add a longer stabilisation delay.
openHAB State Machine
The state machine is the brain of the system — 10 GraalJS rules in a single file that coordinate everything:
States
Ignition ON
┌────────────────────┐
│ ▼
PARKED ──(charger)───► CHARGING ──(60s)──► TRANSFERRING
▲ │ │
│ not confirmed │
│ ▼ "complete"
│ PARKED ▼
│ COOLDOWN ──(30s)──► DUMP_DONE
│ │ │
│ charger off│ │Ignition ON
│ ▼ ▼
│◄──────────────────────────────────────────────── PARKED RIDING
│ V<12.0V
└── LOW_BATTERY ◄──── (any state)
| State | Relay | What’s happening |
|---|---|---|
| PARKED | OFF | Waiting for charger or ignition |
| RIDING | OFF | Ignition ON — K7 powered by ignition circuit |
| CHARGING | OFF | Charger detected, 60s stabilisation to filter false triggers |
| TRANSFERRING | ON | K7 powered, Pi downloading footage |
| COOLDOWN | OFF→ | Dump complete, 30s for clean K7 shutdown |
| DUMP_DONE | OFF | Cycle complete, ready for next ride |
| LOW_BATTERY | OFF | Battery < 12.0V — emergency protection |
The 10 Rules
| # | Rule | What it does |
|---|---|---|
| 1 | System Init | Recovers state after openHAB restart — reads voltage and BLE to determine correct state |
| 2 | Ignition Handler | Handles ignition ON/OFF with 5s debounce (diode filters back-feed) |
| 3 | Voltage Monitor | Watches Shelly ADC for charger connect/disconnect and low battery |
| 4 | Dump Complete | Detects “complete” from Pi, starts 30s cooldown, turns relay OFF |
| 5 | WiFi Poll | Polls Shelly API every 60s for SSID and RSSI |
| 6 | Relay Tracker | Timestamps when relay turns ON/OFF |
| 7 | Manual Override | Allows manual relay control from the UI or app |
| 8 | BLE Online | Handles BLE daemon connecting/disconnecting |
| 9 | BLE Charge State | Reacts to charger state changes (Off → re-arm, Charging → start) |
| 10 | Connection Status | Computes human-readable charger connection string |
The full state machine is ~670 lines of GraalJS. View on GitHub →
Safety Features
Battery protection was a top priority — the motorcycle battery is the single point of failure:
| Feature | Value | Purpose |
|---|---|---|
| Stabilisation delay | 60 seconds | Filters false triggers from voltage spikes |
| Safety timeout | 30 minutes | Forces relay OFF if dump hangs |
| Low battery cutoff | 12.0V (openHAB) / 11.5V (Shelly) | Protects battery from deep discharge |
| MOSFET fail-safe | Physical 10K pull-up | Relay open = MOSFET OFF. No software required. |
| On-device failsafe | Shelly mJS script | Basic protection when openHAB is offline |
| Manual mode safety | 60 min timeout | External relay toggle (Shelly app) auto-shuts off |
| Re-arm grace period | 5 minutes | Prevents false retrigger from lingering high voltage |
| SHA-256 verification | Every file | Files only deleted from K7 after verified on NAS |
| 3-failure abort | Consecutive | Stops if K7 goes offline mid-transfer |
On-Device Failsafe (Shelly mJS)
The Shelly runs a local failsafe script that provides basic protection even when openHAB is completely unreachable:
- Monitors ADC voltage every 30 seconds
- Auto-detects charger connect/disconnect
- Safety timeout: 25 minutes (shorter than openHAB’s 30 min, so openHAB takes priority)
- Low battery cutoff: 11.5V
- Manual mode detection — if someone toggles the relay from the Shelly app, starts a 60-minute safety timer
Pi Dump Service
The dump service runs on the Raspberry Pi as a systemd service. It handles the entire download pipeline:
- Detect K7 WiFi AP → connect via 5 GHz
- Scan K7’s HTTP API for files across all folders (Movie_E, Photo_E, EMR_E)
- Download each file with inline SHA-256 hashing (256 KB chunks)
- Verify read-back hash from NAS matches download hash
- Delete verified files from K7 (burst delete with recovery pauses)
- Report status to openHAB via REST API throughout
The K7 HTTP API
The INNOVV K7 runs a simple HTTP server at 192.168.1.254 when WiFi is active. There’s no official API documentation, but through reverse engineering:
| Endpoint | Response | Purpose |
|---|---|---|
GET /INNOVV/api/reg/photo |
JSON with settings | Camera status |
GET /INNOVV/api/filelist?folder=Movie_E |
JSON file listing | List recorded files |
GET /INNOVV/Movie_E/filename.mp4 |
Binary stream | Download file |
GET /INNOVV/api/delete?folder=Movie_E&name=file.mp4 |
JSON result | Delete one file |
WiFi Firmware Note
If using a Pi 4 with built-in WiFi (BCM43455), the standard Cypress firmware causes ASSOC_REJECT when connecting to the K7’s RTL8821CS 5 GHz access point. The solution is the minimal firmware (7.45.241):
sudo update-alternatives --set cyfmac43455-sdio.bin \
/lib/firmware/cypress/cyfmac43455-sdio-minimal.bin
With an external USB adapter like the ALFA AWUS036ACM (MT7612U, in-kernel mt76 driver), this isn’t needed.
Step-by-Step Setup
Prerequisites
- openHAB 4+ with Shelly binding and GraalJS automation installed
- Raspberry Pi (3B+ or 4) with Ethernet and a 5 GHz WiFi adapter
- INNOVV K7 dashcam (any firmware version)
- Shelly Plus Uni (Gen 2)
- BLE-capable battery charger (optional but recommended — e.g., Victron Blue Smart IP65)
- Basic soldering skills for the MOSFET circuit
1. Wire the MOSFET Circuit
Solder the IRFP9140N with the 10K pull-up resistor (Source to Gate) and optional 100Ω gate resistor. Heat-shrink the assembly. Connect:
- Source (pin 3) → Battery +12V (fused 3A)
- Gate (pin 1) → Shelly Relay COM (via 100Ω)
- Drain (pin 2) → K7 ignition input (yellow wire)
- Relay NO → Battery GND
- Shelly power → Battery +12V / GND
- Shelly ADC → Battery +12V (voltage sensing)
Install a 1N4007 diode in the motorcycle’s ignition wire before the splice point (anode on ignition side, cathode on K7/MOSFET splice) to block back-feed to other devices on the ignition circuit.
See the detailed wiring diagrams in the repo for pin-by-pin assembly instructions.
2. Configure the Shelly Plus Uni
-
Power on (connect battery) and connect to its setup AP via the Shelly app
-
Set primary WiFi (STA0) to your home network
-
Optionally set secondary WiFi (STA1) to phone hotspot for mobile control
-
Add the ADC peripheral via RPC:
http://<SHELLY_IP>/rpc/Uni.AddPeripheral?type="voltmeter"This creates
voltmeter:100— the ADC channel that reads battery voltage. -
Upload the failsafe script via RPC (
Script.PutCode). The script needs to be uploaded in chunks ≤1024 bytes due to Shelly’s payload limit. See the failsafe script.
3. Set Up the Raspberry Pi
git clone https://github.com/Prinsessen/innovv-k7-autodump-.git
cd innovv-k7-autodump/pi-software
# Copy and edit config
cp config.example.json config.json
nano config.json # Set your openHAB URL, NAS path, WiFi details
# Run the installer (sets up systemd service, WiFi, NAS mount)
sudo bash install.sh
# Start the service
sudo systemctl start innovv-k7-dump
sudo systemctl status innovv-k7-dump
See the Pi software README for detailed instructions including NAS mount setup, WiFi adapter configuration, and SD card backup.
4. Set Up BLE Charger Detection (Optional)
If you have a Victron Blue Smart charger (or another BLE-capable charger), the BLE daemon runs on the same Pi:
cd ../victron-ble
pip3 install -r requirements.txt
sudo cp victron-ble-monitor.service /etc/systemd/system/
sudo systemctl enable --now victron-ble-monitor
The daemon reads the charger’s state via BLE GATT and posts to openHAB’s REST API every 30 seconds. Full documentation →
Without BLE: The system works fine with voltage-only detection. Remove the BLE-related rules (8, 9, 10) from the state machine and rely on Shelly ADC voltage thresholds.
5. Configure openHAB
Copy the openHAB files from the repo and adjust the device IDs:
# Copy configuration files
cp openhab/items/*.items /etc/openhab/items/
cp openhab/things/*.things /etc/openhab/things/
cp openhab/rules/*.js /etc/openhab/automation/js/
cp openhab/transform/*.map /etc/openhab/transform/
# Optional: copy custom icons
cp openhab/icons/*.svg /etc/openhab/icons/classic/
What to customise:
| File | What to change |
|---|---|
shelly.things |
Shelly device ID (MAC address) and IP |
motorcycle_k7_power.items |
Channel links match your Shelly thing UID |
vehicle-motorcycle-k7-power.js |
Threshold voltages if your charger/ADC differs |
The items file creates 30 items — Shelly channels, BLE charger data, charge session tracking, and virtual state items used by the rules.
6. Test
- Plug in the battery charger
- Watch the log:
tail -f /var/log/openhab/openhab.log | grep k7_power - You should see:
PARKED → CHARGING → TRANSFERRING → COOLDOWN → DUMP_DONE - Disconnect charger → system re-arms to
PARKED
Sitemap (Optional)
Here’s how the K7 section looks in the sitemap — you can adapt this for your own UI:
Frame label="INNOVV K7 Dashcam" {
Text label="INNOVV K7 Dashcam" icon="camera" {
Frame label="Status" {
Text item=K7_Dump_Status
Text item=K7_Camera_Online
Text item=K7_Last_Dump
}
Frame label="Download Progress" {
Text item=K7_Transfer_Speed
Text item=K7_Files_Downloaded
Text item=K7_MB_Downloaded
}
Frame label="K7 Auto-Power (Shelly)" {
Text item=MC_K7_Power_State
Switch item=MC_K7_Relay mappings=[ON="ON", OFF="OFF"]
Text item=MC_Charger_Connection
Text item=MC_K7_Shelly_Voltage
}
}
}
A full sitemap extract with all K7 and Victron items is in the repo.
Adapting for Other Dashcams
While this project targets the INNOVV K7 specifically, the architecture is adaptable:
- Power switching (MOSFET + Shelly) works for any 12V dashcam
- State machine logic applies to any “charger detected → power on → download → power off” workflow
- Dump service needs modification for cameras with different APIs
- Any dashcam with a WiFi AP and HTTP file access can be adapted
The K7-specific parts are in k7_api.py (~200 lines) — the HTTP API calls for listing, downloading, and deleting files. If your camera has a different API, that’s the file to modify.
Lessons Learned
A few things I discovered building this:
-
Voltage thresholds are unreliable alone. Battery voltage after charging lingers above the detection threshold for minutes. The 5-minute grace period and BLE dual-sensor detection eliminated all false triggers.
-
The Shelly ADC reads ~2-3% low compared to a Fluke reference, and the offset is non-linear. Don’t apply a fixed offset — just use raw ADC values for all thresholds.
-
P-channel MOSFET with pull-up = perfect fail-safe. If anything goes wrong (Shelly crash, power loss, software bug), the relay opens, pull-up holds gate high, MOSFET stays OFF. The K7 stays off. Battery is safe.
-
K7 boot time matters. The K7 takes 20-30 seconds to boot and start its WiFi AP. The Pi dump service accounts for this with a retry loop.
-
GraalJS on openHAB 5:
java.time.Durationonly exposestoMinutes(). NeithertoSeconds()norgetSeconds()work. All duration checks use minute granularity.
Repository
All source code, wiring diagrams, and detailed documentation:
github.com/Prinsessen/innovv-k7-autodump-
Key files:
vehicle-motorcycle-k7-power.js— openHAB state machine (10 JSRules)shelly-failsafe-script.js— On-device Shelly failsafeinnovv_k7_dump.py— Pi dump serviceK7_AUTO_POWER_README.md— Detailed MOSFET circuit & BLE integration docsFIRMWARE_ANALYSIS.md— K7 firmware reverse engineering
Questions & Feedback
Happy to answer questions about the wiring, software, or adapting this for a different camera. The GitHub repo has full documentation including ADC calibration data, test results, and K7 firmware analysis.