Ver código fonte

Merge pull request #85 from sidoh/48899_discovery

Add support for 48899 discovery
Chris Mullins 8 anos atrás
pai
commit
e27c3c6e6c

+ 5 - 3
data/web/index.html

@@ -124,8 +124,8 @@
   <script lang="text/javascript">
     var FORM_SETTINGS = [
       "admin_username", "admin_password", "ce_pin", "csn_pin", "reset_pin","packet_repeats",
-      "http_repeat_factor", "auto_restart_period", "mqtt_server", "mqtt_topic_pattern",
-      "mqtt_username", "mqtt_password", "radio_interface_type"
+      "http_repeat_factor", "auto_restart_period", "discovery_port", "mqtt_server", 
+      "mqtt_topic_pattern", "mqtt_username", "mqtt_password", "radio_interface_type"
     ];
 
     var FORM_SETTINGS_HELP = {
@@ -141,7 +141,9 @@
       mqtt_server : "Domain or IP address of MQTT broker. Optionally specify a port " +
         "with (example) mymqqtbroker.com:1884.",
       mqtt_topic_pattern : "Pattern for MQTT topics to listen on. Example: " +
-        "lights/:device_id/:type/:group. See README for further details."
+        "lights/:device_id/:type/:group. See README for further details.",
+      discovery_port : "UDP port to listen for discovery packets on. Defaults to " +
+        "the same port used by MiLight devices, 48899. Use 0 to disable."
     }
 
     var UDP_PROTOCOL_VERSIONS = [ 5, 6 ];

+ 2 - 0
lib/Settings/Settings.cpp

@@ -76,6 +76,7 @@ void Settings::patch(JsonObject& parsedSettings) {
     this->setIfPresent(parsedSettings, "mqtt_username", mqttUsername);
     this->setIfPresent(parsedSettings, "mqtt_password", mqttPassword);
     this->setIfPresent(parsedSettings, "mqtt_topic_pattern", mqttTopicPattern);
+    this->setIfPresent(parsedSettings, "discovery_port", discoveryPort);
 
     if (parsedSettings.containsKey("radio_interface_type")) {
       this->radioInterfaceType = Settings::typeFromString(parsedSettings["radio_interface_type"]);
@@ -139,6 +140,7 @@ void Settings::serialize(Stream& stream, const bool prettyPrint) {
   root["mqtt_username"] = this->mqttUsername;
   root["mqtt_password"] = this->mqttPassword;
   root["mqtt_topic_pattern"] = this->mqttTopicPattern;
+  root["discovery_port"] = this->discoveryPort;
 
   if (this->deviceIds) {
     JsonArray& arr = jsonBuffer.createArray();

+ 3 - 1
lib/Settings/Settings.h

@@ -62,7 +62,8 @@ public:
     numGatewayConfigs(0),
     packetRepeats(10),
     httpRepeatFactor(5),
-    _autoRestartPeriod(0)
+    _autoRestartPeriod(0),
+    discoveryPort(48899)
   { }
 
   ~Settings() {
@@ -106,6 +107,7 @@ public:
   String mqttUsername;
   String mqttPassword;
   String mqttTopicPattern;
+  uint16_t discoveryPort;
 
 protected:
   size_t _autoRestartPeriod;

+ 85 - 0
lib/Udp/MiLightDiscoveryServer.cpp

@@ -0,0 +1,85 @@
+#include <MiLightDiscoveryServer.h>
+#include <Size.h>
+#include <ESP8266WiFi.h>
+
+const char V3_SEARCH_STRING[] = "Link_Wi-Fi";
+const char V6_SEARCH_STRING[] = "HF-A11ASSISTHREAD";
+
+MiLightDiscoveryServer::MiLightDiscoveryServer(Settings& settings)
+  : settings(settings)
+{ }
+
+MiLightDiscoveryServer::MiLightDiscoveryServer(MiLightDiscoveryServer& other)
+  : settings(other.settings)
+{ }
+
+MiLightDiscoveryServer& MiLightDiscoveryServer::operator=(MiLightDiscoveryServer other) {
+  this->settings = other.settings;
+  this->socket = other.socket;
+}
+
+MiLightDiscoveryServer::~MiLightDiscoveryServer() {
+  socket.stop();
+}
+
+void MiLightDiscoveryServer::begin() {
+  socket.begin(settings.discoveryPort);
+}
+
+void MiLightDiscoveryServer::handleClient() {
+  size_t packetSize = socket.parsePacket();
+
+  if (packetSize) {
+    char buffer[size(V6_SEARCH_STRING) + 1];
+    socket.read(buffer, packetSize);
+    buffer[packetSize] = 0;
+
+#ifdef MILIGHT_UDP_DEBUG
+    printf("Got discovery packet: %s\n", buffer);
+#endif
+
+    if (strcmp(buffer, V3_SEARCH_STRING) == 0) {
+      handleDiscovery(5);
+    } else if (strcmp(buffer, V6_SEARCH_STRING) == 0) {
+      handleDiscovery(6);
+    }
+  }
+}
+
+void MiLightDiscoveryServer::handleDiscovery(uint8_t version) {
+#ifdef MILIGHT_UDP_DEBUG
+  printf("Handling discovery for version: %u, %d configs to consider\n", version, settings.numGatewayConfigs);
+#endif
+
+  char buffer[40];
+
+  for (size_t i = 0; i < settings.numGatewayConfigs; i++) {
+    GatewayConfig* config = settings.gatewayConfigs[i];
+
+    if (config->protocolVersion != version) {
+      continue;
+    }
+
+    IPAddress addr = WiFi.localIP();
+    char* ptr = buffer;
+    ptr += sprintf_P(
+      buffer,
+      PSTR("%d.%d.%d.%d,00000000%02X%02X"),
+      addr[0], addr[1], addr[2], addr[3],
+      (config->deviceId >> 8), (config->deviceId & 0xFF)
+    );
+
+    if (config->protocolVersion == 5) {
+      sendResponse(buffer);
+    } else {
+      sprintf_P(ptr, PSTR(",HF-LPB100"));
+      sendResponse(buffer);
+    }
+  }
+}
+
+void MiLightDiscoveryServer::sendResponse(char* buffer) {
+  socket.beginPacket(socket.remoteIP(), socket.remotePort());
+  socket.write(buffer);
+  socket.endPacket();
+}

+ 25 - 0
lib/Udp/MiLightDiscoveryServer.h

@@ -0,0 +1,25 @@
+#include <WiFiUdp.h>
+#include <Settings.h>
+
+#ifndef MILIGHT_DISCOVERY_SERVER_H
+#define MILIGHT_DISCOVERY_SERVER_H
+
+class MiLightDiscoveryServer {
+public:
+  MiLightDiscoveryServer(Settings& settings);
+  MiLightDiscoveryServer(MiLightDiscoveryServer&);
+  MiLightDiscoveryServer& operator=(MiLightDiscoveryServer other);
+  ~MiLightDiscoveryServer();
+
+  void begin();
+  void handleClient();
+
+private:
+  Settings& settings;
+  WiFiUDP socket;
+
+  void handleDiscovery(uint8_t version);
+  void sendResponse(char* buffer);
+};
+
+#endif

+ 6 - 6
lib/Udp/MiLightUdpServer.cpp

@@ -4,7 +4,7 @@
 #include <ESP8266WiFi.h>
 
 MiLightUdpServer::MiLightUdpServer(MiLightClient*& client, uint16_t port, uint16_t deviceId)
-  : client(client), 
+  : client(client),
     port(port),
     deviceId(deviceId),
     lastGroup(0)
@@ -24,10 +24,10 @@ void MiLightUdpServer::stop() {
 
 void MiLightUdpServer::handleClient() {
   const size_t packetSize = socket.parsePacket();
-  
+
   if (packetSize) {
     socket.read(packetBuffer, packetSize);
-    
+
 #ifdef MILIGHT_UDP_DEBUG
     printf("[MiLightUdpServer port %d] - Handling packet: ", port);
     for (size_t i = 0; i < packetSize; i++) {
@@ -35,7 +35,7 @@ void MiLightUdpServer::handleClient() {
     }
     printf("\n");
 #endif
-    
+
     handlePacket(packetBuffer, packetSize);
   }
 }
@@ -46,6 +46,6 @@ MiLightUdpServer* MiLightUdpServer::fromVersion(uint8_t version, MiLightClient*&
   } else if (version == 6) {
     return new V6MiLightUdpServer(client, port, deviceId);
   }
-  
+
   return NULL;
-}
+}

+ 1 - 1
platformio.ini

@@ -18,7 +18,7 @@ lib_deps_external =
   ArduinoJson
   PubSubClient
   https://github.com/ratkins/RGBConverter
-build_flags = !python .get_version.py
+build_flags = !python .get_version.py -D MILIGHT_UDP_DEBUG 
 # -D MQTT_DEBUG
 # -D MILIGHT_UDP_DEBUG
 # -D DEBUG_PRINTF

+ 19 - 4
src/main.cpp

@@ -15,15 +15,17 @@
 #include <ESP8266SSDP.h>
 #include <MqttClient.h>
 #include <RGBConverter.h>
+#include <MiLightDiscoveryServer.h>
 
 WiFiManager wifiManager;
 
 Settings settings;
 
-MiLightClient* milightClient;
-MiLightRadioFactory* radioFactory;
-MiLightHttpServer *httpServer;
-MqttClient* mqttClient;
+MiLightClient* milightClient = NULL;
+MiLightRadioFactory* radioFactory = NULL;
+MiLightHttpServer *httpServer = NULL;
+MqttClient* mqttClient = NULL;
+MiLightDiscoveryServer* discoveryServer = NULL;
 
 int numUdpServers = 0;
 MiLightUdpServer** udpServers;
@@ -88,6 +90,15 @@ void applySettings() {
   }
 
   initMilightUdpServers();
+
+  if (discoveryServer) {
+    delete discoveryServer;
+    discoveryServer = NULL;
+  }
+  if (settings.discoveryPort != 0) {
+    discoveryServer = new MiLightDiscoveryServer(settings);
+    discoveryServer->begin();
+  }
 }
 
 bool shouldRestart() {
@@ -138,6 +149,10 @@ void loop() {
     }
   }
 
+  if (discoveryServer) {
+    discoveryServer->handleClient();
+  }
+
   if (shouldRestart()) {
     Serial.println(F("Auto-restart triggered. Restarting..."));
     ESP.restart();