Connecter l'arduino à une API

Bonjour,

Je cherche à créer un objet qui m'afficherait le nom des bateaux qui passent à proximité de ma maison.
C'est mon premier projet Arduino, je n'ai probablement pas les bons réflexes.
J'avais codé un programme en Python qui était fonctionnel, j'ai voulu l'adapter à l'Arduino, mais je n'arrive pas à me connecter au Websocket.

Voici mon code:

#include <WiFiS3.h>
#include <WebSocketsClient.h>

const char* ssid = "mon_ssid";
const char* password = "mon_password";
const char* apiKey = "mon_apikey";
const char* bbox = "[[[47.01, -2.00], [49.02, -1.12]]]";

WebSocketsClient webSocket;

void setup() {
    Serial.begin(9600);
    WiFi.begin(ssid, password);  // Connexion au WiFi

    // Attendez la connexion
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("En attente de connexion WiFi...");
    }

    Serial.println("Connecté au WiFi");

    // Configuration du WebSocket avec l'URL
    webSocket.begin("stream.aisstream.io", 443, "/v0/stream");
    
    webSocket.onEvent(webSocketEvent);
}

void loop() {
    webSocket.loop();
}

void webSocketEvent(WStype_t type, uint8_t* payload, size_t length) {
    switch(type) {
        case WStype_DISCONNECTED:
            Serial.println("Déconnecté !");
            // Essayez de se reconnecter
            webSocket.begin("stream.aisstream.io", 443, "/v0/stream");
            break;
        case WStype_CONNECTED:
            Serial.print("Connecté à : ");
            Serial.println((char*)payload);  // Affiche l'URL ou le message de connexion
            sendSubscriptionMessage();  // Envoi le message d'abonnement
            break;
        case WStype_TEXT:
            if (length > 0) {
                Serial.print("Texte reçu : ");
                Serial.println((char*)payload);  // Convertir le payload en chaîne de caractères
            } else {
                Serial.println("Aucun texte reçu.");
            }
            break;
        case WStype_ERROR:
            Serial.println("Erreur !");
            break;
    }
}

void sendSubscriptionMessage() {
    String subscriptionMessage = "{";
    subscriptionMessage += "\"APIKey\": \"" + String(apiKey) + "\",";
    subscriptionMessage += "\"BoundingBoxes\": " + String(bbox) + ",";
    subscriptionMessage += "}";

    webSocket.sendTXT(subscriptionMessage);  // Envoie le message sous forme de texte
    Serial.println("Message d'abonnement envoyé : ");
    Serial.println(subscriptionMessage);
}

Je ne reçois que le message "Déconnecté !"
Quelqu'un aurait-il des pistes pour m'aider à résoudre le problème ?

Merci !!

Veuillez utiliser la langue anglaise dans les sections anglaises du forum.

Votre sujet a été déplacé vers la section française du forum.

il nous faudrait la doc de l'API et éventuellement le code python qui était fonctionnel

La doc est ici:
https://aisstream.io/documentation

Et mon code est le suivant :

import json
import time
from datetime import datetime
import websockets
import asyncio
from django.db.models import CharField


class Bateau:
    nom = CharField(max_length=250, null=True)
    MMSI = CharField(max_length=250, null=False, default='')

    def __str__(self):
        return self.nom


def ajouter_bateau(message):
    nom = message['MetaData']['ShipName'].strip()
    MMSI = message['MetaData']['MMSI']
    if len(Bateau.objects.filter(MMSI=MMSI)) < 1:
        bateau = Bateau(nom=nom, MMSI=MMSI)
        bateau.save()
    else:
        bateau = Bateau.objects.get(MMSI=MMSI)
    return bateau


async def connect_ais_stream():
    async with websockets.connect("wss://stream.aisstream.io/v0/stream") as websocket:
        subscribe_message = {"APIKey": "xxxxxxxxxxxxx",
                             "BoundingBoxes": [[[47.304, -2.061], [47.28, -1.98]]]}
        subscribe_message_json = json.dumps(subscribe_message)
        await websocket.send(subscribe_message_json)

        async for message_json in websocket:
            message = json.loads(message_json)
            bateau = ajouter_bateau(message)
            heure = time.time()
            print(bateau, datetime.fromtimestamp(heure).strftime('%H:%M:%S'))


if __name__ == "__main__":
    asyncio.run(connect_ais_stream())

J'ai regardé rapidement mais je ne trouve pas pour le moment une bonne bibliothèque qui permet de faire une connexion TLS pour wss://stream.aisstream.io/v0/stream

Le serveur semble refuser effectivement la connexion même avec un ID correct.

Certains microcontrôleurs, comme l'ESP32, peuvent se programmer en micropython ou circuitpython, et la bibliothèque asyncio a été portée.

https://docs.micropython.org/en/latest/

https://docs.micropython.org/en/latest/library/asyncio.html#module-asyncio

https://docs.circuitpython.org/projects/asyncio/en/latest/

Il n’y a que très peu de bibliothèques sur micro python

Bonsoir vertocz

En désespoir de cause, as tu pensé à poser ta question à l'IA, je n'ai aucun moyen pour en tester la justesse, mais si ça peut aider, il y a des pistes à suivre :wink:

Une autre version de l'IA.

Cordialement
jpbbricole

json, time et asyncio sont portées.
Pour Websockets, il existe des solutions comme microdot (à confirmer que c'est similaire)
Pour CharField, je n'ai pas l'impression que ce soit important dans ce code, on doit pouvoir faire sans.

Avec micropython ou circuitPython, pas besoin de relier l'arduino à un ordinateur ?
Dans beaucoup de solutions que j'avais essayées, le code ne pouvait qu'être lu par un ordinateur. Or, j'aimerais que mon arduino ne soit branché à rien...

Oui j'avais commencé mes recherches comme ça, mais après quelques heures et des dizaines de tentatives, je n'ai trouvé aucune solution fonctionnelle...

Non c'est comme pour un code en C. L'Arduino est autonome. Mais attention, tous les microcontrôleurs ne sont pas capables d'exécuter un code python. Esp32 ou Esp8266 le sont. Il y en a peut-être d'autres.

l'IA est dans les choux sur ce genre de projets. Elle hallucine en se mélangeant les pinceaux sur les fonctions des bibliothèques arduino (WebSocketsClient) et des bibliothèques équivalents pour d'autres langages

C'est assez simple de tester, pour se créer une clé vous allez sur Sign Up/Authenticate, vous utilisez votre compte GitHub comme single sign on et ça vous emmène sur une page ou en un click vous créez votre clé pour l'API

ensuite avec wokwi vous pouvez utiliser un ESP32 virtuel connecté à internet avec ce code simple

#include <WiFi.h>

const char *ssid = "Wokwi-GUEST";
const char *motDePasseWifi = "";

void setup() {
  Serial.begin(115200);
  Serial.println("Connexion au réseau WiFi en cours");
  WiFi.begin(ssid, motDePasseWifi, 6); // canal 6 pour wokwi, pas forcéemnt utile ailleurs
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.write('.');
  }
  Serial.println("\nWiFi connecté");
}

void loop() {}

il faudrait creuser en utilisant des bibliothèques dispo pour faire des WebSockets mais il faut passer en SSL/TLS puisque leur serveur attend une requête sur le serveur wss://stream.aisstream.io/v0/stream de manière sécurisée et vous avez 3 secondes pour présenter l'authentification avec votre ID sous la forme d'un JSON

{
   "APIKey": <your api key>, // Required!
   "BoundingBoxes": [[[25.835302, -80.207729], [25.602700, -79.879297]], [[33.772292, -118.356139], [33.673490, -118.095731]] ], // Required!
   "FiltersShipMMSI": ["368207620", "367719770", "211476060"] // Optional!
   "FilterMessageTypes": ["PositionReport"] // Optional!
}

donc on met dans le code en dur par exemple

#define API_KEY "xxx" // celle que vous avez obtenue sur le site
const char *jsonSubscription = "{\"APIKey\":\"" API_KEY "\",\"BoundingBoxes\":[[[47.304, -2.061], [47.28, -1.98]]]}";

et on n'a plus qu'à envoyer le payload jsonSubscription une fois que la socket est connectée.

il existe plusieurs bibliothèques comme

ou

qu'il faudrait explorer. Elles ne sont pas très documentées sur la gestion de SSL/TLS même si elles proposent un exemple et la doc de aisstream est aussi assez limitée...

bref faudrait y passer un peu de temps.