Zum Inhalt springen
>_marc-oltersdorf.de

Canyon ECLIPS: Lichtsteuerung fehlt in der App – Lichter per Web Bluetooth steuern

Marc Oltersdorf 3 Min. Lesezeit

Nach der Nutzung der Canyon-App war die komplette ECLIPS-Steuerung verschwunden – kein Verbinden, kein Licht, kein Akkustand. Die Ursache liegt nicht am Rad oder an der Kopplung, sondern an fehlenden Daten vom Canyon-Server. Bis das behoben ist, lassen sich die Lichter über ein paar Zeilen Web Bluetooth direkt ansteuern.

$ git log --graph Der Weg zur Lösung

  1. Problem Steuerung weg

    Nach der App-Nutzung fehlt der komplette ECLIPS-Bereich in der Canyon-App, ohne Fehlermeldung.

  2. Irrweg Erst an App und Kopplung gedacht

    Neuinstallation, alle Berechtigungen, neu koppeln – half nichts. Die Lichter am Rad gehen ja, nur die App bietet nichts an.

  3. Erkenntnis Es liegt an den Server-Daten

    Die App zeigt ECLIPS nur, wenn die Fahrraddaten die Fähigkeit eclips enthalten. Für das Rad kam capabilities leer zurück; der Funktionsschalter war an.

  4. Versuch Gegenprobe per Laufzeit-Analyse

    Der App zur Laufzeit die Fähigkeit eclips untergeschoben → die Steuerung erschien sofort. Also kein App-Bug, sondern fehlende Server-Daten (Fall für den Support).

  5. Erkenntnis Die Lichter sind direkt erreichbar

    Aus der App die BLE-Befehle extrahiert – Nordic UART, ein Byte je Befehl, keine Verschlüsselung.

  6. Lösung Web-Bluetooth-Seite

    Eine kleine Seite verbindet sich direkt mit dem ECLIPS und schaltet Front/Rück und liest den Status. Am Rad bestätigt: Lichter reagieren korrekt.

An meinem Canyon-Rad sitzt die ECLIPS-Anlage (Lichter vorne/hinten mit Dynamo-gepuffertem Akku). Gesteuert wird sie sonst über die Canyon-App (Android, Version 8.5.0). Nach einem Update war in der App der komplette ECLIPS-Bereich weg: kein „Mit ECLIPS-System verbinden", keine Lichtschalter, kein Akkustand. Keine Fehlermeldung – die Funktion ist einfach nicht mehr da.

Das Problem

Die App zeigt mein Rad korrekt in der Garage an, aber die ganze ECLIPS-Steuerung fehlt. Neuinstallation, alle Berechtigungen (Bluetooth, Standort, Kamera) erteilt, neu gekoppelt – nichts half. Die Lichter selbst funktionieren am Rad, nur die App bietet keine Steuerung mehr an.

Die Ursache: fehlt beim Server, nicht am Rad

Die App blendet den ECLIPS-Bereich nur ein, wenn die Fahrraddaten vom Canyon-Server die Fähigkeit eclips enthalten. Genau die fehlte für mein Rad – das Feld capabilities kam leer zurück. Der interne Funktionsschalter für ECLIPS war dagegen aktiv, lag also nicht daran.

Bestätigt habe ich das mit Laufzeit-Instrumentierung (Frida) auf einem gerooteten Android-Telefon: Sobald man der App die Fähigkeit eclips unterschiebt, erscheint die komplette Steuerung sofort wieder. Es ist also kein Bug in der App, sondern ein fehlender Eintrag in den Server-Daten. Das kann nur der Hersteller-Support korrigieren – mit Rad- und ECLIPS-Seriennummer.

Die Lösung: direkt per Bluetooth

Das ECLIPS meldet sich per Bluetooth Low Energy als Canyon Power Supply und spricht den Nordic UART Service – unverschlüsselt, ein einzelnes Byte je Befehl. Die Befehle habe ich aus der App herausgelesen:

ByteFunktion
0x03Frontlicht an
0x04Frontlicht aus
0x05Rücklicht an
0x06Rücklicht aus
0x0EStatus abfragen (Antwort als Text)

Das reicht für eine kleine Steuerung im Browser. Web Bluetooth kann sich als Zentrale mit dem Gerät verbinden – es braucht nur Chrome oder Edge und eine HTTPS-Seite:

// Nordic UART Service des ECLIPS ("Canyon Power Supply")
const NUS = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
const RX  = "6e400002-b5a3-f393-e0a9-e50e24dcca9e"; // zum Gerät schreiben
const TX  = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"; // Antworten vom Gerät

let rx;

async function verbinden() {
  const dev = await navigator.bluetooth.requestDevice({
    filters: [{ services: [NUS] }, { namePrefix: "Canyon" }],
  });
  const server = await dev.gatt.connect();
  const svc = await server.getPrimaryService(NUS);
  rx = await svc.getCharacteristic(RX);
  const tx = await svc.getCharacteristic(TX);
  tx.addEventListener("characteristicvaluechanged", (e) => {
    console.log(new TextDecoder().decode(e.target.value));
  });
  await tx.startNotifications();
}

// ein Byte je Befehl: 0x03 Front an, 0x04 Front aus,
// 0x05 Rück an, 0x06 Rück aus, 0x0E Status
const senden = (byte) => rx.writeValue(new Uint8Array([byte]));

Nach verbinden() schaltet senden(0x03) das Frontlicht ein, senden(0x05) das Rücklicht. Auf 0x0E antwortet das Gerät mit einer Statuszeile im Klartext:

UID: cps_02   Chg: 0, 0   iBat: -10 mA   VBat: 8280 mV   SOC: 82%
USB: 0   FL: 0   RL: 0   Speed: 0 km/h   FW: 0.1.0   Power State: 0

Daraus liest man alles Wichtige: SOC Akkustand in Prozent, VBat Spannung in mV, iBat Strom in mA (negativ = Entladen), FL/RL Licht vorne/hinten (0/1), Speed die Dynamo-Geschwindigkeit, Chg die Ladephase.

Warum das funktioniert

Die App macht beim Schalten nichts anderes: Sie schreibt dieses eine Byte auf die Schreib-Charakteristik des UART-Service. Es gibt keine Verschlüsselung und kein App-Token auf der Datenebene – die einzige Hürde ist die normale Bluetooth-Kopplung des Betriebssystems. Was die App vom Server braucht (die eclips-Fähigkeit), betrifft nur die Anzeige in der App, nicht die Kommunikation mit dem Gerät. Deshalb funktioniert der direkte Weg, auch wenn die App streikt.

Stolperfallen

  • Kopplung: Beim ersten Verbinden fragt Android einen PIN – das sind die letzten 6 Ziffern der Seriennummer des ECLIPS. Danach merkt sich das System die Kopplung.
  • Gerätename: In der Bluetooth-Auswahl heißt es Canyon Power Supply, nicht „ECLIPS".
  • Keine Helligkeitsstufen: Jedes Licht ist nur an oder aus. Was der Lenkertaster umschaltet, ist Automatik (nach Akku/Dynamo) gegen manuell – keine Dimmstufen. Das sieht man auch an der Firmware (ein Nordic nRF52840 mit Zephyr): es gibt dort schlicht keine Helligkeits- oder Blinkmodi für die Lichter.
  • Nach jedem Schalten lohnt ein 0x0E, um den echten Zustand gegenzulesen – so sieht man sofort, ob der Befehl angekommen ist.

Hat dir das geholfen?

RSS abonnieren

$ ls ../ Passt dazu