Fork of the espurna firmware for `mhsw` switches
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
6.0 KiB

  1. /*
  2. THINGSPEAK MODULE
  3. Copyright (C) 2018 by Xose Pérez <xose dot perez at gmail dot com>
  4. */
  5. #if THINGSPEAK_SUPPORT
  6. #if THINGSPEAK_USE_ASYNC
  7. #include <ESPAsyncTCP.h>
  8. AsyncClient _tspk_client;
  9. const char THINGSPEAK_REQUEST_TEMPLATE[] PROGMEM =
  10. "POST %s HTTP/1.1\r\n"
  11. "Host: %s\r\n"
  12. "User-Agent: ESPurna\r\n"
  13. "Connection: close\r\n"
  14. "Content-Type: application/x-www-form-urlencoded\r\n"
  15. "Content-Length: %d\r\n\r\n"
  16. "%s\r\n";
  17. #else
  18. #include <ESP8266WiFi.h>
  19. #if THINGSPEAK_USE_SSL
  20. WiFiClientSecure _tspk_client;
  21. #else
  22. WiFiClient _tspk_client;
  23. #endif
  24. #endif
  25. bool _tspk_enabled = false;
  26. char * _tspk_queue[8] = {NULL};
  27. // -----------------------------------------------------------------------------
  28. void _tspkWebSocketOnSend(JsonObject& root) {
  29. root["tspkVisible"] = 1;
  30. root["tspkEnabled"] = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
  31. JsonArray& relays = root.createNestedArray("tspkRelays");
  32. for (byte i=0; i<relayCount(); i++) {
  33. relays.add(getSetting("tspkRelay", i, 0).toInt());
  34. }
  35. #if SENSOR_SUPPORT
  36. JsonArray& list = root.createNestedArray("tspkMagnitudes");
  37. for (byte i=0; i<magnitudeCount(); i++) {
  38. JsonObject& element = list.createNestedObject();
  39. element["name"] = magnitudeName(i);
  40. element["type"] = magnitudeType(i);
  41. element["index"] = magnitudeIndex(i);
  42. element["idx"] = getSetting("tspkMagnitude", i, 0).toInt();
  43. }
  44. #endif
  45. }
  46. void _tspkConfigure() {
  47. _tspk_enabled = getSetting("tspkEnabled", THINGSPEAK_ENABLED).toInt() == 1;
  48. if (_tspk_enabled && (getSetting("tspkKey").length() == 0)) {
  49. _tspk_enabled = false;
  50. setSetting("tspkEnabled", 0);
  51. }
  52. }
  53. #if THINGSPEAK_USE_ASYNC
  54. bool _tspkPost(String data) {
  55. _tspk_client.onError([](void * arg, AsyncClient * client, int error) {
  56. DEBUG_MSG("[THINGSPEAK] Connection error (%d)\n", error);
  57. _tspk_client = NULL;
  58. }, NULL);
  59. _tspk_client.onConnect([data](void * arg, AsyncClient * client) {
  60. DEBUG_MSG("[THINGSPEAK] POST %s\n", data.c_str());
  61. client->onData([](void * arg, AsyncClient * c, void * response, size_t len) {
  62. char * b = (char *) response;
  63. b[len] = 0;
  64. Serial.println(b);
  65. char * p = strstr((char *)response, "\r\n\r\n");
  66. unsigned int code = (p != NULL) ? atoi(&p[4]) : 0;
  67. DEBUG_MSG("[THINGSPEAK] Response value: %d\n", code);
  68. }, NULL);
  69. char buffer[strlen_P(THINGSPEAK_REQUEST_TEMPLATE) + strlen(THINGSPEAK_URL) + strlen(THINGSPEAK_HOST) + data.length()];
  70. snprintf_P(buffer, sizeof(buffer),
  71. THINGSPEAK_REQUEST_TEMPLATE,
  72. THINGSPEAK_URL,
  73. THINGSPEAK_HOST,
  74. data.length(),
  75. data.c_str()
  76. );
  77. client->write(buffer);
  78. }, NULL);
  79. #if ASYNC_TCP_SSL_ENABLED
  80. if (!_tspk_client.connect(THINGSPEAK_HOST, THINGSPEAK_PORT, THINGSPEAK_USE_SSL)) {
  81. #else
  82. if (!_tspk_client.connect(THINGSPEAK_HOST, THINGSPEAK_PORT)) {
  83. #endif
  84. DEBUG_MSG("[THINGSPEAK] Connection failed\n");
  85. }
  86. }
  87. #else
  88. bool _tspkPost(String data) {
  89. if (_tspk_client.connect(THINGSPEAK_HOST, THINGSPEAK_PORT)) {
  90. DEBUG_MSG("[THINGSPEAK] POST %s\n", data.c_str());
  91. _tspk_client.println("POST " + String(THINGSPEAK_URL) + " HTTP/1.1");
  92. _tspk_client.println("Host: " + String(THINGSPEAK_HOST));
  93. _tspk_client.println("User-Agent: ESPurna");
  94. _tspk_client.println("Connection: close");
  95. _tspk_client.println("Content-Type: application/x-www-form-urlencoded");
  96. _tspk_client.print("Content-Length: ");
  97. _tspk_client.println(data.length());
  98. _tspk_client.println();
  99. _tspk_client.println(data);
  100. _tspk_client.println();
  101. delay(10);
  102. String response = _tspk_client.readString();
  103. int pos = response.indexOf("\r\n\r\n");
  104. unsigned int code = (pos > 0) ? response.substring(pos + 4).toInt() : 0;
  105. DEBUG_MSG("[THINGSPEAK] Response value: %d\n", code);
  106. _tspk_client.stop();
  107. return (code > 0);
  108. }
  109. DEBUG_MSG("[THINGSPEAK] Connection failed\n");
  110. return false;
  111. }
  112. #endif
  113. bool _tspkEnqueue(unsigned char index, char * payload) {
  114. DEBUG_MSG("[THINGSPEAK] Enqueuing field #%d with value %s\n", index, payload);
  115. --index;
  116. if (_tspk_queue[index] != NULL) free(_tspk_queue[index]);
  117. _tspk_queue[index] = strdup(payload);
  118. }
  119. // -----------------------------------------------------------------------------
  120. bool tspkEnqueueRelay(unsigned char index, unsigned char status) {
  121. if (!_tspk_enabled) return true;
  122. unsigned char id = getSetting("tspkRelay", index, 0).toInt();
  123. if (id > 0) {
  124. char payload[3];
  125. itoa(status ? 1 : 0, payload, 10);
  126. _tspkEnqueue(id, payload);
  127. }
  128. }
  129. bool tspkEnqueueMeasurement(unsigned char index, char * payload) {
  130. if (!_tspk_enabled) return true;
  131. unsigned char id = getSetting("tspkMagnitude", index, 0).toInt();
  132. if (id > 0) {
  133. _tspkEnqueue(id, payload);
  134. }
  135. }
  136. bool tspkFlush() {
  137. if (!_tspk_enabled) return true;
  138. if (!wifiConnected() || (WiFi.getMode() != WIFI_STA)) return true;
  139. String data;
  140. // Walk the fields
  141. for (unsigned char id=0; id<8; id++) {
  142. if (_tspk_queue[id] != NULL) {
  143. if (data.length() > 0) data = data + String("&");
  144. data = data + String("field") + String(id+1) + String("=") + String(_tspk_queue[id]);
  145. free(_tspk_queue[id]);
  146. _tspk_queue[id] = NULL;
  147. }
  148. }
  149. // POST data if any
  150. if (data.length() > 0) {
  151. data = data + String("&api_key=") + getSetting("tspkKey");
  152. _tspkPost(data);
  153. }
  154. }
  155. bool tspkEnabled() {
  156. return _tspk_enabled;
  157. }
  158. void tspkSetup() {
  159. _tspkConfigure();
  160. #if WEB_SUPPORT
  161. wsOnSendRegister(_tspkWebSocketOnSend);
  162. wsOnAfterParseRegister(_tspkConfigure);
  163. #endif
  164. }
  165. #endif