Protocole BLE

Contrôlez votre OSSM sans fil à l'aide du Bluetooth Low Energy (BLE) à partir de n'importe quel appareil ou application compatible

L'OSSM utilise Bluetooth Low Energy (BLE) pour le contrôle et la surveillance sans fil. Vous pouvez créer des applications client qui se connectent à l'OSSM pour envoyer des commandes et recevoir des mises à jour d'état en temps réel.

BLE fournit un contrôle sans fil à faible latence avec reconnexion automatique et synchronisation d'état.

Avant de commencer

Pour vous connecter à votre OSSM via BLE, assurez-vous :

  • Votre appareil prend en charge Bluetooth Low Energy (BLE 4.0+)
  • L'OSSM est sous tension et n'est pas connecté à un autre client BLE
  • Vous êtes à environ 10 mètres de l'appareil

Architecture des services

L'OSSM implémente un service BLE personnalisé avec de multiples caractéristiques organisées en groupes fonctionnels.

UUID du service principal

522b443a-4f53-534d-0001-420badbabe69

Les caractéristiques sont organisées par plages d'espaces de noms pour faciliter l'expansion et la découverte.

Référence des caractéristiques

Caractéristiques des commandes (inscriptibles)

Utilisez ces caractéristiques pour envoyer des commandes et configurer l'OSSM.

Caractéristique de commande principale

PropriétéValeur
UUID522b443a-4f53-534d-1000-420badbabe69
PropriétésREAD, WRITE
ButEnvoyer des commandes pour contrôler le comportement de l'OSSM

Format de commande

set:<parameter>:<value>
go:<state>

Commandes disponibles

CommandeParamètrePlage de valeursDescription
set:speed:<value>speed0-100Définir le pourcentage de vitesse de course
set:stroke:<value>stroke0-100Définir le pourcentage de longueur de course
set:depth:<value>depth0-100Définir le pourcentage de profondeur de pénétration
set:sensation:<value>sensation0-100Définir le pourcentage d'intensité de sensation
set:pattern:<value>pattern0-6Définir le motif de course (voir motifs)
go:simplePenetration--Passer en mode pénétration simple depuis le menu
go:strokeEngine--Passer en mode Stroke Engine depuis le menu
go:streaming--Passer en mode streaming (expérimental) depuis le menu
go:menu--Revenir au menu principal depuis n'importe quel mode
stream:<pos>:<time>pos, timepos: 0-100, time: msEnvoyer une commande de position en mode streaming (expérimental)

Format de réponse

RéponseSignification
ok:<original_command>Commande exécutée avec succès
fail:<original_command>Échec de la commande (vérifier le format ou l'état actuel)

Attendez toujours la réponse avant d'envoyer une autre commande. Les commandes sont traitées séquentiellement.

Caractéristique de configuration du bouton de vitesse

PropriétéValeur
UUID522b443a-4f53-534d-1010-420badbabe69
PropriétésREAD, WRITE
ButConfigurer si le bouton de vitesse physique limite les commandes de vitesse BLE

Valeurs de configuration

ValeurDescription
true, 1, tLe bouton de vitesse agit comme limite supérieure (par défaut)
false, 0, fLe bouton de vitesse et la vitesse BLE sont indépendants

Lorsque la valeur est définie sur true, les commandes de vitesse BLE (0-100) sont traitées comme un pourcentage de la position physique actuelle du bouton.

Exemple : Bouton à 50%, commande BLE set:speed:80 → Vitesse effective = 40%

Ce mode fournit une limite de sécurité matérielle que les utilisateurs peuvent contrôler physiquement.

Format de réponse

RéponseSignification
true ou falseValeur de configuration actuelle
error:invalid_valueEntrée invalide fournie

Caractéristique de configuration de compensation de latence

PropriétéValeur
UUID522b443a-4f53-534d-1030-420badbabe69
PropriétésREAD, WRITE
ButConfigurer si l'OSSM tente de compenser la latence

Valeurs de configuration

ValeurDescription
true, 1, tLa compensation de latence est active
false, 0, fLa compensation de latence est inactive (par défaut)

Lorsqu'il est défini sur true, l'OSSM s'attend à recevoir les commandes et les temps exacts du funscript, et à ce que les commandes soient envoyées avec le même délai entre les commandes que la valeur de temps. En calculant le temps entre les commandes reçues et la variable de temps, l'OSSM peut déterminer la latence introduite par BLE et la corriger en modifiant légèrement la vitesse du mouvement. Si le temps entre les commandes ne correspond pas à la variable intime, cette option ne doit pas être activée. Le réglage du tampon sert à ajouter artificiellement un délai à tous les mouvements. L'OSSM dispose ainsi du temps nécessaire pour recevoir la commande suivante avant la fin de la précédente. Cela permet de supprimer les retards introduits par les commandes tardives et de lisser le mouvement en combinant les mouvements dans la même direction. Les lecteurs Funscript doivent ajouter cette valeur de tampon à leur décalage de lecture et prévoir un réglage supplémentaire pour affiner ce décalage, afin de tenir compte du temps de transmission et de tout retard inhérent au funscript lui-même.

Format de réponse

RéponseSignification
true ou falseValeur de configuration actuelle
error:invalid_valueEntrée invalide fournie

Caractéristique de configuration WiFi

PropriétéValeur
UUID522b443a-4f53-534d-1020-420badbabe69
PropriétésREAD, WRITE
ButConfigurez les informations d'identification WiFi et vérifiez l'état de la connexion

Format d'écriture

set:wifi:<ssid>|<password>

Le caractère pipe (|) est utilisé comme délimiteur entre le SSID et le mot de passe. Cela permet à la fois au SSID et au mot de passe de contenir des deux-points.

Format de lecture (JSON)

{
  "connected": true,
  "ssid": "NetworkName",
  "ip": "192.168.1.100",
  "rssi": -45
}

Lorsqu'il n'est pas connecté, le champ ssid contiendra le dernier SSID enregistré (le cas échéant), ip sera vide et rssi sera 0.

Format de réponse

RéponseSignification
ok:wifi:connectedConnecté avec succès
ok:wifi:savedIdentifiants enregistrés, tentative de connexion
fail:wifi:invalid_formatFormat de commande incorrect (délimiteur pipe (|) manquant)
fail:wifi:invalid_ssidLongueur du SSID invalide (doit comporter entre 1 et 32 caractères)
fail:wifi:invalid_passwordLongueur du mot de passe invalide (doit comporter entre 8 et 63 caractères)
fail:wifi:connection_failedImpossible de se connecter au réseau
fail:wifi:save_failedÉchec de l'enregistrement des informations d'identification sur NVS

Les informations d'identification WiFi sont conservées dans un stockage non volatile (NVS) et seront conservées lors des redémarrages de l'appareil. L'appareil tentera de se connecter automatiquement à l'aide des informations d'identification enregistrées au démarrage.

Les informations d'identification WiFi sont transmises en texte brut via BLE. Assurez-vous que vous faites confiance à la connexion et que vous vous trouvez dans un environnement sécurisé lors de la configuration des paramètres WiFi.

Exemple d'utilisation

// Configure WiFi
const wifiCommand = "set:wifi:MyNetwork|MyPassword123";
await commandChar.writeValue(new TextEncoder().encode(wifiCommand));

// Read the response
const response = await commandChar.readValue();
console.log(new TextDecoder().decode(response)); // "ok:wifi:connected"

// Check WiFi status
const wifiConfigChar = await service.getCharacteristic(
  "522b443a-4f53-534d-1020-420badbabe69"
);
const statusValue = await wifiConfigChar.readValue();
const status = JSON.parse(new TextDecoder().decode(statusValue));
console.log(status);
// { "connected": true, "ssid": "MyNetwork", "ip": "192.168.1.100", "rssi": -45 }

Caractéristiques de l'état (lecture seule)

Abonnez-vous à ces caractéristiques pour surveiller l'état actuel de l'OSSM.

Caractéristique de l'état actuel

PropriétéValeur
UUID522b443a-4f53-534d-2000-420badbabe69
PropriétésREAD, NOTIFY
ButSurveiller l'état et les paramètres actuels d'OSSM

Format JSON d'état

{
  "state": "<state_name>",
  "speed": 0-100,
  "stroke": 0-100,
  "sensation": 0-100,
  "depth": 0-100,
  "pattern": 0-6
}

Comportement de notification

  • Les changements d'état déclenchent des notifications immédiates
  • Notifications périodiques toutes les 1 000 ms lorsqu'aucun changement d'état ne se produit
  • Les notifications s'arrêtent lorsqu'aucun client n'est connecté

Caractéristiques des informations sur les motifs

Caractéristique de la liste des motifs

PropriétéValeur
UUID522b443a-4f53-534d-3000-420badbabe69
PropriétésREAD
ButObtenir les motifs de course disponibles

Format de réponse

[
  { "name": "Simple Stroke", "idx": 0 },
  { "name": "Teasing Pounding", "idx": 1 },
  { "name": "Robo Stroke", "idx": 2 },
  { "name": "Half'n'Half", "idx": 3 },
  { "name": "Deeper", "idx": 4 },
  { "name": "Stop'n'Go", "idx": 5 },
  { "name": "Insist", "idx": 6 }
]

Caractéristique de description du motif

PropriétéValeur
UUID522b443a-4f53-534d-3010-420badbabe69
PropriétésREAD, WRITE
ButObtenir des descriptions pour des motifs de course individuels

Pour récupérer une description de motif :

Écrire l'index du motif

Écrivez le numéro d'index (0-6) dans la caractéristique.

Lire le descriptif

Lisez la caractéristique pour recevoir la chaîne de description du motif.

Descriptions des motifs

MotifIndiceDescription
Simple Stroke0Accélération, roue libre et décélération également réparties ; aucune sensation
Teasing Pounding1Changements de vitesse avec sensation ; équilibre les mouvements plus rapides
Robo Stroke2La sensation fait varier l'accélération ; du robotique au progressif
Half'n'Half3Les courses en pleine et demi-profondeur alternent ; la sensation affecte la vitesse
Deeper4La profondeur de course augmente par cycle ; la sensation détermine le nombre
Stop'n'Go5Pauses entre les courses ; la sensation ajuste la longueur
Insist6Modifie la longueur, maintient la vitesse ; la sensation influence la direction

Commandes de streaming (expérimental)

Le streaming de position est expérimental et n’est pas recommandé pour une utilisation générale. Le protocole et le comportement peuvent changer dans les futures mises à jour du micrologiciel.

En mode streaming (go:streaming), l'OSSM accepte les commandes de position en temps réel qui permettent une lecture synchronisée avec du contenu externe tel que des funscripts.

Commande de position du flux

PropriétéValeur
Formatstream:<position>:<time>
Position0-100 (pourcentage de la course)
TempsMillisecondes pour atteindre la position cible

Exemples de commandes

stream:0:200      # Move to 0% (retracted) in 200ms
stream:100:150    # Move to 100% (extended) in 150ms
stream:50:300     # Move to 50% (mid-stroke) in 300ms

Comment ça marche

  1. Entrez en mode streaming avec go:streaming
  2. L'OSSM effectue son référencement jusqu’à la position 0 (complètement rétractée)
  3. Envoyez des commandes stream:<pos>:<time> pour contrôler le mouvement
  4. Le firmware calcule la vitesse requise pour atteindre la position cible dans le temps spécifié
  5. Le mouvement utilise une accélération maximale pour une sensation de réactivité

La position 0 correspond à une rétraction complète (position d’origine) et la position 100 à une extension complète. Le paramètre de temps indique la durée du mouvement, permettant à l’OSSM de calculer la vitesse appropriée pour une lecture fluide.

Exigences

  • Version du micrologiciel 3.0 ou ultérieure
  • OSSM doit être en mode streaming (état : streaming ou streaming.idle)
  • Commandes envoyées via la caractéristique de commande principale

Pour la lecture de funscript, consultez l'outil Lecteur Funscript qui gère automatiquement le timing et la génération de commandes.

Caractéristiques GPIO

Caractéristique de contrôle GPIO

PropriétéValeur
UUID522b443a-4f53-534d-4000-420badbabe69
PropriétésREAD, WRITE
ButContrôlez les broches de sortie GPIO pour les accessoires et les intégrations

Écrivez les commandes au format <pin>:<state> où la broche est 1-4 et l'état est high/low ou 1/0.

Mappage des broches :

Broche logiqueESP32 GPIO
1GPIO 2
2GPIO 15
3GPIO 22
4GPIO 33

Format de réponse :

RéponseSignification
ok:<pin>:<state>Broche définie avec succès
error:invalid_formatFormat de commande non reconnu
error:pin_out_of_rangeNuméro de broche non 1-4

Pour une documentation GPIO détaillée, y compris des exemples d'intégration matérielle, voir Contrôle GPIO.

Émulation Fleshy Thrust Sync (tests uniquement)

Cette fonctionnalité est destinée uniquement aux tests de développement et son utilisation n'est pas recommandée. Elle nécessite une version spéciale du micrologiciel et pourra être supprimée dans les versions futures.

Le micrologiciel OSSM peut éventuellement émuler le protocole BLE Fleshy Thrust Sync (FTS) pour les tests de compatibilité avec des applications telles que faptap.net. Cette fonctionnalité est désactivée par défaut et nécessite la compilation du firmware avec l’option de compilation PRETEND_TO_BE_FLESHY_THRUST_SYNC.

Service FTS

PropriétéValeur
UUID du service0000ffe0-0000-1000-8000-00805f9b34fb
UUID de la caractéristique0000ffe1-0000-1000-8000-00805f9b34fb
PropriétésREAD, WRITE, NOTIFY, INDICATE

Format de protocole binaire

FTS utilise un format binaire compact plutôt que des commandes texte :

OctetDescriptionPlage
0Position0-180 (uint8)
1Octet de poids fort du tempsMSB du temps en ms
2Octet de poids faible du tempsLSB du temps en ms

Mappage de position : 0 = entièrement rétracté, 180 = entièrement étendu

Format du temps/de la durée : entier non signé de 16 bits en gros-boutiste (ordre des octets du réseau)

Exemple

Pour passer à la position 90 (étendue à 50 %) en 250 ms :

Byte 0: 0x5A (90 decimal - position)
Byte 1: 0x00 (250 >> 8 = 0)
Byte 2: 0xFA (250 & 0xFF = 250)

L'émulation FTS utilise le même mécanisme de streaming sous-jacent que la commande native stream:pos:time. L'OSSM doit être en mode streaming pour que les commandes prennent effet.

Pourquoi ce n'est pas recommandé

  • Le protocole FTS est une spécification tierce non contrôlée par le projet OSSM
  • Les modifications de protocole dans les applications compatibles FTS peuvent rompre la compatibilité
  • Le protocole de streaming OSSM natif (stream:pos:time) est préféré pour les nouvelles intégrations
  • Cette fonctionnalité existe principalement pour tester la compatibilité avec les écosystèmes FTS existants

Service d'informations sur les appareils

L'OSSM implémente le service d'informations sur les appareils BLE standard pour l'identification.

CaractéristiqueUUIDValeur
Service180AService d'informations sur les appareils
Nom du fabricant2A29"Research And Desire"
ID système2A2388:1A:14:FF:FE:34:29:63

Structure de l'espace de noms UUID

L'OSSM utilise un espace de noms UUID structuré pour une expansion organisée.

UUID du service

0x0001 = Service UUID

Plages d'espaces de noms

PlagePlage hexadécimaleDescription
0x00x0000–0x0FFFRéservé aux messages système
0x10x1000–0x1FFFCommandes et configuration
0x20x2000–0x2FFFInformations sur l'état
0x30x3000–0x3FFFInformations sur les motifs
0x40x4000–0x4FFFParamétrage des broches GPIO
0x5–0xD0x5000–0xDFFFRéservé pour une utilisation future
0xE0xE000–0xEFFFRéservé aux statistiques
0xF0xF000–0xFFFFExpérimental / bac à sable (volatile)

Affectations de caractéristiques actuelles

522b443a-4f53-534d-1000-420badbabe69  # Primary command
522b443a-4f53-534d-1010-420badbabe69  # Speed knob configuration
522b443a-4f53-534d-1020-420badbabe69  # WiFi configuration

Gestion des connexions

Diffusion BLE

ParamètreValeur
Nom de l'appareilOSSM
UUID des servicesService principal + Service d'informations sur les appareils
Intervalle de diffusion20-40 ms (optimisé pour la fiabilité)
Redémarrage automatiqueLa diffusion reprend lorsque tous les clients se déconnectent

Sécurité

ParamètreValeur
Couplage"Just Works" (aucune authentification requise)
CryptageBLE Secure Connections activées
BondingDésactivé (pas de couplage persistant)

L'OSSM utilise le couplage « Just Works » pour faciliter son utilisation. Toute personne à portée de BLE peut se connecter lorsque l'appareil diffuse.

Sécurité de déconnexion

Lorsqu'une connexion BLE est perdue de manière inattendue, l'OSSM réduit automatiquement la vitesse pour éviter un fonctionnement incontrôlable.

Comportement de décélération :

  1. Connexion perdue détectée
  2. Délai d'une seconde — permet de brèves interruptions de signal sans déclenchement
  3. Rampe de 2 secondes — la vitesse diminue de la valeur actuelle à zéro à l'aide d'une courbe sinusoïdale à accélération/décélération progressive
  4. L'appareil continue à vitesse nulle jusqu'à ce qu'il soit reconnecté ou arrêté manuellement

La courbe sinusoïdale à accélération/décélération progressive offre une décélération douce qui semble naturelle et réduit les contraintes mécaniques. Si la vitesse était déjà nulle au moment de la déconnexion, aucune rampe ne se produit.

Considérations pour les clients :

  • Mettre en œuvre une surveillance des connexions pour détecter rapidement les déconnexions
  • Envisagez une logique de reconnexion automatique
  • Les commandes locales (potentiomètre, encodeur) restent actives pendant et après la déconnexion
  • Les utilisateurs peuvent arrêter manuellement via le bouton de vitesse ou appuyer longuement pour un arrêt d'urgence

Guide de mise en œuvre client

Flux de connexion

Suivez ces étapes pour établir une connexion et commencer à contrôler votre OSSM :

Rechercher l'appareil

Recherchez les appareils BLE portant le nom « OSSM ».

L'appareil apparaît dans les résultats de l'analyse.

Connectez-vous à l'appareil

Établissez une connexion GATT à l’OSSM.

Découvrez les services

Découvrez tous les services et caractéristiques de l'appareil.

L'UUID du service principal 522b443a-4f53-534d-0001-420badbabe69 est trouvé.

Abonnez-vous aux notifications d'état

Activez les notifications sur la caractéristique d'état pour recevoir des mises à jour en temps réel.

Lire l'état initial

Lisez l'état actuel et la liste des motifs pour initialiser votre application.

Envoyer des commandes

Commencez à envoyer des commandes pour contrôler l’OSSM.

Meilleures pratiques

Gestion des commandes

  • Valider le format de la commande avant de l'envoyer
  • Gérer les réponses ok: et fail:
  • Implémenter une logique de nouvelle tentative pour les commandes critiques
  • Surveiller les changements d'état pour confirmer l'exécution de la commande

Surveillance de l'état

  • Abonnez-vous aux notifications sur les caractéristiques de l'état
  • Analyser les mises à jour de l'état JSON de manière fiable
  • Gérer les transitions d'état de manière appropriée
  • Implémenter la gestion des délais d'attente pour les mises à jour manquantes

Exemple de code

// Connect to OSSM
const device = await navigator.bluetooth.requestDevice({
  filters: [{ name: "OSSM" }],
  optionalServices: ["522b443a-4f53-534d-0001-420badbabe69"],
});

const server = await device.gatt.connect();
const service = await server.getPrimaryService(
  "522b443a-4f53-534d-0001-420badbabe69"
);

// Get characteristics
const commandChar = await service.getCharacteristic(
  "522b443a-4f53-534d-1000-420badbabe69"
);
const stateChar = await service.getCharacteristic(
  "522b443a-4f53-534d-2000-420badbabe69"
);
const speedKnobConfigChar = await service.getCharacteristic(
  "522b443a-4f53-534d-1010-420badbabe69"
);
const wifiConfigChar = await service.getCharacteristic(
  "522b443a-4f53-534d-1020-420badbabe69"
);
const patternsChar = await service.getCharacteristic(
  "522b443a-4f53-534d-3000-420badbabe69"
);

// Subscribe to state updates
await stateChar.startNotifications();
stateChar.addEventListener("characteristicvaluechanged", (event) => {
  const state = JSON.parse(new TextDecoder().decode(event.target.value));
  console.log("State update:", state);
});

// Configure speed knob behavior (true = knob as limit, false = independent)
await speedKnobConfigChar.writeValue(new TextEncoder().encode("true"));

// Configure WiFi
await wifiConfigChar.writeValue(new TextEncoder().encode("set:wifi:MyNetwork|MyPassword123"));

// Check WiFi status
const wifiStatus = await wifiConfigChar.readValue();
console.log("WiFi:", JSON.parse(new TextDecoder().decode(wifiStatus)));

// Send a command
const command = "set:speed:75";
await commandChar.writeValue(new TextEncoder().encode(command));

// Read available patterns
const patterns = await patternsChar.readValue();
const patternList = JSON.parse(new TextDecoder().decode(patterns));
console.log("Available patterns:", patternList);
import asyncio
import json
from bleak import BleakClient

SERVICE_UUID = "522b443a-4f53-534d-0001-420badbabe69"
COMMAND_UUID = "522b443a-4f53-534d-1000-420badbabe69"
STATE_UUID = "522b443a-4f53-534d-2000-420badbabe69"
SPEED_KNOB_UUID = "522b443a-4f53-534d-1010-420badbabe69"
WIFI_CONFIG_UUID = "522b443a-4f53-534d-1020-420badbabe69"

def state_callback(sender, data):
    """Handle state update notifications."""
    state = json.loads(data.decode())
    print(f"State update: {state}")

async def connect_to_ossm():
    async with BleakClient("OSSM") as client:
        # Subscribe to state updates
        await client.start_notify(STATE_UUID, state_callback)

        # Configure speed knob behavior
        await client.write_gatt_char(
            SPEED_KNOB_UUID,
            "true".encode()  # Knob acts as upper limit
        )

        # Configure WiFi
        await client.write_gatt_char(
            WIFI_CONFIG_UUID,
            "set:wifi:MyNetwork|MyPassword123".encode()
        )

        # Check WiFi status
        wifi_status = await client.read_gatt_char(WIFI_CONFIG_UUID)
        print(f"WiFi status: {json.loads(wifi_status.decode())}")

        # Send a command
        command = "set:speed:75"
        await client.write_gatt_char(COMMAND_UUID, command.encode())

        # Keep connection alive to receive notifications
        await asyncio.sleep(10)

asyncio.run(connect_to_ossm())

Dépannage

Informations de débogage

Activez la journalisation ESP32 au niveau DEBUG pour obtenir des informations détaillées sur le protocole. Surveillez l’état de la connexion BLE, les modifications de MTU et les transitions de la machine d’état.

Sur cette page