Browse Source

refactor to make it easier to add new kinds of UDP handlers. add UDP handler for CCT bulbs

Chris Mullins 8 years ago
parent
commit
e9faea865c

+ 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()

+ 0 - 17
lib/MiLight/MiLightButtons.h

@@ -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

+ 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

+ 29 - 0
lib/Udp/V6ComamndHandler.cpp

@@ -0,0 +1,29 @@
+#include <V6CommandHandler.h>
+#include <V6RgbCctCommandHandler.h>
+#include <V6RgbCommandHandler.h>
+#include <V6CctCommandHandler.h>
+#include <Size.h>
+
+V6CommandHandler* V6CommandHandler::ALL_HANDLERS[] = {
+  new V6RgbCctCommandHandler(0x0800),
+  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

+ 23 - 101
lib/Udp/V6MiLightUdpServer.cpp

@@ -1,10 +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, 
@@ -51,7 +58,9 @@ uint8_t V6MiLightUdpServer::SEARCH_RESPONSE[] = {
   0x37, 0x65, 0x61, 0x33, 0x62, 0x31, 
   0x39, 0x64, 0x30, 0x64, 0x01, 0x00, 
   0x01, 
-  0x17, 0x63,  // port?
+  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
@@ -65,11 +74,6 @@ uint8_t V6MiLightUdpServer::OPEN_COMMAND_RESPONSE[] = {
   0x00, 0x00, 0x34
 };
 
-template<typename T, size_t sz>
-size_t size(T(&)[sz]) {
-    return sz;
-}
-
 V6MiLightUdpServer::~V6MiLightUdpServer() {
   V6Session* cur = firstSession;
   
@@ -132,12 +136,6 @@ void V6MiLightUdpServer::handleSearch() {
   memcpy(response, SEARCH_RESPONSE, packetLen);
   WiFi.macAddress(response + 6);
   
-  printf("Sending search response - ");
-  for (size_t i = 0; i < packetLen; i++) {
-    printf("%02X ", response[i]);
-  }
-  printf("\n");
-  
   socket.beginPacket(socket.remoteIP(), socket.remotePort());
   socket.write(response, packetLen);
   socket.endPacket();
@@ -183,91 +181,6 @@ bool V6MiLightUdpServer::sendResponse(uint16_t sessionId, uint8_t* responseBuffe
   return true;
 }
 
-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);
-  }
-}
-
-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;
-  }
-  
-  return true;
-}
-
 bool V6MiLightUdpServer::handleOpenCommand(uint16_t sessionId) {
   size_t len = size(OPEN_COMMAND_RESPONSE);
   uint8_t response[len];
@@ -297,11 +210,20 @@ void V6MiLightUdpServer::handleCommand(
   
   if (cmdHeader == 0) {
     handled = handleOpenCommand(sessionId);
-  } else if ((cmdHeader & 0x0800) == 0x0800) {
-    handled = handleV2BulbCommand(group, cmdHeader, cmdArg);
-  } else if ((cmdHeader & 0x0500) == 0x0500) {
-    handled = handleRgbBulbCommand(group, cmdHeader, cmdArg);
+  } 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);

+ 3 - 33
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,6 +49,8 @@ public:
   static uint8_t* writeInt(const T& value, uint8_t* packet);
     
 protected:
+  static V6CommandDemuxer* COMMAND_DEMUXER;
+  
   static uint8_t START_SESSION_COMMAND[] PROGMEM;
   static uint8_t START_SESSION_RESPONSE[] PROGMEM;
   static uint8_t COMMAND_HEADER[] PROGMEM;
@@ -102,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

+ 47 - 0
lib/Udp/V6RgbCctCommandHandler.cpp

@@ -0,0 +1,47 @@
+#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;
+      
+    default:
+      return false;
+  }
+  
+  return true;
+}

+ 30 - 0
lib/Udp/V6RgbCctCommandHandler.h

@@ -0,0 +1,30 @@
+#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
+};
+
+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

+ 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>