Automated Motorcycle Dashcam Backup with openHAB, Shelly & Raspberry Pi — Triggered by Battery Charger Detection

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):

  1. isBLECharging() — Active charging: Bulk / Absorption / Float / Recondition
  2. isBLEConnected() — Charger on mains: includes Storage / Idle (full battery)
  3. 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

View failsafe script →

Pi Dump Service

The dump service runs on the Raspberry Pi as a systemd service. It handles the entire download pipeline:

  1. Detect K7 WiFi AP → connect via 5 GHz
  2. Scan K7’s HTTP API for files across all folders (Movie_E, Photo_E, EMR_E)
  3. Download each file with inline SHA-256 hashing (256 KB chunks)
  4. Verify read-back hash from NAS matches download hash
  5. Delete verified files from K7 (burst delete with recovery pauses)
  6. 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

View dump service source →

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

  1. Power on (connect battery) and connect to its setup AP via the Shelly app

  2. Set primary WiFi (STA0) to your home network

  3. Optionally set secondary WiFi (STA1) to phone hotspot for mobile control

  4. 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.

  5. 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

  1. Plug in the battery charger
  2. Watch the log: tail -f /var/log/openhab/openhab.log | grep k7_power
  3. You should see: PARKED → CHARGING → TRANSFERRING → COOLDOWN → DUMP_DONE
  4. 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:

  1. 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.

  2. 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.

  3. 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.

  4. 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.

  5. GraalJS on openHAB 5: java.time.Duration only exposes toMinutes(). Neither toSeconds() nor getSeconds() work. All duration checks use minute granularity.

Repository

All source code, wiring diagrams, and detailed documentation:

:arrow_right: github.com/Prinsessen/innovv-k7-autodump-

Key files:

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.

4 Likes

Great project, great description. It’s just one thing that I don’t understand: Why do you charge your MC after use?

Haha, I love that! Rest assured, it’s definitely not because it’s a secret electric motorcycle!

On a more serious note, it’s because the system uses a trickle charger. This is designed to maintain the battery health during long standby periods and, more importantly, to protect it through winter storage. It ensures the battery stays topped up and ready to go the moment the season starts, rather than letting it degrade while sitting idle.

I get maintenance charging during storage/winter or for long periods without use. But, it sounds to me like you’re plugging it after every trip, where the alternator normally has just topped up the battery. That was the point I wondered about :wink: