CctPacketFormatter.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. #include <CctPacketFormatter.h>
  2. static const uint8_t CCT_PROTOCOL_ID = 0x5A;
  3. bool CctPacketFormatter::canHandle(const uint8_t *packet, const size_t len) {
  4. return len == packetLength && packet[0] == CCT_PROTOCOL_ID;
  5. }
  6. void CctPacketFormatter::initializePacket(uint8_t* packet) {
  7. size_t packetPtr = 0;
  8. // Byte 0: Packet length = 7 bytes
  9. // Byte 1: CCT protocol
  10. packet[packetPtr++] = CCT_PROTOCOL_ID;
  11. // Byte 2 and 3: Device ID
  12. packet[packetPtr++] = deviceId >> 8;
  13. packet[packetPtr++] = deviceId & 0xFF;
  14. // Byte 4: Zone
  15. packet[packetPtr++] = groupId;
  16. // Byte 5: Bulb command, filled in later
  17. packet[packetPtr++] = 0;
  18. // Byte 6: Packet sequence number 0..255
  19. packet[packetPtr++] = sequenceNum++;
  20. // Byte 7: Checksum over previous bytes, including packet length = 7
  21. // The checksum will be calculated when setting the command field
  22. packet[packetPtr++] = 0;
  23. // Byte 8: CRC LSB
  24. // Byte 9: CRC MSB
  25. }
  26. void CctPacketFormatter::finalizePacket(uint8_t* packet) {
  27. uint8_t checksum;
  28. // Calculate checksum over packet length .. sequenceNum
  29. checksum = 7; // Packet length is not part of packet
  30. for (uint8_t i = 0; i < 6; i++) {
  31. checksum += currentPacket[i];
  32. }
  33. // Store the checksum in the sixth byte
  34. currentPacket[6] = checksum;
  35. }
  36. void CctPacketFormatter::updateBrightness(uint8_t value) {
  37. const GroupState* state = this->stateStore->get(deviceId, groupId, MiLightRemoteType::REMOTE_TYPE_CCT);
  38. int8_t knownValue = (state != NULL && state->isSetBrightness()) ? state->getBrightness() : -1;
  39. valueByStepFunction(
  40. &PacketFormatter::increaseBrightness,
  41. &PacketFormatter::decreaseBrightness,
  42. CCT_INTERVALS,
  43. value / CCT_INTERVALS,
  44. knownValue / CCT_INTERVALS
  45. );
  46. }
  47. void CctPacketFormatter::updateTemperature(uint8_t value) {
  48. const GroupState* state = this->stateStore->get(deviceId, groupId, MiLightRemoteType::REMOTE_TYPE_CCT);
  49. int8_t knownValue = (state != NULL && state->isSetKelvin()) ? state->getKelvin() : -1;
  50. valueByStepFunction(
  51. &PacketFormatter::increaseTemperature,
  52. &PacketFormatter::decreaseTemperature,
  53. CCT_INTERVALS,
  54. value / CCT_INTERVALS,
  55. knownValue / CCT_INTERVALS
  56. );
  57. }
  58. void CctPacketFormatter::command(uint8_t command, uint8_t arg) {
  59. pushPacket();
  60. if (held) {
  61. command |= 0x80;
  62. }
  63. currentPacket[CCT_COMMAND_INDEX] = command;
  64. }
  65. void CctPacketFormatter::updateStatus(MiLightStatus status, uint8_t groupId) {
  66. command(getCctStatusButton(groupId, status), 0);
  67. }
  68. void CctPacketFormatter::increaseTemperature() {
  69. command(CCT_TEMPERATURE_UP, 0);
  70. }
  71. void CctPacketFormatter::decreaseTemperature() {
  72. command(CCT_TEMPERATURE_DOWN, 0);
  73. }
  74. void CctPacketFormatter::increaseBrightness() {
  75. command(CCT_BRIGHTNESS_UP, 0);
  76. }
  77. void CctPacketFormatter::decreaseBrightness() {
  78. command(CCT_BRIGHTNESS_DOWN, 0);
  79. }
  80. void CctPacketFormatter::enableNightMode() {
  81. command(getCctStatusButton(groupId, OFF) | 0x10, 0);
  82. }
  83. uint8_t CctPacketFormatter::getCctStatusButton(uint8_t groupId, MiLightStatus status) {
  84. uint8_t button = 0;
  85. if (status == ON) {
  86. switch(groupId) {
  87. case 0:
  88. button = CCT_ALL_ON;
  89. break;
  90. case 1:
  91. button = CCT_GROUP_1_ON;
  92. break;
  93. case 2:
  94. button = CCT_GROUP_2_ON;
  95. break;
  96. case 3:
  97. button = CCT_GROUP_3_ON;
  98. break;
  99. case 4:
  100. button = CCT_GROUP_4_ON;
  101. break;
  102. }
  103. } else {
  104. switch(groupId) {
  105. case 0:
  106. button = CCT_ALL_OFF;
  107. break;
  108. case 1:
  109. button = CCT_GROUP_1_OFF;
  110. break;
  111. case 2:
  112. button = CCT_GROUP_2_OFF;
  113. break;
  114. case 3:
  115. button = CCT_GROUP_3_OFF;
  116. break;
  117. case 4:
  118. button = CCT_GROUP_4_OFF;
  119. break;
  120. }
  121. }
  122. return button;
  123. }
  124. uint8_t CctPacketFormatter::cctCommandIdToGroup(uint8_t command) {
  125. switch (command & 0xF) {
  126. case CCT_GROUP_1_ON:
  127. case CCT_GROUP_1_OFF:
  128. return 1;
  129. case CCT_GROUP_2_ON:
  130. case CCT_GROUP_2_OFF:
  131. return 2;
  132. case CCT_GROUP_3_ON:
  133. case CCT_GROUP_3_OFF:
  134. return 3;
  135. case CCT_GROUP_4_ON:
  136. case CCT_GROUP_4_OFF:
  137. return 4;
  138. case CCT_ALL_ON:
  139. case CCT_ALL_OFF:
  140. return 0;
  141. }
  142. return 255;
  143. }
  144. MiLightStatus CctPacketFormatter::cctCommandToStatus(uint8_t command) {
  145. switch (command & 0xF) {
  146. case CCT_GROUP_1_ON:
  147. case CCT_GROUP_2_ON:
  148. case CCT_GROUP_3_ON:
  149. case CCT_GROUP_4_ON:
  150. case CCT_ALL_ON:
  151. return ON;
  152. case CCT_GROUP_1_OFF:
  153. case CCT_GROUP_2_OFF:
  154. case CCT_GROUP_3_OFF:
  155. case CCT_GROUP_4_OFF:
  156. case CCT_ALL_OFF:
  157. default:
  158. return OFF;
  159. }
  160. }
  161. BulbId CctPacketFormatter::parsePacket(const uint8_t* packet, JsonObject result) {
  162. uint8_t command = packet[CCT_COMMAND_INDEX] & 0x7F;
  163. uint8_t onOffGroupId = cctCommandIdToGroup(command);
  164. BulbId bulbId(
  165. (packet[1] << 8) | packet[2],
  166. onOffGroupId < 255 ? onOffGroupId : packet[3],
  167. REMOTE_TYPE_CCT
  168. );
  169. // Night mode
  170. if (command & 0x10) {
  171. result["command"] = "night_mode";
  172. } else if (onOffGroupId < 255) {
  173. result["state"] = cctCommandToStatus(command) == ON ? "ON" : "OFF";
  174. } else if (command == CCT_BRIGHTNESS_DOWN) {
  175. result["command"] = "brightness_down";
  176. } else if (command == CCT_BRIGHTNESS_UP) {
  177. result["command"] = "brightness_up";
  178. } else if (command == CCT_TEMPERATURE_DOWN) {
  179. result["command"] = "temperature_down";
  180. } else if (command == CCT_TEMPERATURE_UP) {
  181. result["command"] = "temperature_up";
  182. } else {
  183. result["button_id"] = command;
  184. }
  185. return bulbId;
  186. }
  187. void CctPacketFormatter::format(uint8_t const* packet, char* buffer) {
  188. PacketFormatter::formatV1Packet(packet, buffer);
  189. }