V6MiLightUdpServer.cpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. #include <V6MiLightUdpServer.h>
  2. #include <ESP8266WiFi.h>
  3. uint8_t V6MiLightUdpServer::START_SESSION_COMMAND[] = {
  4. 0x20, 0x00, 0x00, 0x00, 0x16, 0x02, 0x62, 0x3A, 0xD5, 0xED, 0xA3, 0x01, 0xAE,
  5. 0x08, 0x2D, 0x46, 0x61, 0x41, 0xA7, 0xF6, 0xDC, 0xAF, 0xD3, 0xE6, 0x00, 0x00,
  6. 0x1E
  7. };
  8. uint8_t V6MiLightUdpServer::START_SESSION_RESPONSE[] = {
  9. 0x28, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02,
  10. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // should be replaced with hw addr
  11. 0x69, 0xF0, 0x3C, 0x23, 0x00, 0x01,
  12. 0xFF, 0xFF, // should be replaced with a session ID
  13. 0x00
  14. };
  15. uint8_t V6MiLightUdpServer::COMMAND_HEADER[] = {
  16. 0x80, 0x00, 0x00, 0x00
  17. };
  18. template<typename T, size_t sz>
  19. size_t size(T(&)[sz]) {
  20. return sz;
  21. }
  22. template <typename T>
  23. T V6MiLightUdpServer::readInt(uint8_t* packet) {
  24. size_t numBytes = sizeof(T);
  25. T value = 0;
  26. for (size_t i = 0; i < numBytes; i++) {
  27. value |= packet[i] << (8 * (numBytes - i - 1));
  28. }
  29. return value;
  30. }
  31. template <typename T>
  32. uint8_t* V6MiLightUdpServer::writeInt(const T& value, uint8_t* packet) {
  33. size_t numBytes = sizeof(T);
  34. for (size_t i = 0; i < numBytes; i++) {
  35. packet[i] = (value >> (8 * (numBytes - i - 1))) & 0xFF;
  36. }
  37. return packet + numBytes;
  38. }
  39. uint16_t V6MiLightUdpServer::beginSession() {
  40. const uint16_t id = sessionId++;
  41. V6Session session(socket.remoteIP(), socket.remotePort(), id);
  42. sessions.push_back(session);
  43. return id;
  44. }
  45. void V6MiLightUdpServer::handleStartSession() {
  46. size_t len = size(START_SESSION_RESPONSE);
  47. uint8_t response[len];
  48. uint16_t sessionId = beginSession();
  49. memcpy(response, START_SESSION_RESPONSE, len);
  50. WiFi.macAddress(response + 7);
  51. response[19] = sessionId >> 8;
  52. response[20] = sessionId & 0xFF;
  53. sendResponse(sessionId, response, len);
  54. }
  55. void V6MiLightUdpServer::sendResponse(uint16_t sessionId, uint8_t* responseBuffer, size_t responseSize) {
  56. V6Session* session = NULL;
  57. for (size_t i = 0; i < sessions.size(); i++) {
  58. if (sessions[i].sessionId == sessionId) {
  59. session = &sessions[i];
  60. }
  61. }
  62. if (session == NULL) {
  63. Serial.print("Tried to send response to untracked session id: ");
  64. Serial.println(sessionId);
  65. }
  66. Serial.println("Sending a response!");
  67. Serial.print("IP: ");
  68. Serial.println(session->ipAddr.toString());
  69. Serial.print("Port: ");
  70. Serial.println(session->port);
  71. socket.beginPacket(session->ipAddr, session->port);
  72. socket.write(responseBuffer, responseSize);
  73. socket.endPacket();
  74. }
  75. bool V6MiLightUdpServer::handleV1BulbCommand(uint8_t group, uint32_t _cmd, uint32_t _arg) {
  76. }
  77. bool V6MiLightUdpServer::handleV2BulbCommand(uint8_t group, uint32_t _cmd, uint32_t _arg) {
  78. const uint8_t cmd = _cmd & 0xFF;
  79. const uint8_t arg = _arg >> 24;
  80. client->prepare(MilightRgbCctConfig, deviceId, group);
  81. switch (cmd) {
  82. case V2_STATUS:
  83. if (arg == 0x01) {
  84. client->updateStatus(ON);
  85. } else if (arg == 0x02) {
  86. client->updateStatus(OFF);
  87. } else if (arg == 0x05) {
  88. client->updateBrightness(0);
  89. }
  90. break;
  91. case V2_COLOR:
  92. client->updateColorRaw(arg);
  93. break;
  94. case V2_KELVIN:
  95. client->updateTemperature(arg);
  96. break;
  97. case V2_BRIGHTNESS:
  98. client->updateBrightness(arg);
  99. break;
  100. case V2_SATURATION:
  101. client->updateSaturation(arg);
  102. break;
  103. default:
  104. return false;
  105. }
  106. return true;
  107. }
  108. void V6MiLightUdpServer::handleCommand(
  109. uint16_t sessionId,
  110. uint8_t sequenceNum,
  111. uint8_t* cmd,
  112. uint8_t group,
  113. uint8_t checksum
  114. ) {
  115. uint8_t cmdType = readInt<uint8_t>(cmd);
  116. uint32_t cmdHeader = readInt<uint32_t>(cmd+1);
  117. uint32_t cmdArg = readInt<uint32_t>(cmd+5);
  118. #ifdef MILIGHT_UDP_DEBUG
  119. printf("Command type: %02X, command: %08X, arg: %08X\n", cmdType, cmdHeader, cmdArg);
  120. #endif
  121. bool handled = false;
  122. if ((cmdHeader & 0x0800) == 0x0800) {
  123. printf("Yup.\n");
  124. handled = handleV2BulbCommand(group, cmdHeader, cmdArg);
  125. } else if ((cmdHeader & 0x0700) == 0x0700) {
  126. handled = handleV1BulbCommand(group, cmdHeader, cmdArg);
  127. }
  128. if (handled) {
  129. uint8_t* responsePacket = this->responseBuffer;
  130. uint8_t* packetStart = responseBuffer;
  131. responsePacket = writeInt<uint32_t>(0x88000000, responsePacket);
  132. responsePacket = writeInt<uint16_t>(0x0300, responsePacket);
  133. responsePacket = writeInt<uint8_t>(sequenceNum, responsePacket);
  134. responsePacket = writeInt<uint8_t>(0, responsePacket);
  135. sendResponse(sessionId, packetStart, responsePacket - packetStart);
  136. return;
  137. }
  138. #ifdef MILIGHT_UDP_DEBUG
  139. printf("V6MiLightUdpServer - Unhandled command: ");
  140. for (size_t i = 0; i < V6_COMMAND_LEN; i++) {
  141. printf("%02X ", cmd[i]);
  142. }
  143. printf("\n");
  144. #endif
  145. }
  146. void V6MiLightUdpServer::handlePacket(uint8_t* packet, size_t packetSize) {
  147. printf("Packet size: %d\n", packetSize);
  148. if (packetSize == size(START_SESSION_COMMAND) && memcmp(START_SESSION_COMMAND, packet, packetSize) == 0) {
  149. handleStartSession();
  150. } else if (packetSize == 22 && memcmp(COMMAND_HEADER, packet, size(COMMAND_HEADER)) == 0) {
  151. uint16_t sessionId = (packet[5] << 8) | packet[6];
  152. uint8_t sequenceNum = packet[8];
  153. uint8_t* cmd = packet+10;
  154. uint8_t group = packet[19];
  155. uint8_t checksum = packet[21];
  156. #ifdef MILIGHT_UDP_DEBUG
  157. printf("session: %04X, sequence: %d, group: %d, checksum: %d\n", sessionId, sequenceNum, group, checksum);
  158. #endif
  159. handleCommand(sessionId, sequenceNum, cmd, group, checksum);
  160. } else {
  161. Serial.println("Unhandled V6 packet");
  162. }
  163. }