소스 검색

Refactor unit conversion in state tracking. Correct color temperature scales

Chris Mullins 8 년 전
부모
커밋
30c657bc94

+ 5 - 12
lib/Helpers/Units.h

@@ -16,22 +16,15 @@ public:
   }
 
   static uint8_t miredsToWhiteVal(uint16_t mireds, uint8_t maxValue = 255) {
-      uint32_t tempMireds = constrain(mireds, COLOR_TEMP_MIN_MIREDS, COLOR_TEMP_MAX_MIREDS);
-
-      uint8_t scaledTemp = round(
-        maxValue*
-        (tempMireds - COLOR_TEMP_MIN_MIREDS)
-          /
-        static_cast<double>(COLOR_TEMP_MAX_MIREDS - COLOR_TEMP_MIN_MIREDS)
+      return rescale<uint16_t, uint16_t>(
+        constrain(mireds, COLOR_TEMP_MIN_MIREDS, COLOR_TEMP_MAX_MIREDS) - COLOR_TEMP_MIN_MIREDS,
+        maxValue,
+        (COLOR_TEMP_MAX_MIREDS - COLOR_TEMP_MIN_MIREDS)
       );
-
-      return scaledTemp;
   }
 
   static uint16_t whiteValToMireds(uint8_t value, uint8_t maxValue = 255) {
-    uint8_t reverseValue = maxValue - value;
-    uint16_t scaled = rescale<uint16_t, uint16_t>(reverseValue, (COLOR_TEMP_MAX_MIREDS - COLOR_TEMP_MIN_MIREDS), maxValue);
-
+    uint16_t scaled = rescale<uint16_t, uint16_t>(value, (COLOR_TEMP_MAX_MIREDS - COLOR_TEMP_MIN_MIREDS), maxValue);
     return COLOR_TEMP_MIN_MIREDS + scaled;
   }
 };

+ 3 - 3
lib/MiLight/FUT089PacketFormatter.cpp

@@ -33,7 +33,7 @@ void FUT089PacketFormatter::updateTemperature(uint8_t value) {
 }
 
 void FUT089PacketFormatter::updateSaturation(uint8_t value) {
-  command(FUT089_SATURATION, value);
+  command(FUT089_SATURATION, 100 - value);
 }
 
 void FUT089PacketFormatter::updateColorWhite() {
@@ -92,9 +92,9 @@ void FUT089PacketFormatter::parsePacket(const uint8_t *packet, JsonObject& resul
   // without using state
   } else if (command == FUT089_SATURATION) {
     if (state->getBulbMode() == BULB_MODE_COLOR) {
-      result["saturation"] = constrain(arg, 0, 100);
+      result["saturation"] = 100 - constrain(arg, 0, 100);
     } else {
-      result["color_temp"] = Units::whiteValToMireds(arg, 100);
+      result["color_temp"] = Units::whiteValToMireds(100 - arg, 100);
     }
   } else if (command == FUT089_MODE) {
     result["mode"] = arg;

+ 23 - 14
lib/MiLight/RgbCctPacketFormatter.cpp

@@ -37,7 +37,16 @@ void RgbCctPacketFormatter::updateColorRaw(uint8_t value) {
 }
 
 void RgbCctPacketFormatter::updateTemperature(uint8_t value) {
-  command(RGB_CCT_KELVIN, RGB_CCT_KELVIN_OFFSET - (value*2));
+  // Packet scale is [0x94, 0x92, .. 0, .., 0xCE, 0xCC]. Increments of 2.
+  // From coolest to warmest.
+  // To convert from [0, 100] scale:
+  //   * Multiply by 2
+  //   * Reverse direction (increasing values should be cool -> warm)
+  //   * Start scale at 0xCC
+
+  value = ((100 - value) * 2) + RGB_CCT_KELVIN_REMOTE_END;
+
+  command(RGB_CCT_KELVIN, value);
 }
 
 void RgbCctPacketFormatter::updateSaturation(uint8_t value) {
@@ -83,19 +92,19 @@ void RgbCctPacketFormatter::parsePacket(const uint8_t *packet, JsonObject& resul
     uint16_t hue = Units::rescale<uint16_t, uint16_t>(rescaledColor, 360, 255.0);
     result["hue"] = hue;
   } else if (command == RGB_CCT_KELVIN) {
-    uint8_t temperature =
-        static_cast<uint8_t>(
-          // Range in packets is 180 - 220 or something like that. Shift to
-          // 0..224. Then strip out values out of range [0..24), and (224..255]
-          constrain(
-            static_cast<uint8_t>(arg + RGB_CCT_KELVIN_REMOTE_OFFSET),
-            24,
-            224
-          )
-            +
-          // Shift 24 down to 0
-          RGB_CCT_KELVIN_REMOTE_START
-        )/2; // values are in increments of 2
+    // Packet range is [0x94, 0x92, ..., 0xCC]. Remote sends values outside this
+    // range, so normalize.
+    uint8_t temperature = arg;
+    if (arg < 0xCC && arg >= 0xB0) {
+      temperature = 0xCC;
+    } else if (arg > 0x94 && arg <= 0xAF) {
+      temperature = 0x94;
+    }
+
+    temperature = (temperature + (0x100 - RGB_CCT_KELVIN_REMOTE_END)) % 0x100;
+    temperature /= 2;
+    temperature = (100 - temperature);
+    temperature = constrain(temperature, 0, 100);
 
     result["color_temp"] = Units::whiteValToMireds(temperature, 100);
   // brightness == saturation

+ 2 - 2
lib/MiLight/RgbCctPacketFormatter.h

@@ -11,8 +11,8 @@
 #define RGB_CCT_KELVIN_OFFSET 0x94
 
 // Remotes have a larger range
-#define RGB_CCT_KELVIN_REMOTE_OFFSET 0x4C
-#define RGB_CCT_KELVIN_REMOTE_START  0xE8
+#define RGB_CCT_KELVIN_REMOTE_START  0x94
+#define RGB_CCT_KELVIN_REMOTE_END    0xCC
 
 enum MiLightRgbCctCommand {
   RGB_CCT_ON = 0x01,

+ 31 - 17
lib/MiLightState/GroupState.cpp

@@ -1,6 +1,7 @@
 #include <GroupState.h>
 #include <Units.h>
 #include <MiLightRemoteConfig.h>
+#include <RGBConverter.h>
 
 const GroupState& GroupState::defaultState(MiLightRemoteType remoteType) {
   static GroupState instances[MiLightRemoteConfig::NUM_REMOTES];
@@ -96,7 +97,6 @@ bool GroupState::isSetBrightness() const {
 
   return false;
 }
-
 uint8_t GroupState::getBrightness() const {
   switch (state.fields._bulbMode) {
     case BULB_MODE_WHITE:
@@ -109,7 +109,6 @@ uint8_t GroupState::getBrightness() const {
 
   return 0;
 }
-
 void GroupState::setBrightness(uint8_t brightness) {
   setDirty();
 
@@ -134,11 +133,13 @@ void GroupState::setBrightness(uint8_t brightness) {
 }
 
 bool GroupState::isSetHue() const { return state.fields._isSetHue; }
-uint8_t GroupState::getHue() const { return state.fields._hue; }
-void GroupState::setHue(uint8_t hue) {
+uint16_t GroupState::getHue() const {
+  return Units::rescale<uint16_t, uint16_t>(state.fields._hue, 360, 255);
+}
+void GroupState::setHue(uint16_t hue) {
   setDirty();
   state.fields._isSetHue = 1;
-  state.fields._hue = hue;
+  state.fields._hue = Units::rescale<uint16_t, uint16_t>(hue, 255, 360);
 }
 
 bool GroupState::isSetSaturation() const { return state.fields._isSetSaturation; }
@@ -159,11 +160,17 @@ void GroupState::setMode(uint8_t mode) {
 
 bool GroupState::isSetKelvin() const { return state.fields._isSetKelvin; }
 uint8_t GroupState::getKelvin() const { return state.fields._kelvin; }
+uint16_t GroupState::getMireds() const {
+  return Units::whiteValToMireds(getKelvin(), 100);
+}
 void GroupState::setKelvin(uint8_t kelvin) {
   setDirty();
   state.fields._isSetKelvin = 1;
   state.fields._kelvin = kelvin;
 }
+void GroupState::setMireds(uint16_t mireds) {
+  setKelvin(Units::miredsToWhiteVal(mireds, 100));
+}
 
 bool GroupState::isSetBulbMode() const { return state.fields._isSetBulbMode; }
 BulbMode GroupState::getBulbMode() const { return static_cast<BulbMode>(state.fields._bulbMode); }
@@ -198,7 +205,7 @@ void GroupState::patch(const JsonObject& state) {
     setBrightness(Units::rescale(state.get<uint8_t>("brightness"), 100, 255));
   }
   if (state.containsKey("hue")) {
-    setHue(Units::rescale<uint16_t, uint16_t>(state["hue"], 255, 360));
+    setHue(state["hue"]);
     setBulbMode(BULB_MODE_COLOR);
   }
   if (state.containsKey("saturation")) {
@@ -209,7 +216,7 @@ void GroupState::patch(const JsonObject& state) {
     setBulbMode(BULB_MODE_SCENE);
   }
   if (state.containsKey("color_temp")) {
-    setKelvin(Units::miredsToWhiteVal(state["color_temp"], 100));
+    setMireds(state["color_temp"]);
     setBulbMode(BULB_MODE_WHITE);
   }
   if (state.containsKey("command")) {
@@ -224,29 +231,36 @@ void GroupState::patch(const JsonObject& state) {
 }
 
 void GroupState::applyState(JsonObject& partialState) {
-  if (state.fields._isSetState) {
+  if (isSetState()) {
     partialState["state"] = getState() == ON ? "ON" : "OFF";
   }
-  if (state.fields._isSetBrightness) {
+  if (isSetBrightness()) {
     partialState["brightness"] = Units::rescale(getBrightness(), 255, 100);
   }
-  if (state.fields._isSetBulbMode) {
+  if (isSetBulbMode()) {
     partialState["bulb_mode"] = BULB_MODE_NAMES[getBulbMode()];
 
     if (getBulbMode() == BULB_MODE_COLOR) {
-      if (state.fields._isSetHue) {
-        partialState["hue"] = Units::rescale<uint16_t, uint16_t>(getHue(), 360, 255);
-      }
-      if (state.fields._isSetSaturation) {
+      if (isSetHue() && isSetSaturation()) {
+        uint8_t rgb[3];
+        RGBConverter converter;
+        converter.hsvToRgb(getHue()/360.0, getSaturation()/100.0, 1, rgb);
+        JsonObject& color = partialState.createNestedObject("color");
+        color["r"] = rgb[0];
+        color["g"] = rgb[1];
+        color["b"] = rgb[2];
+      } else if (isSetHue()) {
+        partialState["hue"] = getHue();
+      } else if (isSetSaturation()) {
         partialState["saturation"] = getSaturation();
       }
     } else if (getBulbMode() == BULB_MODE_SCENE) {
-      if (state.fields._isSetMode) {
+      if (isSetMode()) {
         partialState["mode"] = getMode();
       }
     } else if (getBulbMode() == BULB_MODE_WHITE) {
-      if (state.fields._isSetKelvin) {
-        partialState["color_temp"] = Units::whiteValToMireds(getKelvin(), 100);
+      if (isSetKelvin()) {
+        partialState["color_temp"] = getMireds();
       }
     }
   }

+ 4 - 2
lib/MiLightState/GroupState.h

@@ -47,8 +47,8 @@ public:
 
   // 8 bits
   bool isSetHue() const;
-  uint8_t getHue() const;
-  void setHue(uint8_t hue);
+  uint16_t getHue() const;
+  void setHue(uint16_t hue);
 
   // 7 bits
   bool isSetSaturation() const;
@@ -63,7 +63,9 @@ public:
   // 7 bits
   bool isSetKelvin() const;
   uint8_t getKelvin() const;
+  uint16_t getMireds() const;
   void setKelvin(uint8_t kelvin);
+  void setMireds(uint16_t mireds);
 
   // 3 bits
   bool isSetBulbMode() const;