RgbCctPacketFormatter.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. #include <RgbCctPacketFormatter.h>
  2. #include <V2RFEncoding.h>
  3. #include <Units.h>
  4. #include <MiLightCommands.h>
  5. void RgbCctPacketFormatter::modeSpeedDown() {
  6. command(RGB_CCT_ON, RGB_CCT_MODE_SPEED_DOWN);
  7. }
  8. void RgbCctPacketFormatter::modeSpeedUp() {
  9. command(RGB_CCT_ON, RGB_CCT_MODE_SPEED_UP);
  10. }
  11. void RgbCctPacketFormatter::updateMode(uint8_t mode) {
  12. lastMode = mode;
  13. command(RGB_CCT_MODE, mode);
  14. }
  15. void RgbCctPacketFormatter::nextMode() {
  16. updateMode((lastMode+1)%RGB_CCT_NUM_MODES);
  17. }
  18. void RgbCctPacketFormatter::previousMode() {
  19. updateMode((lastMode-1)%RGB_CCT_NUM_MODES);
  20. }
  21. void RgbCctPacketFormatter::updateBrightness(uint8_t brightness) {
  22. command(RGB_CCT_BRIGHTNESS, RGB_CCT_BRIGHTNESS_OFFSET + brightness);
  23. }
  24. // change the hue (which may also change to color mode).
  25. void RgbCctPacketFormatter::updateHue(uint16_t value) {
  26. uint8_t remapped = Units::rescale(value, 255, 360);
  27. updateColorRaw(remapped);
  28. }
  29. void RgbCctPacketFormatter::updateColorRaw(uint8_t value) {
  30. command(RGB_CCT_COLOR, RGB_CCT_COLOR_OFFSET + value);
  31. }
  32. void RgbCctPacketFormatter::updateTemperature(uint8_t value) {
  33. // Packet scale is [0x94, 0x92, .. 0, .., 0xCE, 0xCC]. Increments of 2.
  34. // From coolest to warmest.
  35. uint8_t cmdValue = V2PacketFormatter::tov2scale(value, RGB_CCT_KELVIN_REMOTE_END, 2);
  36. // when updating temperature, the bulb switches to white. If we are not already
  37. // in white mode, that makes changing temperature annoying because the current hue/mode
  38. // is lost. So lookup our current bulb mode, and if needed, reset the hue/mode after
  39. // changing the temperature
  40. const GroupState* ourState = this->stateStore->get(this->deviceId, this->groupId, REMOTE_TYPE_RGB_CCT);
  41. // now make the temperature change
  42. command(RGB_CCT_KELVIN, cmdValue);
  43. // and return to our original mode
  44. if (ourState != NULL) {
  45. BulbMode originalBulbMode = ourState->getBulbMode();
  46. if ((settings->enableAutomaticModeSwitching) && (originalBulbMode != BulbMode::BULB_MODE_WHITE)) {
  47. switchMode(*ourState, originalBulbMode);
  48. }
  49. }
  50. }
  51. // update saturation. This only works when in Color mode, so if not in color we switch to color,
  52. // make the change, and switch back again.
  53. void RgbCctPacketFormatter::updateSaturation(uint8_t value) {
  54. // look up our current mode
  55. const GroupState* ourState = this->stateStore->get(this->deviceId, this->groupId, REMOTE_TYPE_RGB_CCT);
  56. BulbMode originalBulbMode = BulbMode::BULB_MODE_WHITE;
  57. if (ourState != NULL) {
  58. originalBulbMode = ourState->getBulbMode();
  59. // are we already in white? If not, change to white
  60. if ((settings->enableAutomaticModeSwitching) && (originalBulbMode != BulbMode::BULB_MODE_COLOR)) {
  61. updateHue(ourState->getHue());
  62. }
  63. }
  64. // now make the saturation change
  65. uint8_t remapped = value + RGB_CCT_SATURATION_OFFSET;
  66. command(RGB_CCT_SATURATION, remapped);
  67. if (ourState != NULL) {
  68. if ((settings->enableAutomaticModeSwitching) && (originalBulbMode != BulbMode::BULB_MODE_COLOR)) {
  69. switchMode(*ourState, originalBulbMode);
  70. }
  71. }
  72. }
  73. void RgbCctPacketFormatter::updateColorWhite() {
  74. // there is no direct white command, so let's look up our prior temperature and set that, which
  75. // causes the bulb to go white
  76. const GroupState* ourState = this->stateStore->get(this->deviceId, this->groupId, REMOTE_TYPE_RGB_CCT);
  77. uint8_t value =
  78. ourState == NULL
  79. ? 0
  80. : V2PacketFormatter::tov2scale(ourState->getKelvin(), RGB_CCT_KELVIN_REMOTE_END, 2);
  81. // issue command to set kelvin to prior value, which will drive to white
  82. command(RGB_CCT_KELVIN, value);
  83. }
  84. void RgbCctPacketFormatter::enableNightMode() {
  85. uint8_t arg = groupCommandArg(OFF, groupId);
  86. command(RGB_CCT_ON | 0x80, arg);
  87. }
  88. BulbId RgbCctPacketFormatter::parsePacket(const uint8_t *packet, JsonObject result) {
  89. uint8_t packetCopy[V2_PACKET_LEN];
  90. memcpy(packetCopy, packet, V2_PACKET_LEN);
  91. V2RFEncoding::decodeV2Packet(packetCopy);
  92. BulbId bulbId(
  93. (packetCopy[2] << 8) | packetCopy[3],
  94. packetCopy[7],
  95. REMOTE_TYPE_RGB_CCT
  96. );
  97. uint8_t command = (packetCopy[V2_COMMAND_INDEX] & 0x7F);
  98. uint8_t arg = packetCopy[V2_ARGUMENT_INDEX];
  99. if (command == RGB_CCT_ON) {
  100. if ((packetCopy[V2_COMMAND_INDEX] & 0x80) == 0x80) {
  101. result[GroupStateFieldNames::COMMAND] = MiLightCommandNames::NIGHT_MODE;
  102. } else if (arg == RGB_CCT_MODE_SPEED_DOWN) {
  103. result[GroupStateFieldNames::COMMAND] = MiLightCommandNames::MODE_SPEED_DOWN;
  104. } else if (arg == RGB_CCT_MODE_SPEED_UP) {
  105. result[GroupStateFieldNames::COMMAND] = MiLightCommandNames::MODE_SPEED_UP;
  106. } else if (arg < 5) { // Group is not reliably encoded in group byte. Extract from arg byte
  107. result[GroupStateFieldNames::STATE] = "ON";
  108. bulbId.groupId = arg;
  109. } else {
  110. result[GroupStateFieldNames::STATE] = "OFF";
  111. bulbId.groupId = arg-5;
  112. }
  113. } else if (command == RGB_CCT_COLOR) {
  114. uint8_t rescaledColor = (arg - RGB_CCT_COLOR_OFFSET) % 0x100;
  115. uint16_t hue = Units::rescale<uint16_t, uint16_t>(rescaledColor, 360, 255.0);
  116. result[GroupStateFieldNames::HUE] = hue;
  117. } else if (command == RGB_CCT_KELVIN) {
  118. uint8_t temperature = V2PacketFormatter::fromv2scale(arg, RGB_CCT_KELVIN_REMOTE_END, 2);
  119. result[GroupStateFieldNames::COLOR_TEMP] = Units::whiteValToMireds(temperature, 100);
  120. // brightness == saturation
  121. } else if (command == RGB_CCT_BRIGHTNESS && arg >= (RGB_CCT_BRIGHTNESS_OFFSET - 15)) {
  122. uint8_t level = constrain(arg - RGB_CCT_BRIGHTNESS_OFFSET, 0, 100);
  123. result[GroupStateFieldNames::BRIGHTNESS] = Units::rescale<uint8_t, uint8_t>(level, 255, 100);
  124. } else if (command == RGB_CCT_SATURATION) {
  125. result[GroupStateFieldNames::SATURATION] = constrain(arg - RGB_CCT_SATURATION_OFFSET, 0, 100);
  126. } else if (command == RGB_CCT_MODE) {
  127. result[GroupStateFieldNames::MODE] = arg;
  128. } else {
  129. result["button_id"] = command;
  130. result["argument"] = arg;
  131. }
  132. return bulbId;
  133. }