Skip to main content
Glama
SafaAslan

Engwe N1 Air MCP Server

by SafaAslan
README.md
# 🚲 Engwe N1 Air — BLE Reverse Engineering + Claude MCP Server

> Reverse engineered the Engwe N1 Air e-bike's Bluetooth protocol and built a Claude AI integration to control it from your Mac.

![License](https://img.shields.io/badge/license-MIT-blue)
![Python](https://img.shields.io/badge/python-3.9+-blue)
![Node](https://img.shields.io/badge/node-18+-green)

## What This Does

- šŸš€ **Unlock speed limit** via Bluetooth (up to 40 km/h)
- šŸ”’ **Lock/unlock** the bike remotely via IoT API
- šŸ”Š **Find your bike** (sound + light alarm)
- šŸ”‹ **Battery, mileage, cadence** real-time stats
- šŸ“ **Geo-fence** management
- šŸ’Ŗ **PAS level** control via Bluetooth
- šŸ¤– **Claude AI integration** — control your bike by talking to Claude
- šŸ–„ļø **Mac menubar app** — one-click access to all features

---

## How It Was Built

### Step 1 — API Discovery (Charles Proxy)
Captured network traffic from the Engwe iOS app using Charles Proxy. Found the main API endpoint at `app-api.engweapp.com` with JWT authentication.

### Step 2 — APK Decompile (JADX)
Decompiled the Android APK using JADX to find all internal API endpoints and BLE command codes.

```bash
jadx -d engwe-source ENGWE_2.7.2_APKPure.xapk
grep -r "iot/device" engwe-source --include="*.java" | grep -o '"[^"]*iot/device[^"]*"' | sort -u
```

### Step 3 — BLE Protocol Reverse Engineering
Found the complete BLE protocol in `ProtocolUtil.java` and `BLEBikeCommand.java`.

**V2 Protocol Format:**
```
456E + CMD(4) + LEN(4) + DATA + CRC16(4) + 7765
```

**BLE UUIDs (from BluetoothRegulate.java):**
```
Service:  00001820-0000-1000-8000-00805f9b34fb
Write:    00001822-0000-1000-8000-00805f9b34fb
Notify:   00001821-0000-1000-8000-00805f9b34fb
```

---

## BLE Command Reference

All commands use V2 protocol format: `456E + CMD + LEN + DATA + CRC16 + 7765`

| Command | Hex | Description |
|---------|-----|-------------|
| Speed Limit | `2A65` | 0x00=0, 0x10=10, 0x20=20, 0x30=30, 0x40=40 km/h |
| PAS Level | `010A` | 0x00–0x05 |
| Motor Current Limit | `2A66` | Under investigation |
| Cruise Control Set | `0128` | Under investigation |
| Wheel Diameter | `08C3` | Under investigation |
| Factory Reset | `8049` | āš ļø Irreversible |
| Lock State | `0108` | Query lock |
| Power On/Off | `0107` | 01=on, 02=off |
| Auto Shutdown Time | `1000` | Minutes |

**Speed Limit Example (40 km/h):**
```python
# Index 4 * 16 = 0x40
command = "456E2A650001406A237765"
```

**CRC16 Calculation (ModBus):**
```python
def crc16(hex_str):
    data = bytes.fromhex(hex_str)
    crc = 0xFFFF
    for byte in data:
        crc ^= byte
        for _ in range(8):
            crc = (crc >> 1) ^ 0xA001 if crc & 1 else crc >> 1
    return format(crc, "04X")

# CRC input = CMD + LEN + DATA
# Example: crc16("2A65" + "0001" + "40") = "6A23"
```

---

## IoT API Endpoints

Base URL: `https://app-api.engweapp.com`

| Endpoint | Description |
|----------|-------------|
| `/api/app/iot/device/lockSwitch` | Lock/unlock bike |
| `/api/app/iot/device/findVehicle` | Sound + light alarm |
| `/api/app/iot/device/vibrationAlarmSwitch` | Vibration alarm + signal |
| `/api/app/iot/device/fenceSwitch` | Geo-fence on/off |
| `/api/app/iot/device/getFenceList` | List geo-fences |
| `/api/app/iot/device/bleSenselessSwitch` | BLE auto-unlock |
| `/api/app/iot/device/headlightSwitch` | Headlight + realtime PAS/charge |
| `/api/app/iot/device/attr/newest` | Battery SOC/SOH, mileage, cadence |
| `/api/app/iot/device/version` | IoT/BT/4G firmware versions |
| `/api/app/iot/device/attr/newest` | Real-time attributes |
| `/api/app/paypal/syDetail` | IoT subscription info |
| `/api/app/ride-data/index` | Weekly ride statistics |

---

## Installation

### Requirements
- Node.js 18+
- Python 3.9+
- Mac (for menubar app)

```bash
git clone https://github.com/SafaAslan/engwe-n1air-mcp
cd engwe-n1air-mcp
npm install
pip3 install bleak
```

### Get Your Token
Use Charles Proxy to capture traffic from the Engwe iOS/Android app. Find the `Authorization` header in any request to `app-api.engweapp.com`.

### Configure Claude Desktop

`~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "engwe-n1air": {
      "command": "node",
      "args": ["/path/to/engwe-n1air-mcp/index.js"],
      "env": {
        "ENGWE_IMEI": "YOUR_IMEI",
        "ENGWE_BLE_MAC": "YOUR_BLE_MAC",
        "ENGWE_TOKEN": "YOUR_JWT_TOKEN"
      }
    }
  }
}
```

### Find Your IMEI & BLE MAC
```bash
# IMEI — visible in Engwe app under bike settings
# BLE MAC — run while bike is on:
python3 -c "
import asyncio
from bleak import BleakScanner
async def scan():
    devices = await BleakScanner.discover(timeout=10)
    for d in devices:
        if d.name and 'ENGWE' in d.name.upper():
            print(d.address, d.name)
asyncio.run(scan())
"
```

---

## Usage

### Claude AI (via MCP)
Once configured, just talk to Claude:
- *"Lock my bike"*
- *"What's my battery level?"*
- *"Set speed limit to 35 km/h"*
- *"Show my ride stats for this week"*

### Menubar App (Mac)
```bash
npm install electron
./node_modules/.bin/electron tray.js
```

### Auto-start on Boot
```bash
chmod +x setup_autostart.sh
bash setup_autostart.sh
```

### Speed Limit Script (standalone)
```bash
python3 ble_speed3.py
```

---

## Project Structure

```
engwe-n1air-mcp/
ā”œā”€ā”€ index.js          # Claude MCP server (18 tools)
ā”œā”€ā”€ tray.js           # Mac menubar app
ā”œā”€ā”€ ble_speed3.py     # Standalone speed limit script
ā”œā”€ā”€ ble_scan2.py      # BLE device scanner
ā”œā”€ā”€ setup_autostart.sh # Mac autostart setup
└── README.md
```

---

## āš ļø Disclaimer

Unlocking the speed limit above 25 km/h is **illegal on public roads in the EU**. This project is for educational and off-road/private use only. Use at your own risk. This project is not affiliated with Engwe.

---

## Contributing

Pull requests welcome! Especially interested in:
- Testing on other Engwe models (P275 SE, M20, etc.)
- Cruise control command (`0128`)
- Motor current limit (`2A66`)
- Android version of menubar app

---

## License

MIT