Ich habe dazu folgendes ESP32 Modul benutzt: ESP32-D0WD-V3 (revision v3.1) / diymore ESP32 NodeMCU ESP32 WROOM 32D - development board CH340.
Zusätzlich benötigt ihr nur noch die MAC Adresse eurer Enterprise, z.B. herauszufinden über Wireshark (ggf. auch über BLE Scanner App?), und den Code unten für den ESP32. Danach in Loxone http-get Befehle triggern, z.B. mit http://192.168.1.XXX/M1 (XXX=vergebene lokale IP, herausfinden am Router!).
Ich habe die BLE-Befehle der iPhone App an die Enterprise über iPhone Bluetooth Logging in Erfahrung gebracht (nach Aktivierung des Loggings die App benutzt und die Befehle der Reihe nach ausgeführt), und zwar so wie hier beschrieben per Wireshark und dem Filter: bluetooth.dst == ac:XX:XX:26:c5:22. Hier muss man die passende MAC Adresse für euere Enterprise in Wireshark herausfinden (suche nach: "TexasInstrum_26:c5:22", oder nach Timestamp die entsprechenden Befehle im BT Protokoll wiederfinden) um übersichtlich alle Befehle (=Values) an die Enterprise gelistet zu bekommen. Man bekommt so die einzelnen Befehle heraus um die entsprechenden Aktionen zu triggern. Das habe ich bereits gemacht und findet sich unter im Code im byte-Array PmUSSECMDs wieder!
Schnell konnte ich so (geht auch über BLE scanner Apps am Smartphone) den entsprechenden BLE Service UUID und die Charcteristic UUID herausfinden:
[Destination Device Name: Pm_USSE_6C522] ← hierunter ist die Enterprise in BLE Scanner Apps schnell zu finden.
[Service UUID: bc2f4cc6aaef43519034d66268e328f0]
[UUID: 06d1e5e779ad4a718faa373789f7d93c]
über eine iPhone App wie z.B. "BLE Scanner" (dort: connect to "Pm_USSE_6C522" → Custom Service → Custom Characteristic → click "W" symbol → Hex → e.g.: aa0701ffff) oder aber am Mac über eine App wie "LightBlue" (dort: connect to "Pm_USSE_6C522" → USSE Command (="Characteristic user description") → "Write new value") kann man die Befehle (=Values) auch vorher mal testen.
Der nächste Schritt war die Verbindung zur Enterprise analog zu meinem Vorgehen hier: link, d.h. unter Nutzung der "BLEDevice.h"-Library. (siehe code anbei)
Außerdem läuft dann auf dem ESP32 ein Server über die Bibliotheken: "WiFi.h" / "WiFiClient.h" / "HTTPClient.h", sodass das Modul die passenden BLE Befehle auf http-get Befehl hin sendet...
Anwendungsfälle:
- Kopplung des "Roter Alarm"-Sounds an die Alarm-Anlage
- Lichter der Enterprise an BWM Koppeln...
Viel Spaß damit!
// Playmobile USS Enterprise #include <WiFi.h> //Wifi support #include <WiFiClient.h> //Wifi support #include <HTTPClient.h> //Wifi server support #include "BLEDevice.h" //BLE support //On-chip LED GPIO (depends on used ESP32 board) int LED_BUILTIN = 2; //Wifi SSID and password const char* ssid = "YourSSID"; const char* password = "YourPW"; unsigned long previousMillis = 0; unsigned long timeoutTime = 30000; //timeout for Wifi-Connection unsigned long previousMillisS = 0; const long timeoutTimeS = 1000; // Define timeout for Server connection WiFiServer server(80); //BLE UUIDs: The pattern is 8-4-4-4-12 #define EnterpriseBLEAddress "ac:XX:XX:26:c5:22" // The remote service we wish to connect to: Pm_USSE_6C522 (Playmobil USS Enterprise) static BLEUUID serviceUUID("bc2f4cc6-aaef-4351-9034-d66268e328f0"); // The characteristic of the remote service we are interested in: "USSE Command" static BLEUUID charUUID("06d1e5e7-79ad-4a71-8faa-373789f7d93c"); static BLERemoteCharacteristic* pRemoteCharacteristic; //variable holding connection status //BLEClient* pClient; bool BLEConnectionStatus; //define commands ("Values") sniffed from Playmobil Enterprise iPhone APP static byte PmUSSECMDs[19][5] = { {0xaa, 0x07, 0x01, 0xff, 0xff}, // CMD 1 / Warp: aa0701ffff {0xaa, 0x07, 0x02, 0x00, 0xff}, // CMD 2 / Alarm: aa070200ff {0xaa, 0x07, 0x03, 0x00, 0xff}, // CMD 3 / Torpedo: aa070300ff {0xaa, 0x08, 0x07, 0xc8, 0xff}, // CMD 4 / sound Alarm: aa0807c8ff {0xaa, 0x08, 0x05, 0xc8, 0xff}, // CMD 5 / sound Torpedo: aa0805c8ff {0xaa, 0x08, 0x02, 0xc8, 0xff}, // CMD 6 / sound Pfeife: aa0802c8ff {0xaa, 0x08, 0x08, 0xc8, 0xff}, // CMD 7 / sound Live long and Prosper: aa0808c8ff {0xaa, 0x08, 0x06, 0xc8, 0xff}, // CMD 8 / sound Scotty James to Enterprise: aa0806c8ff {0xaa, 0x08, 0x0b, 0xbe, 0xff}, // CMD 9 / sound Brücken-Ambiente: aa080bbeff {0xaa, 0x08, 0x01, 0xbe, 0xff}, // CMD 10 / sound Dematerialisieren: aa0801beff {0xaa, 0x04, 0x07, 0xc8, 0xff}, // CMD 11 / lights: Warp Gondeln: aa0407c8ff {0xaa, 0x05, 0x07, 0xc8, 0xff}, // CMD 12 / lights: Go to Warp: aa0507c8ff {0xaa, 0x04, 0x03, 0xc8, 0xff}, // CMD 13 / lights: Torpedo: aa0403c8ff {0xaa, 0x05, 0x01, 0xc8, 0xff}, // CMD 14 / lights: Torpedo Twice: aa0501c8ff {0xaa, 0x03, 0xff, 0x00, 0xff}, // CMD 15 / Vol 100: aa03ff00ff {0xaa, 0x03, 0x83, 0x00, 0xff}, // CMD 16 / Vol 50: aa038300ff {0xaa, 0x03, 0x80, 0x00, 0xff}, // CMD 17 / Vol 30: aa038000ff {0xaa, 0x03, 0x00, 0x00, 0xff}, // CMD 18 / Vol 0: aa030000ff {0xaa, 0x07, 0x04, 0x00, 0xff} // CMD 19 / Alles AUS: aa070400ff }; WiFiClient espClient; // Standard Arduino function which is called once when the device first starts up void setup() { // Setup for Serial Monitor (when connected to Arduino IDE: Tools -> Serial Monitor) Serial.begin(9600); while(!Serial) { delay(10); } // Initialize digital pin LED_BUILTIN as an output. pinMode(LED_BUILTIN, OUTPUT); //connect to Pm_USSE_6C522 (Playmobil USS Enterprise) BLEDevice::init(""); BLEClient* pClient = BLEDevice::createClient(); Serial.println("\nTrying to connect to Pm_USSE_6C522"); //BLE address of Pm_USSE_6C522 (Playmobil USS Enterprise) if (pClient->connect(BLEAddress(EnterpriseBLEAddress))) { Serial.println("Connected!"); BlinkLED();BlinkLED(); Serial.println("\nTrying to connect to BLE-Service"); BLERemoteService* pRemoteService = pClient->getService(serviceUUID); if (pRemoteService == nullptr) { Serial.println("Failed to get service"); return; } else Serial.println("Got service"); Serial.println("\nTrying to connect to BLE-Characteristic of Service"); pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); if (pRemoteCharacteristic == nullptr) { Serial.println("Failed to get characteristic"); return; } else Serial.println("Got characteristic"); } else Serial.println("Failed to connect"); Serial.println("\nPrint Status:"); BLEConnectionStatus = pClient->isConnected(); Serial.println(BLEConnectionStatus); // Connect to WiFi Serial.println("\nConnecting to WiFi"); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while(WiFi.status() != WL_CONNECTED){ Serial.print("."); delay(500); } Serial.print("\nConnected to the WiFi network: "); Serial.print(String(ssid)); Serial.print(" | local ESP32 IP: "); Serial.print(WiFi.localIP()); Serial.print(" | RSSI: "); Serial.println(WiFi.RSSI()); //start server to allow control via http commands server.begin(); // Blink LED on Chip once on Startup BlinkLED();BlinkLED();BlinkLED(); } // Blink LED on Chip void BlinkLED() { digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level) delay(100); // LED on for 100msec digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW delay(100); // wait / off for 100msec } // Standard Arduino function that is called in an endless loop after setup void loop() { unsigned long currentMillis = millis(); //works for ca. 50 days before reset to 0 unsigned long currentMillisS = millis(); //works for ca. 50 days before reset to 0 // if WiFi is down, try reconnecting every timeoutTime seconds if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >= timeoutTime)) { Serial.print(millis()); Serial.println("Reconnecting to WiFi..."); WiFi.disconnect(); WiFi.reconnect(); Serial.print("\nConnected to the WiFi network: "); Serial.print(String(ssid)); Serial.print(" | local ESP32 IP: "); Serial.print(WiFi.localIP()); Serial.print(" | RSSI: "); Serial.println(WiFi.RSSI()); previousMillis = currentMillis; } if (currentMillis - previousMillis < 0) { previousMillis = currentMillis; } //get restart command from external http command to server WiFiClient client = server.available(); if (client) { currentMillisS = millis(); previousMillisS = currentMillisS; Serial.println("New Client"); String currentLine = ""; while (client.connected() && (currentMillisS - previousMillisS <= timeoutTimeS)) { currentMillisS = millis(); if (client.available()) { char c = client.read(); Serial.write(c); if (c == '\n') { if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); //client.println("Connection: close"); client.println(); //create the buttons client.print("Effekte: <a href=\"/M1\">Warp</a><br>"); client.print("Effekte: <a href=\"/M2\">Alarm</a><br>"); client.print("Effekte: <a href=\"/M3\">Torpedo</a><br><br>"); client.print("Sound: <a href=\"/M4\">Alarm</a><br>"); client.print("Sound: <a href=\"/M5\">Torpedo</a><br>"); client.print("Sound: <a href=\"/M6\">Pfeife</a><br>"); client.print("Sound: <a href=\"/M7\">Live Long and Prosper</a><br>"); client.print("Sound: <a href=\"/M8\">Scotty James to Enterprise</a><br>"); client.print("Sound: <a href=\"/M9\">Brückenambiente</a><br>"); client.print("Sound: <a href=\"/M10\">Dematerialisieren</a><br><br>"); client.print("Lights: <a href=\"/M11\">Warp Gondeln</a><br>"); client.print("Lights: <a href=\"/M12\">Go to Warp</a><br>"); client.print("Lights: <a href=\"/M13\">Torpedo Full</a><br>"); client.print("Lights: <a href=\"/M14\">Torpedo Twice</a><br><br>"); client.print("Volume: <a href=\"/v1\">100%</a><br>"); client.print("Volume: <a href=\"/v2\">50%</a><br>"); client.print("Volume: <a href=\"/v3\">30%</a><br>"); client.print("Volume: <a href=\"/v4\">0%</a><br><br>"); client.print("Enterprise: <a href=\"/x\">AUS</a><br><br>"); client.print("ESP32 Modul: <a href=\"/T\">Blink!</a><br><br>"); // The HTTP response ends with another blank line: client.println(); // break out of the while loop: break; } else { currentLine = ""; } } else if (c != '\r') { currentLine += c; } // Execute commands if (currentLine.endsWith("GET /T")) { Serial.println(" command received to Blink ESP32 Module"); BlinkLED();BlinkLED();BlinkLED(); } if (currentLine.endsWith("GET /R")) { Serial.println(" command received to restart ESP32 Module"); BlinkLED();BlinkLED();BlinkLED(); ESP.restart(); } if (currentLine.endsWith("GET /M1")) { Serial.println(" command received to send BLE-command 1 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[0],sizeof(PmUSSECMDs[0])); } if (currentLine.endsWith("GET /M2")) { Serial.println(" command received to send BLE-command 2 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[1],sizeof(PmUSSECMDs[1])); } if (currentLine.endsWith("GET /M3")) { Serial.println(" command received to send BLE-command 3 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[2],sizeof(PmUSSECMDs[2])); } if (currentLine.endsWith("GET /M4")) { Serial.println(" command received to send BLE-command 4 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[3],sizeof(PmUSSECMDs[3])); } if (currentLine.endsWith("GET /M5")) { Serial.println(" command received to send BLE-command 5 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[4],sizeof(PmUSSECMDs[4])); } if (currentLine.endsWith("GET /M6")) { Serial.println(" command received to send BLE-command 6 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[5],sizeof(PmUSSECMDs[5])); } if (currentLine.endsWith("GET /M7")) { Serial.println(" command received to send BLE-command 7 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[6],sizeof(PmUSSECMDs[6])); } if (currentLine.endsWith("GET /M8")) { Serial.println(" command received to send BLE-command 8 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[7],sizeof(PmUSSECMDs[7])); } if (currentLine.endsWith("GET /M9")) { Serial.println(" command received to send BLE-command 9 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[8],sizeof(PmUSSECMDs[8])); } if (currentLine.endsWith("GET /M10")) { Serial.println(" command received to send BLE-command 10 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[9],sizeof(PmUSSECMDs[9])); } if (currentLine.endsWith("GET /M11")) { Serial.println(" command received to send BLE-command 11 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[10],sizeof(PmUSSECMDs[10])); } if (currentLine.endsWith("GET /M12")) { Serial.println(" command received to send BLE-command 12 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[11],sizeof(PmUSSECMDs[11])); } if (currentLine.endsWith("GET /M13")) { Serial.println(" command received to send BLE-command 13 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[12],sizeof(PmUSSECMDs[12])); } if (currentLine.endsWith("GET /M14")) { Serial.println(" command received to send BLE-command 14 to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[13],sizeof(PmUSSECMDs[13])); } if (currentLine.endsWith("GET /v1")) { Serial.println(" command received to send BLE-command 15 = v1 = Vol 100% to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[14],sizeof(PmUSSECMDs[14])); } if (currentLine.endsWith("GET /v2")) { Serial.println(" command received to send BLE-command 16 = v2 = Vol 50% to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[15],sizeof(PmUSSECMDs[15])); } if (currentLine.endsWith("GET /v3")) { Serial.println(" command received to send BLE-command 17 = v3 = Vol 30% to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[16],sizeof(PmUSSECMDs[16])); } if (currentLine.endsWith("GET /v4")) { Serial.println(" command received to send BLE-command 18 = v4 = Vol 0% to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[17],sizeof(PmUSSECMDs[17])); } if (currentLine.endsWith("GET /x")) { Serial.println(" command received to send BLE-command 19 = x = AUS to Enterprise"); BlinkLED(); pRemoteCharacteristic->writeValue(PmUSSECMDs[18],sizeof(PmUSSECMDs[18])); } } } client.stop(); Serial.println("Client disconnected"); } }
Kommentar