Procházet zdrojové kódy

Add support for FUT091/B2/T2 (v2 CCT remote)

Christopher Mullins před 7 roky
rodič
revize
b4084c24ec

+ 56 - 0
lib/MiLight/FUT091PacketFormatter.cpp

@@ -0,0 +1,56 @@
+#include <FUT091PacketFormatter.h>
+#include <V2RFEncoding.h>
+#include <Units.h>
+
+void FUT091PacketFormatter::updateBrightness(uint8_t value) {
+  command(static_cast<uint8_t>(FUT091Command::BRIGHTNESS), V2PacketFormatter::tov2scale(value, 0x97, 2));
+}
+
+void FUT091PacketFormatter::updateTemperature(uint8_t value) {
+  command(static_cast<uint8_t>(FUT091Command::KELVIN), V2PacketFormatter::tov2scale(value, 0xCD, 2));
+}
+
+void FUT091PacketFormatter::enableNightMode() {
+  uint8_t arg = groupCommandArg(OFF, groupId);
+  command(static_cast<uint8_t>(FUT091Command::ON_OFF) | 0x80, arg);
+}
+
+BulbId FUT091PacketFormatter::parsePacket(const uint8_t *packet, JsonObject& result) {
+  uint8_t packetCopy[V2_PACKET_LEN];
+  memcpy(packetCopy, packet, V2_PACKET_LEN);
+  V2RFEncoding::decodeV2Packet(packetCopy);
+
+  BulbId bulbId(
+    (packetCopy[2] << 8) | packetCopy[3],
+    packetCopy[7],
+    REMOTE_TYPE_FUT091
+  );
+
+  uint8_t command = (packetCopy[V2_COMMAND_INDEX] & 0x7F);
+  uint8_t arg = packetCopy[V2_ARGUMENT_INDEX];
+
+  if (command == (uint8_t)FUT091Command::ON_OFF) {
+    if ((packetCopy[V2_COMMAND_INDEX] & 0x80) == 0x80) {
+      result["command"] = "night_mode";
+    } else if (arg < 5) { // Group is not reliably encoded in group byte. Extract from arg byte
+      result["state"] = "ON";
+      bulbId.groupId = arg;
+    } else {
+      result["state"] = "OFF";
+      bulbId.groupId = arg-5;
+    }
+  } else if (command == (uint8_t)FUT091Command::BRIGHTNESS) {
+    uint8_t level = V2PacketFormatter::fromv2scale(arg, 0x97, 2);
+    result["brightness"] = Units::rescale<uint8_t, uint8_t>(level, 255, 100);
+  // saturation == kelvin. arg ranges are the same, so can't distinguish
+  // without using state
+  } else if (command == (uint8_t)FUT091Command::KELVIN) {
+    uint8_t kelvin = V2PacketFormatter::fromv2scale(arg, 0xCD, 2);
+    result["color_temp"] = Units::whiteValToMireds(kelvin, 100);
+  } else {
+    result["button_id"] = command;
+    result["argument"] = arg;
+  }
+
+  return bulbId;
+}

+ 25 - 0
lib/MiLight/FUT091PacketFormatter.h

@@ -0,0 +1,25 @@
+#include <V2PacketFormatter.h>
+
+#ifndef _FUT091_PACKET_FORMATTER_H
+#define _FUT091_PACKET_FORMATTER_H
+
+enum class FUT091Command {
+  ON_OFF = 0x01,
+  BRIGHTNESS = 0x2,
+  KELVIN = 0x03
+};
+
+class FUT091PacketFormatter : public V2PacketFormatter {
+public:
+  FUT091PacketFormatter()
+    : V2PacketFormatter(0x21, 4)    // protocol is 0x21, and there are 4 groups
+  { }
+
+  virtual void updateBrightness(uint8_t value);
+  virtual void updateTemperature(uint8_t value);
+  virtual void enableNightMode();
+
+  virtual BulbId parsePacket(const uint8_t* packet, JsonObject& result);
+};
+
+#endif

+ 18 - 5
lib/MiLight/MiLightRemoteConfig.cpp

@@ -5,10 +5,11 @@
  */
 const MiLightRemoteConfig* MiLightRemoteConfig::ALL_REMOTES[] = {
   &FUT096Config, // rgbw
-  &FUT091Config, // cct
+  &FUT007Config, // cct
   &FUT092Config, // rgb+cct
   &FUT098Config, // rgb
-  &FUT089Config  // 8-group rgb+cct (b8, fut089)
+  &FUT089Config, // 8-group rgb+cct (b8, fut089)
+  &FUT091Config
 };
 
 const MiLightRemoteConfig* MiLightRemoteConfig::fromType(const String& type) {
@@ -16,8 +17,8 @@ const MiLightRemoteConfig* MiLightRemoteConfig::fromType(const String& type) {
     return &FUT096Config;
   }
 
-  if (type.equalsIgnoreCase("cct") || type.equalsIgnoreCase("fut091")) {
-    return &FUT091Config;
+  if (type.equalsIgnoreCase("cct") || type.equalsIgnoreCase("fut007")) {
+    return &FUT007Config;
   }
 
   if (type.equalsIgnoreCase("rgb_cct") || type.equalsIgnoreCase("fut092")) {
@@ -32,6 +33,10 @@ const MiLightRemoteConfig* MiLightRemoteConfig::fromType(const String& type) {
     return &FUT098Config;
   }
 
+  if (type.equalsIgnoreCase("v2_cct") || type.equalsIgnoreCase("fut091")) {
+    return &FUT091Config;
+  }
+
   Serial.print(F("MiLightRemoteConfig::fromType: ERROR - tried to fetch remote config for type: "));
   Serial.println(type);
 
@@ -77,7 +82,7 @@ const MiLightRemoteConfig FUT096Config( //rgbw
   4
 );
 
-const MiLightRemoteConfig FUT091Config( //cct
+const MiLightRemoteConfig FUT007Config( //cct
   new CctPacketFormatter(),
   MiLightRadioConfig::ALL_CONFIGS[1],
   REMOTE_TYPE_CCT,
@@ -85,6 +90,14 @@ const MiLightRemoteConfig FUT091Config( //cct
   4
 );
 
+const MiLightRemoteConfig FUT091Config( //v2 cct
+  new FUT091PacketFormatter(),
+  MiLightRadioConfig::ALL_CONFIGS[2],
+  REMOTE_TYPE_FUT091,
+  "fut091",
+  4
+);
+
 const MiLightRemoteConfig FUT092Config( //rgb+cct
   new RgbCctPacketFormatter(),
   MiLightRadioConfig::ALL_CONFIGS[2],

+ 4 - 2
lib/MiLight/MiLightRemoteConfig.h

@@ -6,6 +6,7 @@
 #include <RgbCctPacketFormatter.h>
 #include <CctPacketFormatter.h>
 #include <FUT089PacketFormatter.h>
+#include <FUT091PacketFormatter.h>
 #include <PacketFormatter.h>
 
 #ifndef _MILIGHT_REMOTE_CONFIG_H
@@ -36,14 +37,15 @@ public:
   static const MiLightRemoteConfig* fromType(const String& type);
   static const MiLightRemoteConfig* fromReceivedPacket(const MiLightRadioConfig& radioConfig, const uint8_t* packet, const size_t len);
 
-  static const size_t NUM_REMOTES = 5;
+  static const size_t NUM_REMOTES = 6;
   static const MiLightRemoteConfig* ALL_REMOTES[NUM_REMOTES];
 };
 
 extern const MiLightRemoteConfig FUT096Config; //rgbw
-extern const MiLightRemoteConfig FUT091Config; //cct
+extern const MiLightRemoteConfig FUT007Config; //cct
 extern const MiLightRemoteConfig FUT092Config; //rgb+cct
 extern const MiLightRemoteConfig FUT089Config; //rgb+cct B8 / FUT089
 extern const MiLightRemoteConfig FUT098Config; //rgb
+extern const MiLightRemoteConfig FUT091Config; //v2 cct
 
 #endif

+ 8 - 0
lib/MiLight/V2PacketFormatter.cpp

@@ -103,3 +103,11 @@ void V2PacketFormatter::switchMode(GroupState currentState, BulbMode desiredMode
   }
   
 }
+
+uint8_t V2PacketFormatter::tov2scale(uint8_t value, uint8_t endValue, uint8_t interval) {
+  return ((100 - value) * interval) + endValue;
+}
+
+uint8_t V2PacketFormatter::fromv2scale(uint8_t value, uint8_t endValue, uint8_t interval) {
+  return 100 - (((value + (0x100 - endValue))%0x100) / 2);
+}

+ 10 - 0
lib/MiLight/V2PacketFormatter.h

@@ -26,6 +26,16 @@ public:
 
   uint8_t groupCommandArg(MiLightStatus status, uint8_t groupId);
 
+  /*
+   * Some protocols have scales which have the following characteristics:
+   *   Start at some value X, goes down to 0, then up to Y.
+   * eg:
+   *   0x8F, 0x8D, ..., 0, 0x2, ..., 0x20
+   * This is a parameterized method to convert from [0, 100] TO this scale
+   */
+  static uint8_t tov2scale(uint8_t value, uint8_t endValue, uint8_t interval);
+  static uint8_t fromv2scale(uint8_t value, uint8_t endValue, uint8_t interval);
+
 protected:
   const uint8_t protocolId;
   const uint8_t numGroups;

+ 2 - 1
lib/Radio/MiLightConstants.h

@@ -7,7 +7,8 @@ enum MiLightRemoteType {
   REMOTE_TYPE_CCT     = 1,
   REMOTE_TYPE_RGB_CCT = 2,
   REMOTE_TYPE_RGB     = 3,
-  REMOTE_TYPE_FUT089  = 4
+  REMOTE_TYPE_FUT089  = 4,
+  REMOTE_TYPE_FUT091  = 5
 };
 
 enum MiLightStatus {

+ 2 - 1
lib/Types/MiLightConstants.h

@@ -7,7 +7,8 @@ enum MiLightRemoteType {
   REMOTE_TYPE_CCT     = 1,
   REMOTE_TYPE_RGB_CCT = 2,
   REMOTE_TYPE_RGB     = 3,
-  REMOTE_TYPE_FUT089  = 4
+  REMOTE_TYPE_FUT089  = 4,
+  REMOTE_TYPE_FUT091  = 5
 };
 
 enum MiLightStatus {

+ 2 - 2
lib/Udp/V5MiLightUdpServer.cpp

@@ -85,7 +85,7 @@ void V5MiLightUdpServer::handleCommand(uint8_t command, uint8_t commandArg) {
     uint8_t onOffGroup = CctPacketFormatter::cctCommandIdToGroup(command);
 
     if (onOffGroup != 255) {
-      client->prepare(&FUT091Config, deviceId, onOffGroup);
+      client->prepare(&FUT007Config, deviceId, onOffGroup);
       // Night mode commands are same as off commands with MSB set
       if ((command & 0x80) == 0x80) {
         client->enableNightMode();
@@ -95,7 +95,7 @@ void V5MiLightUdpServer::handleCommand(uint8_t command, uint8_t commandArg) {
       return;
     }
 
-    client->prepare(&FUT091Config, deviceId, lastGroup);
+    client->prepare(&FUT007Config, deviceId, lastGroup);
 
     switch(command) {
       case UDP_CCT_BRIGHTNESS_DOWN:

+ 1 - 1
lib/Udp/V6CctCommandHandler.h

@@ -18,7 +18,7 @@ enum CctCommandIds {
 class V6CctCommandHandler : public V6CommandHandler {
 public:
   V6CctCommandHandler()
-    : V6CommandHandler(0x0100, FUT091Config)
+    : V6CommandHandler(0x0100, FUT007Config)
   { }
 
   virtual bool handleCommand(