Kaynağa Gözat

Merge pull request #28 from sidoh/discovery

Discovery
Chris Mullins 8 yıl önce
ebeveyn
işleme
e7a04a1dbd

+ 1 - 1
data/web/index.html

@@ -133,7 +133,7 @@
   
     var activeUrl = function() {
       var deviceId = $('#deviceId option:selected').val()
-        , groupId = $('#groupId input:checked').data('value')
+        , groupId = $('#groupId .active input').data('value')
         , mode = getCurrentMode();
         
       if (deviceId == "") {

+ 6 - 0
lib/Helpers/Size.h

@@ -0,0 +1,6 @@
+#include <Arduino.h>
+
+template<typename T, size_t sz>
+size_t size(T(&)[sz]) {
+    return sz;
+}

+ 2 - 0
lib/MiLight/CctPacketFormatter.cpp

@@ -91,6 +91,8 @@ uint8_t CctPacketFormatter::getCctStatusButton(uint8_t groupId, MiLightStatus st
     }
   }
   
+  printf("Group id = %d\n", groupId);
+  
   return button;
 }
 

+ 17 - 0
lib/MiLight/CctPacketFormatter.h

@@ -6,6 +6,23 @@
 #define CCT_COMMAND_INDEX 4
 #define CCT_INTERVALS 10
 
+enum MiLightCctButton {
+  CCT_ALL_ON            = 0x05,
+  CCT_ALL_OFF           = 0x09,
+  CCT_GROUP_1_ON        = 0x08,
+  CCT_GROUP_1_OFF       = 0x0B,
+  CCT_GROUP_2_ON        = 0x0D,
+  CCT_GROUP_2_OFF       = 0x03,
+  CCT_GROUP_3_ON        = 0x07,
+  CCT_GROUP_3_OFF       = 0x0A,
+  CCT_GROUP_4_ON        = 0x02,
+  CCT_GROUP_4_OFF       = 0x06,
+  CCT_BRIGHTNESS_DOWN   = 0x04,
+  CCT_BRIGHTNESS_UP     = 0x0C,
+  CCT_TEMPERATURE_UP    = 0x0E,
+  CCT_TEMPERATURE_DOWN  = 0x0F
+};
+
 class CctPacketFormatter : public PacketFormatter {
 public:
   CctPacketFormatter()

+ 1 - 18
lib/MiLight/MiLightButtons.h

@@ -3,7 +3,7 @@
 
 enum MiLightRadioType {
   UNKNOWN = 0,
-  RGBW  = 0xB8,
+  RGBW  = 0xB0,
   CCT   = 0x5A,
   RGB_CCT = 0x20,
   RGB = 0xA4
@@ -14,21 +14,4 @@ enum MiLightStatus {
   OFF = 1 
 };
 
-enum MiLightCctButton {
-  CCT_ALL_ON            = 0x05,
-  CCT_ALL_OFF           = 0x09,
-  CCT_GROUP_1_ON        = 0x08,
-  CCT_GROUP_1_OFF       = 0x0B,
-  CCT_GROUP_2_ON        = 0x0D,
-  CCT_GROUP_2_OFF       = 0x03,
-  CCT_GROUP_3_ON        = 0x07,
-  CCT_GROUP_3_OFF       = 0x0A,
-  CCT_GROUP_4_ON        = 0x02,
-  CCT_GROUP_4_OFF       = 0x06,
-  CCT_BRIGHTNESS_DOWN   = 0x04,
-  CCT_BRIGHTNESS_UP     = 0x0C,
-  CCT_TEMPERATURE_UP    = 0x0E,
-  CCT_TEMPERATURE_DOWN  = 0x0F
-};
-
 #endif

+ 5 - 0
lib/MiLight/RgbwPacketFormatter.cpp

@@ -30,6 +30,11 @@ void RgbwPacketFormatter::nextMode() {
   command(RGBW_DISCO_MODE, 0);
 }
 
+void RgbwPacketFormatter::updateMode(uint8_t mode) {
+  command(RGBW_DISCO_MODE, 0);
+  currentPacket[0] = RGBW | mode;
+}
+
 void RgbwPacketFormatter::updateStatus(MiLightStatus status, uint8_t groupId) {
   uint8_t button = RGBW_GROUP_1_ON + ((groupId - 1)*2) + status;
   command(button, 0);

+ 1 - 0
lib/MiLight/RgbwPacketFormatter.h

@@ -55,6 +55,7 @@ public:
   virtual void modeSpeedDown();
   virtual void modeSpeedUp();
   virtual void nextMode();
+  virtual void updateMode(uint8_t mode);
   
   virtual void initializePacket(uint8_t* packet);
 };

+ 1 - 1
lib/Udp/MiLightUdpServer.cpp

@@ -29,7 +29,7 @@ void MiLightUdpServer::handleClient() {
     socket.read(packetBuffer, packetSize);
     
 #ifdef MILIGHT_UDP_DEBUG
-    printf("Handling packet: ");
+    printf("[MiLightUdpServer port %d] - Handling packet: ", port);
     for (size_t i = 0; i < packetSize; i++) {
       printf("%02X ", packetBuffer[i]);
     }

+ 49 - 0
lib/Udp/V6CctCommandHandler.cpp

@@ -0,0 +1,49 @@
+#include <V6CctCommandHandler.h>
+
+bool V6CctCommandHandler::handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg)
+{
+  const uint8_t cmd = command & 0xFF;
+  const uint8_t arg = commandArg >> 24;
+  
+  client->prepare(MilightCctConfig, deviceId, group);
+  
+  if (cmd == V2_CCT_COMMAND_PREFIX) {
+    switch (arg) {
+      case V2_CCT_ON:
+        client->updateStatus(ON);
+        break;
+        
+      case V2_CCT_OFF:
+        client->updateStatus(OFF);
+        break;
+        
+      case V2_CCT_BRIGHTNESS_DOWN:
+        client->decreaseBrightness();
+        break;
+        
+      case V2_CCT_BRIGHTNESS_UP:
+        client->increaseBrightness();
+        break;
+        
+      case V2_CCT_TEMPERATURE_DOWN:
+        client->decreaseTemperature();
+        break;
+        
+      case V2_CCT_TEMPERATURE_UP:
+        client->increaseTemperature();
+        break;
+        
+      default:
+        return false;
+    }
+    
+    return true;
+  }
+  
+  return false;
+}

+ 34 - 0
lib/Udp/V6CctCommandHandler.h

@@ -0,0 +1,34 @@
+#include <V6CommandHandler.h>
+
+#ifndef _V6_CCT_COMMAND_HANDLER_H
+#define _V6_CCT_COMMAND_HANDLER_H 
+
+enum CctCommandIds {
+  V2_CCT_COMMAND_PREFIX   = 0x01,
+  
+  V2_CCT_BRIGHTNESS_UP    = 0x01,
+  V2_CCT_BRIGHTNESS_DOWN  = 0x02,
+  V2_CCT_TEMPERATURE_UP   = 0x03,
+  V2_CCT_TEMPERATURE_DOWN = 0x04,
+  V2_CCT_NIGHT_LIGHT      = 0x06,
+  V2_CCT_ON               = 0x07,
+  V2_CCT_OFF              = 0x08
+};
+
+class V6CctCommandHandler : public V6CommandHandler {
+public:
+  V6CctCommandHandler(uint16_t commandId)
+    : V6CommandHandler(commandId)
+  { }
+  
+  virtual bool handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg
+  );
+  
+};
+
+#endif

+ 31 - 0
lib/Udp/V6ComamndHandler.cpp

@@ -0,0 +1,31 @@
+#include <V6CommandHandler.h>
+#include <V6RgbCctCommandHandler.h>
+#include <V6RgbwCommandHandler.h>
+#include <V6RgbCommandHandler.h>
+#include <V6CctCommandHandler.h>
+#include <Size.h>
+
+V6CommandHandler* V6CommandHandler::ALL_HANDLERS[] = {
+  new V6RgbCctCommandHandler(0x0800),
+  new V6RgbwCommandHandler(0x0700),
+  new V6RgbCommandHandler(0x0500),
+  new V6CctCommandHandler(0x0100),
+};
+
+const size_t V6CommandHandler::NUM_HANDLERS = size(ALL_HANDLERS);
+
+bool V6CommandDemuxer::handleCommand(MiLightClient* client, 
+  uint16_t deviceId,
+  uint8_t group,
+  uint32_t command,
+  uint32_t commandArg)
+{
+  for (size_t i = 0; i < numHandlers; i++) {
+    if (((handlers[i]->commandId & command) == handlers[i]->commandId)
+      && handlers[i]->handleCommand(client, deviceId, group, command, commandArg)) {
+      return true;
+    }
+  }
+  
+  return false;
+}

+ 47 - 0
lib/Udp/V6CommandHandler.h

@@ -0,0 +1,47 @@
+#include <MiLightClient.h>
+
+#ifndef _V6_COMMAND_HANDLER_H
+#define _V6_COMMAND_HANDLER_H 
+
+class V6CommandHandler {
+public:
+  static V6CommandHandler* ALL_HANDLERS[];
+  static const size_t NUM_HANDLERS;
+  
+  V6CommandHandler(uint16_t commandId)
+    : commandId(commandId)
+  { }
+  
+  virtual bool handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg
+  ) = 0;
+  
+  const uint16_t commandId;
+};
+
+class V6CommandDemuxer : public V6CommandHandler {
+public:
+  V6CommandDemuxer(V6CommandHandler* handlers[], size_t numHandlers)
+    : V6CommandHandler(0),  
+      handlers(handlers),
+      numHandlers(numHandlers)
+  { }
+  
+  virtual bool handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg
+  );
+  
+protected:
+  V6CommandHandler** handlers;
+  size_t numHandlers;
+};
+
+#endif

+ 91 - 95
lib/Udp/V6MiLightUdpServer.cpp

@@ -1,6 +1,17 @@
 #include <V6MiLightUdpServer.h>
 #include <ESP8266WiFi.h>
 #include <Arduino.h>
+#include <Size.h>
+#include <V6CommandHandler.h>
+
+#define MATCHES_PACKET(packet1) ( \
+  matchesPacket(packet1, size(packet1), packet, packetSize) \
+)
+
+V6CommandDemuxer* V6MiLightUdpServer::COMMAND_DEMUXER = new V6CommandDemuxer(
+  V6CommandHandler::ALL_HANDLERS,
+  V6CommandHandler::NUM_HANDLERS
+);
   
 uint8_t V6MiLightUdpServer::START_SESSION_COMMAND[] = {
   0x20, 0x00, 0x00, 0x00, 0x16, 0x02, 0x62, 0x3A, 0xD5, 0xED, 0xA3, 0x01, 0xAE, 
@@ -23,14 +34,45 @@ uint8_t V6MiLightUdpServer::HEARTBEAT_HEADER[] = {
   0xD0, 0x00, 0x00, 0x00, 0x02
 };
 
+uint8_t V6MiLightUdpServer::HEARTBEAT_HEADER2[] = {
+  0x30, 0x00, 0x00, 0x00, 0x03
+};
+
 uint8_t V6MiLightUdpServer::COMMAND_RESPONSE[] = {
   0x88, 0x00, 0x00, 0x00, 0x03, 0x00, 0xFF, 0x00
 };
 
-template<typename T, size_t sz>
-size_t size(T(&)[sz]) {
-    return sz;
-}
+uint8_t V6MiLightUdpServer::SEARCH_COMMAND[] = {
+  0x10, 0x00, 0x00, 0x00
+  //, 0x24, 0x02
+  //, 0xAE, 0x65, 0x02, 0x39, 0x38, 0x35, 0x62
+};
+
+uint8_t V6MiLightUdpServer::SEARCH_RESPONSE[] = {
+  0x18, 0x00, 0x00, 0x00, 0x40, 0x02, 
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // mac address
+  0x00, 0x20, 0x39, 0x38, 0x35, 0x62, 
+  0x31, 0x35, 0x37, 0x62, 0x66, 0x36, 
+  0x66, 0x63, 0x34, 0x33, 0x33, 0x36, 
+  0x38, 0x61, 0x36, 0x33, 0x34, 0x36, 
+  0x37, 0x65, 0x61, 0x33, 0x62, 0x31, 
+  0x39, 0x64, 0x30, 0x64, 0x01, 0x00, 
+  0x01, 
+  0x17, 0x63,  // this is 5987 in hex. specifying a different value seems to 
+               // cause client to connect on a different port for some commands
+  0x00, 0xFF,
+  0x00, 0x00, 0x05, 0x00, 0x09, 0x78, 
+  0x6C, 0x69, 0x6E, 0x6B, 0x5F, 0x64, 
+  0x65, 0x76, 0x07, 0x5B, 0xCD, 0x15
+};
+
+uint8_t V6MiLightUdpServer::OPEN_COMMAND_RESPONSE[] = {
+  0x80, 0x00, 0x00, 0x00, 0x15,
+  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // mac address
+  0x05, 0x02, 0x00, 0x34, 0x00, 0x00,
+  0x00, 0x00 ,0x00 ,0x00, 0x00, 0x00, 
+  0x00, 0x00, 0x34
+};
 
 V6MiLightUdpServer::~V6MiLightUdpServer() {
   V6Session* cur = firstSession;
@@ -88,6 +130,17 @@ uint16_t V6MiLightUdpServer::beginSession() {
   return id;
 }
 
+void V6MiLightUdpServer::handleSearch() {
+  const size_t packetLen = size(SEARCH_RESPONSE);
+  uint8_t response[packetLen];
+  memcpy(response, SEARCH_RESPONSE, packetLen);
+  WiFi.macAddress(response + 6);
+  
+  socket.beginPacket(socket.remoteIP(), socket.remotePort());
+  socket.write(response, packetLen);
+  socket.endPacket();
+}
+
 void V6MiLightUdpServer::handleStartSession() {
   size_t len = size(START_SESSION_RESPONSE);
   uint8_t response[len];
@@ -101,7 +154,7 @@ void V6MiLightUdpServer::handleStartSession() {
   sendResponse(sessionId, response, len);
 }
   
-void V6MiLightUdpServer::sendResponse(uint16_t sessionId, uint8_t* responseBuffer, size_t responseSize) {
+bool V6MiLightUdpServer::sendResponse(uint16_t sessionId, uint8_t* responseBuffer, size_t responseSize) {
   V6Session* session = firstSession;
   
   while (session != NULL) {
@@ -114,7 +167,7 @@ void V6MiLightUdpServer::sendResponse(uint16_t sessionId, uint8_t* responseBuffe
   if (session == NULL || session->sessionId != sessionId) {
     Serial.print("Received request with untracked session ID: ");
     Serial.println(sessionId);
-    return;
+    return false;
   }
   
 #ifdef MILIGHT_UDP_DEBUG
@@ -124,91 +177,17 @@ void V6MiLightUdpServer::sendResponse(uint16_t sessionId, uint8_t* responseBuffe
   socket.beginPacket(session->ipAddr, session->port);
   socket.write(responseBuffer, responseSize);
   socket.endPacket();
-}
-
-bool V6MiLightUdpServer::handleRgbBulbCommand(uint8_t group, uint32_t _cmd, uint32_t _arg) {
-  const uint8_t cmd = _cmd & 0xFF;
-  const uint8_t arg = _arg >> 24;
   
-  client->prepare(MilightRgbConfig, deviceId, 0);
-  
-  if (cmd == V2_RGB_COMMAND_PREFIX) {
-    switch (arg) {
-      case V2_RGB_ON:
-        client->updateStatus(ON);
-        break;
-        
-      case V2_RGB_OFF:
-        client->updateStatus(OFF);
-        break;
-        
-      case V2_RGB_BRIGHTNESS_DOWN:
-        client->decreaseBrightness();
-        break;
-        
-      case V2_RGB_BRIGHTNESS_UP:
-        client->increaseBrightness();
-        break;
-        
-      case V2_RGB_MODE_DOWN:
-        client->previousMode();
-        break;
-        
-      case V2_RGB_MODE_UP:
-        client->nextMode();
-        break;
-        
-      case V2_RGB_SPEED_DOWN:
-        client->modeSpeedDown();
-        break;
-        
-      case V2_RGB_SPEED_UP:
-        client->modeSpeedUp();
-        break;
-    }
-  } else if (cmd == V2_RGB_COLOR_PREFIX) {
-    client->updateColorRaw(arg);
-  }
+  return true;
 }
 
-bool V6MiLightUdpServer::handleV2BulbCommand(uint8_t group, uint32_t _cmd, uint32_t _arg) {
-  const uint8_t cmd = _cmd & 0xFF;
-  const uint8_t arg = _arg >> 24;
-  
-  client->prepare(MilightRgbCctConfig, deviceId, group);
-  
-  switch (cmd) {
-    case V2_STATUS:
-      if (arg == 0x01) {
-        client->updateStatus(ON);
-      } else if (arg == 0x02) {
-        client->updateStatus(OFF);
-      } else if (arg == 0x05) {
-        client->updateBrightness(0);
-      }
-      break;
-      
-    case V2_COLOR:
-      client->updateColorRaw(arg);
-      break;
-      
-    case V2_KELVIN:
-      client->updateTemperature(arg);
-      break;
-      
-    case V2_BRIGHTNESS:
-      client->updateBrightness(arg);
-      break;
-      
-    case V2_SATURATION:
-      client->updateSaturation(100 - arg);
-      break;
-      
-    default:
-      return false;
-  }
+bool V6MiLightUdpServer::handleOpenCommand(uint16_t sessionId) {
+  size_t len = size(OPEN_COMMAND_RESPONSE);
+  uint8_t response[len];
+  memcpy(response, OPEN_COMMAND_RESPONSE, len);
+  WiFi.macAddress(response + 5);
   
-  return true;
+  return sendResponse(sessionId, response, len);
 }
   
 void V6MiLightUdpServer::handleCommand(
@@ -224,16 +203,27 @@ void V6MiLightUdpServer::handleCommand(
   uint32_t cmdArg = readInt<uint32_t>(cmd+5);
   
 #ifdef MILIGHT_UDP_DEBUG
-  printf("Command type: %02X, command: %08X, arg: %08X\n", cmdType, cmdHeader, cmdArg);
+  printf("Command cmdType: %02X, cmdHeader: %08X, cmdArg: %08X\n", cmdType, cmdHeader, cmdArg);
 #endif
   
   bool handled = false;
   
-  if ((cmdHeader & 0x0800) == 0x0800) {
-    handled = handleV2BulbCommand(group, cmdHeader, cmdArg);
-  } else if ((cmdHeader & 0x0500) == 0x0500) {
-    handled = handleRgbBulbCommand(group, cmdHeader, cmdArg);
+  if (cmdHeader == 0) {
+    handled = handleOpenCommand(sessionId);
+  } else {
+    handled = COMMAND_DEMUXER->handleCommand(
+      client,
+      deviceId,
+      group,
+      cmdHeader,
+      cmdArg
+    );
   }
+  // else if ((cmdHeader & 0x0800) == 0x0800) {
+  //   handled = handleV2BulbCommand(group, cmdHeader, cmdArg);
+  // } else if ((cmdHeader & 0x0500) == 0x0500) {
+  //   handled = handleRgbBulbCommand(group, cmdHeader, cmdArg);
+  // }
   
   if (handled) {
     size_t len = size(COMMAND_RESPONSE);
@@ -262,18 +252,24 @@ void V6MiLightUdpServer::handleHeartbeat(uint16_t sessionId) {
   
   sendResponse(sessionId, responseBuffer, 12);
 }
+  
+bool V6MiLightUdpServer::matchesPacket(uint8_t* packet1, size_t packet1Len, uint8_t* packet2, size_t packet2Len) {
+  return packet2Len >= packet1Len && memcmp(packet1, packet2, packet1Len) == 0;
+}
 
 void V6MiLightUdpServer::handlePacket(uint8_t* packet, size_t packetSize) {
 #ifdef MILIGHT_UDP_DEBUG
   printf("Packet size: %d\n", packetSize);
 #endif
   
-  if (packetSize >= size(START_SESSION_COMMAND) && memcmp(START_SESSION_COMMAND, packet, size(START_SESSION_COMMAND)) == 0) {
+  if (MATCHES_PACKET(START_SESSION_COMMAND)) {
     handleStartSession();
-  } else if (packetSize >= size(HEARTBEAT_HEADER) && memcmp(HEARTBEAT_HEADER, packet, size(HEARTBEAT_HEADER)) == 0) {
+  } else if (MATCHES_PACKET(HEARTBEAT_HEADER) || MATCHES_PACKET(HEARTBEAT_HEADER2)) {
     uint16_t sessionId = readInt<uint16_t>(packet+5);
     handleHeartbeat(sessionId);
-  } else if (packetSize == 22 && memcmp(COMMAND_HEADER, packet, size(COMMAND_HEADER)) == 0) {
+  } else if (MATCHES_PACKET(SEARCH_COMMAND)) {
+    handleSearch();
+  } else if (packetSize == 22 && MATCHES_PACKET(COMMAND_HEADER)) {
     uint16_t sessionId = readInt<uint16_t>(packet+5);
     uint8_t sequenceNum = packet[8];
     uint8_t* cmd = packet+10;

+ 20 - 41
lib/Udp/V6MiLightUdpServer.h

@@ -6,6 +6,7 @@
 #include <WiFiUdp.h>
 #include <MiLightUdpServer.h>
 #include <Vector.h>
+#include <V6CommandHandler.h>
 
 #define V6_COMMAND_LEN 8
 #define V6_MAX_SESSIONS 10
@@ -13,27 +14,6 @@
 #ifndef _V6_MILIGHT_UDP_SERVER
 #define _V6_MILIGHT_UDP_SERVER 
 
-enum V2CommandIds {
-  V2_COLOR = 0x01,
-  V2_SATURATION = 0x02,
-  V2_BRIGHTNESS = 0x03,
-  V2_STATUS = 0x04,
-  V2_KELVIN = 0x05
-};
-
-enum RgbCommandIds {
-  V2_RGB_COMMAND_PREFIX  = 0x02,
-  V2_RGB_COLOR_PREFIX    = 0x01,
-  V2_RGB_BRIGHTNESS_DOWN = 0x01,
-  V2_RGB_BRIGHTNESS_UP   = 0x02,
-  V2_RGB_SPEED_DOWN      = 0x03,
-  V2_RGB_SPEED_UP        = 0x04,
-  V2_RGB_MODE_DOWN       = 0x05,
-  V2_RGB_MODE_UP         = 0x06,
-  V2_RGB_ON              = 0x09,
-  V2_RGB_OFF             = 0x0A
-};
-
 struct V6Session {
   V6Session(IPAddress ipAddr, uint16_t port, uint16_t sessionId)
     : ipAddr(ipAddr),
@@ -69,22 +49,33 @@ public:
   static uint8_t* writeInt(const T& value, uint8_t* packet);
     
 protected:
-  static uint8_t START_SESSION_COMMAND[];
-  static uint8_t START_SESSION_RESPONSE[];
-  static uint8_t COMMAND_HEADER[];
-  static uint8_t COMMAND_RESPONSE[];
-  static uint8_t SEARCH_COMMAND[];
-  static uint8_t LOCAL_SEARCH_COMMAND[];
-  static uint8_t HEARTBEAT_HEADER[];
+  static V6CommandDemuxer* COMMAND_DEMUXER;
+  
+  static uint8_t START_SESSION_COMMAND[] PROGMEM;
+  static uint8_t START_SESSION_RESPONSE[] PROGMEM;
+  static uint8_t COMMAND_HEADER[] PROGMEM;
+  static uint8_t COMMAND_RESPONSE[] PROGMEM;
+  static uint8_t LOCAL_SEARCH_COMMAND[] PROGMEM;
+  static uint8_t HEARTBEAT_HEADER[] PROGMEM;
+  static uint8_t HEARTBEAT_HEADER2[] PROGMEM;
+  
+  static uint8_t SEARCH_COMMAND[] PROGMEM;
+  static uint8_t SEARCH_RESPONSE[] PROGMEM;
+  
+  static uint8_t OPEN_COMMAND_RESPONSE[] PROGMEM;
   
   V6Session* firstSession;
   size_t numSessions;
   uint16_t sessionId;
   
   uint16_t beginSession();
-  void sendResponse(uint16_t sessionId, uint8_t* responseBuffer, size_t responseSize);
+  bool sendResponse(uint16_t sessionId, uint8_t* responseBuffer, size_t responseSize);
   
+  bool matchesPacket(uint8_t* packet1, size_t packet1Len, uint8_t* packet2, size_t packet2Len);
+  
+  void handleSearch();
   void handleStartSession();
+  bool handleOpenCommand(uint16_t sessionId);
   void handleHeartbeat(uint16_t sessionId);
   void handleCommand(
     uint16_t sessionId,
@@ -93,18 +84,6 @@ protected:
     uint8_t group,
     uint8_t checksum
   );
-  
-  bool handleRgbBulbCommand(
-    uint8_t group,
-    uint32_t cmd,
-    uint32_t cmdArg
-  );
-  
-  bool handleV2BulbCommand(
-    uint8_t group,
-    uint32_t cmd,
-    uint32_t cmdArg
-  );
 };
 
 #endif

+ 51 - 0
lib/Udp/V6RgbCctCommandHandler.cpp

@@ -0,0 +1,51 @@
+#include <V6RgbCctCommandHandler.h>
+
+bool V6RgbCctCommandHandler::handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg)
+{
+  const uint8_t cmd = command & 0xFF;
+  const uint8_t arg = commandArg >> 24;
+  
+  client->prepare(MilightRgbCctConfig, deviceId, group);
+  
+  switch (cmd) {
+    case V2_STATUS:
+      if (arg == 0x01) {
+        client->updateStatus(ON);
+      } else if (arg == 0x02) {
+        client->updateStatus(OFF);
+      } else if (arg == 0x05) {
+        client->updateBrightness(0);
+      }
+      break;
+      
+    case V2_COLOR:
+      client->updateColorRaw(arg);
+      break;
+      
+    case V2_KELVIN:
+      client->updateTemperature(arg);
+      break;
+      
+    case V2_BRIGHTNESS:
+      client->updateBrightness(arg);
+      break;
+      
+    case V2_SATURATION:
+      client->updateSaturation(100 - arg);
+      break;
+      
+    case V2_MODE:
+      client->updateMode(arg-1);
+      break;
+      
+    default:
+      return false;
+  }
+  
+  return true;
+}

+ 31 - 0
lib/Udp/V6RgbCctCommandHandler.h

@@ -0,0 +1,31 @@
+#include <V6CommandHandler.h>
+
+#ifndef _V6_RGB_CCT_COMMAND_HANDLER_H
+#define _V6_RGB_CCT_COMMAND_HANDLER_H 
+
+enum V2CommandIds {
+  V2_COLOR = 0x01,
+  V2_SATURATION = 0x02,
+  V2_BRIGHTNESS = 0x03,
+  V2_STATUS = 0x04,
+  V2_KELVIN = 0x05,
+  V2_MODE = 0x06
+};
+
+class V6RgbCctCommandHandler : public V6CommandHandler {
+public:
+  V6RgbCctCommandHandler(uint16_t commandId)
+    : V6CommandHandler(commandId)
+  { }
+  
+  virtual bool handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg
+  );
+  
+};
+
+#endif

+ 60 - 0
lib/Udp/V6RgbCommandHandler.cpp

@@ -0,0 +1,60 @@
+#include <V6RgbCommandHandler.h>
+
+bool V6RgbCommandHandler::handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg)
+{
+  const uint8_t cmd = command & 0xFF;
+  const uint8_t arg = commandArg >> 24;
+  
+  client->prepare(MilightRgbConfig, deviceId, 0);
+  
+  if (cmd == V2_RGB_COMMAND_PREFIX) {
+    switch (arg) {
+      case V2_RGB_ON:
+        client->updateStatus(ON);
+        break;
+        
+      case V2_RGB_OFF:
+        client->updateStatus(OFF);
+        break;
+        
+      case V2_RGB_BRIGHTNESS_DOWN:
+        client->decreaseBrightness();
+        break;
+        
+      case V2_RGB_BRIGHTNESS_UP:
+        client->increaseBrightness();
+        break;
+        
+      case V2_RGB_MODE_DOWN:
+        client->previousMode();
+        break;
+        
+      case V2_RGB_MODE_UP:
+        client->nextMode();
+        break;
+        
+      case V2_RGB_SPEED_DOWN:
+        client->modeSpeedDown();
+        break;
+        
+      case V2_RGB_SPEED_UP:
+        client->modeSpeedUp();
+        break;
+        
+      default:
+        return false;
+    }
+    
+    return true;
+  } else if (cmd == V2_RGB_COLOR_PREFIX) {
+    client->updateColorRaw(arg);
+    return true;
+  }
+  
+  return false;
+}

+ 35 - 0
lib/Udp/V6RgbCommandHandler.h

@@ -0,0 +1,35 @@
+#include <V6CommandHandler.h>
+
+#ifndef _V6_RGB_COMMAND_HANDLER_H
+#define _V6_RGB_COMMAND_HANDLER_H 
+
+enum RgbCommandIds {
+  V2_RGB_COMMAND_PREFIX  = 0x02,
+  V2_RGB_COLOR_PREFIX    = 0x01,
+  V2_RGB_BRIGHTNESS_DOWN = 0x01,
+  V2_RGB_BRIGHTNESS_UP   = 0x02,
+  V2_RGB_SPEED_DOWN      = 0x03,
+  V2_RGB_SPEED_UP        = 0x04,
+  V2_RGB_MODE_DOWN       = 0x05,
+  V2_RGB_MODE_UP         = 0x06,
+  V2_RGB_ON              = 0x09,
+  V2_RGB_OFF             = 0x0A
+};
+
+class V6RgbCommandHandler : public V6CommandHandler {
+public:
+  V6RgbCommandHandler(uint16_t commandId)
+    : V6CommandHandler(commandId)
+  { }
+  
+  virtual bool handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg
+  );
+  
+};
+
+#endif

+ 59 - 0
lib/Udp/V6RgbwCommandHandler.cpp

@@ -0,0 +1,59 @@
+#include <V6RgbwCommandHandler.h>
+
+bool V6RgbwCommandHandler::handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg)
+{
+  const uint8_t cmd = command & 0xFF;
+  const uint8_t arg = commandArg >> 24;
+  
+  client->prepare(MilightRgbwConfig, deviceId, 0);
+  
+  if (cmd == V2_RGBW_COMMAND_PREFIX) {
+    switch (arg) {
+      case V2_RGBW_ON:
+        client->updateStatus(ON);
+        break;
+        
+      case V2_RGBW_OFF:
+        client->updateStatus(OFF);
+        break;
+        
+      case V2_RGBW_WHITE_ON:
+        client->updateColorWhite();
+        break;
+        
+      case V2_RGBW_NIGHT_LIGHT:
+        client->updateColorWhite();
+        client->updateBrightness(0);
+        break;
+        
+      case V2_RGBW_SPEED_DOWN:
+        client->modeSpeedDown();
+        break;
+        
+      case V2_RGBW_SPEED_UP:
+        client->modeSpeedUp();
+        break;
+        
+      default:
+        return false;
+    }
+    
+    return true;
+  } else if (cmd == V2_RGBW_COLOR_PREFIX) {
+    client->updateColorRaw(arg);
+    return true;
+  } else if (cmd == V2_RGBW_BRIGHTNESS_PREFIX) {
+    client->updateBrightness(arg);
+    return true;
+  } else if (cmd == V2_RGBW_MODE_PREFIX) {
+    client->updateMode(arg);
+    return true;
+  }
+  
+  return false;
+}

+ 36 - 0
lib/Udp/V6RgbwCommandHandler.h

@@ -0,0 +1,36 @@
+#include <V6CommandHandler.h>
+
+#ifndef _V6_RGBW_COMMAND_HANDLER_H
+#define _V6_RGBW_COMMAND_HANDLER_H 
+
+enum RgbwCommandIds {
+  V2_RGBW_COLOR_PREFIX      = 0x01,
+  V2_RGBW_BRIGHTNESS_PREFIX = 0x02,
+  V2_RGBW_COMMAND_PREFIX    = 0x03,
+  V2_RGBW_MODE_PREFIX       = 0x04,
+  
+  V2_RGBW_ON                = 0x01,
+  V2_RGBW_OFF               = 0x02,
+  V2_RGBW_SPEED_DOWN        = 0x03,
+  V2_RGBW_SPEED_UP          = 0x04,
+  V2_RGBW_WHITE_ON          = 0x05,
+  V2_RGBW_NIGHT_LIGHT       = 0x06
+};
+
+class V6RgbwCommandHandler : public V6CommandHandler {
+public:
+  V6RgbwCommandHandler(uint16_t commandId)
+    : V6CommandHandler(commandId)
+  { }
+  
+  virtual bool handleCommand(
+    MiLightClient* client, 
+    uint16_t deviceId,
+    uint8_t group,
+    uint32_t command,
+    uint32_t commandArg
+  );
+  
+};
+
+#endif

+ 1 - 1
platformio.ini

@@ -16,7 +16,7 @@ lib_deps_external =
   RF24
   WiFiManager
   ArduinoJson
-build_flags = -D MILIGHT_HUB_VERSION=\"1.1.0\"
+build_flags = -D MILIGHT_HUB_VERSION=\"1.1.0\" -D MILIGHT_UDP_DEBUG
 
 [env:nodemcuv2]
 platform = espressif8266

+ 1 - 0
src/main.cpp

@@ -5,6 +5,7 @@
 #include <FS.h>
 #include <GithubDownloader.h>
 #include <IntParsing.h>
+#include <Size.h>
 #include <MiLightClient.h>
 #include <MiLightRadioConfig.h>
 #include <MiLightHttpServer.h>