MiLightClient.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #include <MiLightClient.h>
  2. void MiLightClient::deserializePacket(const uint8_t rawPacket[], MiLightPacket& packet) {
  3. uint8_t ptr = 0;
  4. packet.deviceType = rawPacket[ptr++];
  5. packet.deviceId = (rawPacket[ptr++] << 8) | rawPacket[ptr++];
  6. packet.color = rawPacket[ptr++];
  7. packet.brightness = rawPacket[ptr] >> 3;
  8. packet.groupId = rawPacket[ptr++] & 0x07;
  9. packet.button = rawPacket[ptr++];
  10. packet.sequenceNum = rawPacket[ptr++];
  11. }
  12. void MiLightClient::serializePacket(uint8_t rawPacket[], const MiLightPacket& packet) {
  13. uint8_t ptr = 0;
  14. rawPacket[ptr++] = packet.deviceType;
  15. // big endian
  16. rawPacket[ptr++] = packet.deviceId >> 8;
  17. rawPacket[ptr++] = packet.deviceId & 0xFF;
  18. rawPacket[ptr++] = packet.color;
  19. rawPacket[ptr++] = (packet.brightness << 3) | (packet.groupId & 0x07);
  20. rawPacket[ptr++] = packet.button;
  21. rawPacket[ptr++] = packet.sequenceNum;
  22. }
  23. uint8_t MiLightClient::nextSequenceNum() {
  24. return sequenceNum++;
  25. }
  26. bool MiLightClient::available() {
  27. return radio.available();
  28. }
  29. void MiLightClient::read(MiLightPacket& packet) {
  30. uint8_t packetBytes[MILIGHT_PACKET_LENGTH];
  31. size_t length;
  32. radio.read(packetBytes, length);
  33. deserializePacket(packetBytes, packet);
  34. }
  35. void MiLightClient::write(MiLightPacket& packet, const unsigned int resendCount) {
  36. uint8_t packetBytes[MILIGHT_PACKET_LENGTH];
  37. serializePacket(packetBytes, packet);
  38. Serial.print("Packet bytes (");
  39. Serial.print(MILIGHT_PACKET_LENGTH);
  40. Serial.print(" bytes): ");
  41. for (int i = 0; i < MILIGHT_PACKET_LENGTH; i++) {
  42. Serial.print(packetBytes[i], HEX);
  43. Serial.print(" ");
  44. }
  45. Serial.println();
  46. for (int i = 0; i < resendCount; i++) {
  47. Serial.print(".");
  48. radio.write(packetBytes, MILIGHT_PACKET_LENGTH);
  49. }
  50. Serial.println();
  51. }
  52. void MiLightClient::write(
  53. const uint16_t deviceId,
  54. const uint16_t color,
  55. const uint8_t brightness,
  56. const uint8_t groupId,
  57. const MiLightButton button) {
  58. // Expect an input value in [0, 255]. Map it down to [0, 25].
  59. const uint8_t adjustedBrightness = round(brightness * (25 / 255.0));
  60. // The actual protocol uses a bizarre range where min is 16, max is 23:
  61. // [16, 15, ..., 0, 31, ..., 23]
  62. const uint8_t packetBrightnessValue = (
  63. ((31 - adjustedBrightness) + 17) % 32
  64. );
  65. // Map color as a Hue value in [0, 359] to [0, 255]. The protocol also has
  66. // 0 being roughly magenta (#FF00FF)
  67. const int16_t remappedColor = (color + 40) % 360;
  68. const uint8_t adjustedColor = round(remappedColor * (255 / 359.0));
  69. MiLightPacket packet;
  70. packet.deviceType = MiLightDeviceType::RGBW;
  71. packet.deviceId = deviceId;
  72. packet.color = adjustedColor;
  73. packet.brightness = packetBrightnessValue;
  74. packet.groupId = groupId;
  75. packet.button = button;
  76. packet.sequenceNum = nextSequenceNum();
  77. write(packet);
  78. }
  79. void MiLightClient::updateColor(const uint16_t deviceId, const uint8_t groupId, const uint16_t hue) {
  80. write(deviceId, hue, 0, groupId, COLOR);
  81. }
  82. void MiLightClient::updateBrightness(const uint16_t deviceId, const uint8_t groupId, const uint8_t brightness) {
  83. write(deviceId, 0, brightness, groupId, BRIGHTNESS);
  84. }
  85. void MiLightClient::updateStatus(const uint16_t deviceId, const uint8_t groupId, MiLightStatus status) {
  86. uint8_t button = MiLightButton::GROUP_1_ON + ((groupId - 1)*2) + status;
  87. write(deviceId, 0, 0, groupId, static_cast<MiLightButton>(button));
  88. }
  89. void MiLightClient::updateColorWhite(const uint16_t deviceId, const uint8_t groupId) {
  90. uint8_t button = MiLightButton::GROUP_1_MAX_LEVEL + ((groupId - 1)*2);
  91. pressButton(deviceId, groupId, static_cast<MiLightButton>(button));
  92. }
  93. void MiLightClient::pair(const uint16_t deviceId, const uint8_t groupId) {
  94. updateStatus(deviceId, groupId, ON);
  95. }
  96. void MiLightClient::unpair(const uint16_t deviceId, const uint8_t groupId) {
  97. updateStatus(deviceId, groupId, ON);
  98. delay(1);
  99. updateColorWhite(deviceId, groupId);
  100. }
  101. void MiLightClient::pressButton(const uint16_t deviceId, const uint8_t groupId, MiLightButton button) {
  102. write(deviceId, 0, 0, groupId, button);
  103. }
  104. void MiLightClient::allOn(const uint16_t deviceId) {
  105. write(deviceId, 0, 0, 0, ALL_ON);
  106. }
  107. void MiLightClient::allOff(const uint16_t deviceId) {
  108. write(deviceId, 0, 0, 0, ALL_OFF);
  109. }