mqttRSSI_NA.ino 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. /*
  2. ESP8266/ESP32 publish the RSSI as the WiFi signal strength to ThingSpeak channel.
  3. This example is for explaining how to use the AutoConnect library.
  4. In order to execute this example, the ThingSpeak account is needed. Sing up
  5. for New User Account and create a New Channel via My Channels.
  6. For details, please refer to the project page.
  7. https://hieromon.github.io/AutoConnect/howtoembed.html#used-with-mqtt-as-a-client-application
  8. This example is based on the environment as of March 20, 2018.
  9. Copyright (c) 2020 Hieromon Ikasamo.
  10. This software is released under the MIT License.
  11. https://opensource.org/licenses/MIT
  12. */
  13. #if defined(ARDUINO_ARCH_ESP8266)
  14. #include <ESP8266WiFi.h>
  15. #include <ESP8266HTTPClient.h>
  16. #define GET_CHIPID() (ESP.getChipId())
  17. #elif defined(ARDUINO_ARCH_ESP32)
  18. #include <WiFi.h>
  19. #include <HTTPClient.h>
  20. #define GET_CHIPID() ((uint16_t)(ESP.getEfuseMac()>>32))
  21. #endif
  22. #include <PubSubClient.h>
  23. #include <AutoConnect.h>
  24. #define AUX_SETTING_URI "/mqtt_setting"
  25. #define AUX_SAVE_URI "/mqtt_save"
  26. #define AUX_CLEAR_URI "/mqtt_clear"
  27. // Adjusting WebServer class with between ESP8266 and ESP32.
  28. #if defined(ARDUINO_ARCH_ESP8266)
  29. typedef ESP8266WebServer WiFiWebServer;
  30. #elif defined(ARDUINO_ARCH_ESP32)
  31. typedef WebServer WiFiWebServer;
  32. #endif
  33. // This example shows a sketch that realizes the equivalent operation
  34. // of mqttRSSI without using JSON.
  35. // By comparing this example with the example using JSON, mqttRSSI or
  36. // mqttRSSI_FS, you will better understand AutoConnect's custom Web page
  37. // facility.
  38. // Declare AutoConnectElements for the page asf /mqtt_setting
  39. ACStyle(style, "label+input,label+select{position:sticky;left:120px;width:230px!important;box-sizing:border-box;}");
  40. ACText(header, "<h2>MQTT broker settings</h2>", "text-align:center;color:#2f4f4f;padding:10px;");
  41. ACText(caption, "Publishing the WiFi signal strength to MQTT channel. RSSI value of ESP8266 to the channel created on ThingSpeak", "font-family:serif;color:#4682b4;");
  42. ACInput(mqttserver, "", "Server", "^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9])\\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\\-]*[A-Za-z0-9])$", "MQTT broker server");
  43. ACInput(channelid, "", "Channel ID", "^[0-9]{6}$");
  44. ACInput(userkey, "", "User Key");
  45. ACInput(apikey, "", "API Key");
  46. ACElement(newline, "<hr>");
  47. ACRadio(period, { "30 sec.", "60 sec.", "180 sec." }, "Update period", AC_Vertical, 1);
  48. ACSubmit(save, "Start", AUX_SAVE_URI);
  49. ACSubmit(discard, "Discard", "/");
  50. // Declare the custom Web page as /mqtt_setting and contains the AutoConnectElements
  51. AutoConnectAux mqtt_setting(AUX_SETTING_URI, "MQTT Setting", true, {
  52. style,
  53. header,
  54. caption,
  55. mqttserver,
  56. channelid,
  57. userkey,
  58. apikey,
  59. newline,
  60. period,
  61. save,
  62. discard
  63. });
  64. // Declare AutoConnectElements for the page as /mqtt_save
  65. ACText(caption2, "<h4>Parameters available as:</h4>", "text-align:center;color:#2f4f4f;padding:10px;");
  66. ACText(parameters);
  67. ACSubmit(clear, "Clear channel", AUX_CLEAR_URI);
  68. // Declare the custom Web page as /mqtt_save and contains the AutoConnectElements
  69. AutoConnectAux mqtt_save(AUX_SAVE_URI, "MQTT Setting", false, {
  70. caption2,
  71. parameters,
  72. clear
  73. });
  74. AutoConnect portal;
  75. AutoConnectConfig config;
  76. WiFiClient wifiClient;
  77. PubSubClient mqttClient(wifiClient);
  78. unsigned int updateInterval = 0;
  79. unsigned long lastPub = 0;
  80. #define MQTT_USER_ID "anyone"
  81. bool mqttConnect() {
  82. static const char alphanum[] = "0123456789"
  83. "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  84. "abcdefghijklmnopqrstuvwxyz"; // For random generation of client ID.
  85. char clientId[9];
  86. uint8_t retry = 3;
  87. while (!mqttClient.connected()) {
  88. if (mqttserver.value.length() <= 0)
  89. break;
  90. mqttClient.setServer(mqttserver.value.c_str(), 1883);
  91. Serial.println(String("Attempting MQTT broker:") + mqttserver.value);
  92. for (uint8_t i = 0; i < 8; i++) {
  93. clientId[i] = alphanum[random(62)];
  94. }
  95. clientId[8] = '\0';
  96. if (mqttClient.connect(clientId, MQTT_USER_ID, userkey.value.c_str())) {
  97. Serial.println("Established:" + String(clientId));
  98. return true;
  99. }
  100. else {
  101. Serial.println("Connection failed:" + String(mqttClient.state()));
  102. if (!--retry)
  103. break;
  104. delay(3000);
  105. }
  106. }
  107. return false;
  108. }
  109. void mqttPublish(String msg) {
  110. String path = String("channels/") + channelid.value + String("/publish/") + apikey.value;
  111. mqttClient.publish(path.c_str(), msg.c_str());
  112. }
  113. int getStrength(uint8_t points) {
  114. uint8_t sc = points;
  115. long rssi = 0;
  116. while (sc--) {
  117. rssi += WiFi.RSSI();
  118. delay(20);
  119. }
  120. return points ? static_cast<int>(rssi / points) : 0;
  121. }
  122. // Retreive the value of each element entered by '/mqtt_setting'.
  123. String saveParams(AutoConnectAux& aux, PageArgument& args) {
  124. mqttserver.value.trim();
  125. channelid.value.trim();
  126. userkey.value.trim();
  127. apikey.value.trim();
  128. updateInterval = period.value().substring(0, 2).toInt() * 1000;
  129. // Echo back saved parameters to AutoConnectAux page.
  130. String echo = "Server: " + mqttserver.value + "<br>";
  131. echo += "Channel ID: " + channelid.value + "<br>";
  132. echo += "User Key: " + userkey.value + "<br>";
  133. echo += "API Key: " + apikey.value + "<br>";
  134. echo += "Update period: " + String(updateInterval / 1000) + " sec.<br>";
  135. parameters.value = echo;
  136. return String("");
  137. }
  138. void handleRoot() {
  139. String content =
  140. "<html>"
  141. "<head>"
  142. "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"
  143. "</head>"
  144. "<body>"
  145. "<iframe width=\"450\" height=\"260\" style=\"transform:scale(0.79);-o-transform:scale(0.79);-webkit-transform:scale(0.79);-moz-transform:scale(0.79);-ms-transform:scale(0.79);transform-origin:0 0;-o-transform-origin:0 0;-webkit-transform-origin:0 0;-moz-transform-origin:0 0;-ms-transform-origin:0 0;border: 1px solid #cccccc;\" src=\"https://thingspeak.com/channels/{{CHANNEL}}/charts/1?bgcolor=%23ffffff&color=%23d62020&dynamic=true&type=line\"></iframe>"
  146. "<p style=\"padding-top:5px;text-align:center\">" AUTOCONNECT_LINK(COG_24) "</p>"
  147. "</body>"
  148. "</html>";
  149. content.replace("{{CHANNEL}}", channelid.value);
  150. WiFiWebServer& webServer = portal.host();
  151. webServer.send(200, "text/html", content);
  152. }
  153. // Clear channel using ThingSpeak's API.
  154. void handleClearChannel() {
  155. HTTPClient httpClient;
  156. String endpoint = mqttserver.value;
  157. endpoint.replace("mqtt", "api");
  158. String delUrl = "http://" + endpoint + "/channels/" + channelid.value + "/feeds.json?api_key=" + userkey.value;
  159. Serial.print("DELETE " + delUrl);
  160. if (httpClient.begin(wifiClient, delUrl)) {
  161. Serial.print(":");
  162. int resCode = httpClient.sendRequest("DELETE");
  163. const String& res = httpClient.getString();
  164. Serial.println(String(resCode) + String(",") + res);
  165. httpClient.end();
  166. }
  167. else
  168. Serial.println(" failed");
  169. // Returns the redirect response. The page is reloaded and its contents
  170. // are updated to the state after deletion.
  171. WiFiWebServer& webServer = portal.host();
  172. webServer.sendHeader("Location", String("http://") + webServer.client().localIP().toString() + String("/"));
  173. webServer.send(302, "text/plain", "");
  174. webServer.client().flush();
  175. webServer.client().stop();
  176. }
  177. void setup() {
  178. delay(1000);
  179. Serial.begin(115200);
  180. Serial.println();
  181. // Reconnect and continue publishing even if WiFi is disconnected.
  182. config.homeUri = "/";
  183. config.autoReconnect = true;
  184. config.reconnectInterval = 1;
  185. portal.config(config);
  186. // Join the custom Web pages and register /mqtt_save handler
  187. portal.join({ mqtt_setting, mqtt_save });
  188. portal.on(AUX_SAVE_URI, saveParams);
  189. Serial.print("WiFi ");
  190. if (portal.begin()) {
  191. config.bootUri = AC_ONBOOTURI_HOME;
  192. Serial.println("connected:" + WiFi.SSID());
  193. Serial.println("IP:" + WiFi.localIP().toString());
  194. }
  195. else {
  196. Serial.println("connection failed:" + String(WiFi.status()));
  197. Serial.println("Needs WiFi connection to start publishing messages");
  198. }
  199. WiFiWebServer& webServer = portal.host();
  200. webServer.on("/", handleRoot);
  201. webServer.on(AUX_CLEAR_URI, handleClearChannel);
  202. }
  203. void loop() {
  204. if (WiFi.status() == WL_CONNECTED) {
  205. // MQTT publish control
  206. if (updateInterval > 0) {
  207. if (millis() - lastPub > updateInterval) {
  208. if (!mqttClient.connected()) {
  209. mqttConnect();
  210. }
  211. String item = String("field1=") + String(getStrength(7));
  212. mqttPublish(item);
  213. mqttClient.loop();
  214. lastPub = millis();
  215. }
  216. }
  217. }
  218. portal.handleClient();
  219. }