MiLightClient.cpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. for (int i = 0; i < resendCount; i++) {
  39. radio.write(packetBytes, MILIGHT_PACKET_LENGTH);
  40. }
  41. }
  42. void MiLightClient::write(
  43. const uint16_t deviceId,
  44. const uint16_t color,
  45. const uint8_t brightness,
  46. const uint8_t groupId,
  47. const MiLightButton button) {
  48. // Expect an input value in [0, 100]. Map it down to [0, 25].
  49. const uint8_t adjustedBrightness = round(brightness * (25 / 100.0));
  50. // The actual protocol uses a bizarre range where min is 16, max is 23:
  51. // [16, 15, ..., 0, 31, ..., 23]
  52. const uint8_t packetBrightnessValue = (
  53. ((31 - adjustedBrightness) + 17) % 32
  54. );
  55. // Map color as a Hue value in [0, 359] to [0, 255]. The protocol also has
  56. // 0 being roughly magenta (#FF00FF)
  57. const int16_t remappedColor = (color + 40) % 360;
  58. const uint8_t adjustedColor = round(remappedColor * (255 / 359.0));
  59. MiLightPacket packet;
  60. packet.deviceType = MiLightDeviceType::RGBW;
  61. packet.deviceId = deviceId;
  62. packet.color = adjustedColor;
  63. packet.brightness = packetBrightnessValue;
  64. packet.groupId = groupId;
  65. packet.button = button;
  66. packet.sequenceNum = nextSequenceNum();
  67. write(packet);
  68. }
  69. void MiLightClient::updateColor(const uint16_t deviceId, const uint8_t groupId, const uint16_t hue) {
  70. write(deviceId, hue, 0, groupId, COLOR);
  71. }
  72. void MiLightClient::updateBrightness(const uint16_t deviceId, const uint8_t groupId, const uint8_t brightness) {
  73. write(deviceId, 0, brightness, groupId, BRIGHTNESS);
  74. }
  75. void MiLightClient::updateStatus(const uint16_t deviceId, const uint8_t groupId, MiLightStatus status) {
  76. uint8_t button = MiLightButton::GROUP_1_ON + ((groupId - 1)*2) + status;
  77. write(deviceId, 0, 0, groupId, static_cast<MiLightButton>(button));
  78. }
  79. void MiLightClient::updateColorWhite(const uint16_t deviceId, const uint8_t groupId) {
  80. uint8_t button = MiLightButton::GROUP_1_MAX_LEVEL + ((groupId - 1)*2);
  81. pressButton(deviceId, groupId, static_cast<MiLightButton>(button));
  82. }
  83. void MiLightClient::pair(const uint16_t deviceId, const uint8_t groupId) {
  84. updateStatus(deviceId, groupId, ON);
  85. }
  86. void MiLightClient::unpair(const uint16_t deviceId, const uint8_t groupId) {
  87. updateStatus(deviceId, groupId, ON);
  88. delay(1);
  89. updateColorWhite(deviceId, groupId);
  90. }
  91. void MiLightClient::pressButton(const uint16_t deviceId, const uint8_t groupId, MiLightButton button) {
  92. write(deviceId, 0, 0, groupId, button);
  93. }
  94. void MiLightClient::allOn(const uint16_t deviceId) {
  95. write(deviceId, 0, 0, 0, ALL_ON);
  96. }
  97. void MiLightClient::allOff(const uint16_t deviceId) {
  98. write(deviceId, 0, 0, 0, ALL_OFF);
  99. }