├── examples ├── .DS_Store └── GettingStarted │ ├── basicUse │ └── basicUse.ino │ ├── OTA │ └── OTA.ino │ ├── wifiCallback │ └── wifiCallback.ino │ ├── basicUserPass │ └── basicUserPass.ino │ ├── Adafruit_IO │ └── Adafruit_IO.ino │ ├── relayControl │ └── relayControl.ino │ ├── buttonDemo │ └── buttonDemo.ino │ └── RelayControlV2 │ └── RelayControlV2.ino ├── library.json ├── library.properties ├── README.md ├── keywords.txt ├── src ├── ESPHelper32WebConfig.h ├── ESPHelper32FS.h ├── sharedData.h ├── ESPHelper32.h ├── ESPHelper32WebConfig.cpp ├── ESPHelper32FS.cpp └── ESPHelper32.cpp └── LICENSE /examples/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ItKindaWorks/ESPHelper32/master/examples/.DS_Store -------------------------------------------------------------------------------- /library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ESPHelper32", 3 | "authors": 4 | { 5 | "name": "ItKindaWorks", 6 | "email": "itkindaworksinc@gmail.com", 7 | "url": "http://itkindaworks.com" 8 | }, 9 | "repository": 10 | { 11 | "type": "git", 12 | "url": "https://github.com/ItKindaWorks/ESPHelper32" 13 | }, 14 | "license": "GPL-3.0-or-later", 15 | "keywords": "mqtt, iot, esp32", 16 | "description": "A library to make using WiFi & MQTT on ESP32 based platforms easy.", 17 | "version": "0.9.1", 18 | "examples": "examples/*/*.ino", 19 | "frameworks": "arduino", 20 | "platforms": [ 21 | "espressif32" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=ESPHelper32 2 | version=0.9.1 3 | author=It Kinda Works 4 | maintainer=It Kinda Works 5 | sentence=A library to make using WiFi & MQTT on ESP32 based platforms easy. 6 | paragraph=This library makes creating MQTT sketches easier on the ESP32 as it abstracts a lot of the connection and MQTT handling away from the user so they only have to run a single function to handle automatic connection to both WiFi & MQTT and handles resubscribing to topics when the connection is lost. This library also supports auto hopping between known networks and OTA updating 7 | category=Communication 8 | url=http://github.com/ItKindaWorks/ESPHelper32 9 | architectures=esp32 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESPHelper32 2 | ### This project has been merged with https://github.com/ItKindaWorks/ESPHelper ### 3 | Please use that library instead as this code is no longer being maintained 4 | 5 | 6 | A library to make using WiFi and MQTT on the ESP32 easy. 7 | 8 | This is a port of the ESPHelper library originally written for the ESP8266. For more information, 9 | check out that library [here](https://github.com/ItKindaWorks/ESPHelper) 10 | 11 | The library also features the ability to use the ArduinoOTA system for OTA updates. There are a number of wrapper 12 | methods for enabling/disabling OTA and changing the OTA hostname and password. 13 | 14 | Please take a look at the examples included with this library to get an idea of how it works. 15 | 16 | Note: 17 | ----- 18 | This library does requre the use of these libraries (so make sure they're installed as well!): 19 | * 20 | [Metro](https://www.pjrc.com/teensy/td_libs_Metro.html) 21 | * 22 | [pubsubclient](https://github.com/knolleary/pubsubclient) 23 | 24 | In addition to those libraries, make sure that you have the ESP32 core installed. That can be found [here](https://github.com/espressif/arduino-esp32) 25 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For ESPHelper 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | ESPHelper32 KEYWORD1 10 | ESPHelper32FS KEYWORD1 11 | ESPHelper32WebConfig KEYWORD1 12 | netInfo KEYWORD1 13 | subscription KEYWORD1 14 | 15 | ####################################### 16 | # Methods and Functions (KEYWORD2) 17 | ####################################### 18 | 19 | begin KEYWORD2 20 | end KEYWORD2 21 | broadcastMode KEYWORD2 22 | disableBroadcast KEYWORD2 23 | loop KEYWORD2 24 | subscribe KEYWORD2 25 | addSubscription KEYWORD2 26 | removeSubscription KEYWORD2 27 | unsubscribe KEYWORD2 28 | publish KEYWORD2 29 | setCallback KEYWORD2 30 | setMQTTCallback KEYWORD2 31 | setWifiCallback KEYWORD2 32 | reconnect KEYWORD2 33 | updateNetwork KEYWORD2 34 | getSSID KEYWORD2 35 | setSSID KEYWORD2 36 | getPASS KEYWORD2 37 | setPass KEYWORD2 38 | getMQTTIP KEYWORD2 39 | setMQTTIP KEYWORD2 40 | getMQTTQOS KEYWORD2 41 | setMQTTQOS KEYWORD2 42 | setWill KEYWORD2 43 | getIP KEYWORD2 44 | getIPAddress KEYWORD2 45 | getNetInfo KEYWORD2 46 | setNetInfo KEYWORD2 47 | setHopping KEYWORD2 48 | listSubscriptions 49 | OTA_enable KEYWORD2 50 | OTA_disable KEYWORD2 51 | OTA_begin KEYWORD2 52 | OTA_setPassword KEYWORD2 53 | OTA_setHostname KEYWORD2 54 | OTA_setHostnameWithVersion KEYWORD2 55 | 56 | ####################################### 57 | # Constants (LITERAL1) 58 | ####################################### 59 | 60 | MAX_SUBSCRIPTIONS LITERAL1 61 | DEFAULT_QOS LITERAL1 62 | VERSION LITERAL1 63 | -------------------------------------------------------------------------------- /examples/GettingStarted/basicUse/basicUse.ino: -------------------------------------------------------------------------------- 1 | /* 2 | basicUse.ino 3 | Copyright (c) 2018 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | #include "ESPHelper32.h" 23 | 24 | //defualt net info for unconfigured devices 25 | netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT 26 | .mqttUser = "YOUR MQTT USERNAME", //can be blank 27 | .mqttPass = "YOUR MQTT PASSWORD", //can be blank 28 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 29 | .ssid = "YOUR SSID", 30 | .pass = "YOUR NETWORK PASS", 31 | .otaPassword = "YOUR OTA PASS", 32 | .hostname = "NEW-ESP8266"}; 33 | 34 | ESPHelper32 myESP(&homeNet); 35 | 36 | void setup() { 37 | 38 | Serial.begin(115200); //start the serial line 39 | delay(500); 40 | 41 | Serial.println("Starting Up, Please Wait..."); 42 | 43 | myESP.addSubscription("/test"); 44 | 45 | myESP.setMQTTCallback(callback); 46 | myESP.begin(); 47 | 48 | Serial.println("Initialization Finished."); 49 | } 50 | 51 | void loop(){ 52 | myESP.loop(); //run the loop() method as often as possible - this keeps the network services running 53 | 54 | //Put application code here 55 | 56 | yield(); 57 | } 58 | 59 | void callback(char* topic, uint8_t* payload, unsigned int length) { 60 | //put mqtt callback code here 61 | } -------------------------------------------------------------------------------- /examples/GettingStarted/OTA/OTA.ino: -------------------------------------------------------------------------------- 1 | /* 2 | OTA.ino 3 | Copyright (c) 2018 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | #include "ESPHelper32.h" 23 | 24 | netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT 25 | .mqttUser = "YOUR MQTT USERNAME", //can be blank 26 | .mqttPass = "YOUR MQTT PASSWORD", //can be blank 27 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 28 | .ssid = "YOUR SSID", 29 | .pass = "YOUR NETWORK PASS", 30 | .otaPassword = "YOUR OTA PASS", 31 | .hostname = "NEW-ESP8266"}; 32 | 33 | ESPHelper32 myESP(&homeNet); 34 | 35 | void setup() { 36 | 37 | Serial.begin(115200); //start the serial line 38 | delay(500); 39 | 40 | Serial.println("Starting Up, Please Wait..."); 41 | 42 | myESP.OTA_enable(); 43 | myESP.OTA_setPassword(homeNet.otaPassword); 44 | myESP.OTA_setHostnameWithVersion(homeNet.hostname); 45 | 46 | myESP.addSubscription("/test"); 47 | 48 | myESP.setMQTTCallback(callback); 49 | myESP.begin(); 50 | 51 | Serial.println("Initialization Finished."); 52 | } 53 | 54 | void loop(){ 55 | myESP.loop(); //run the loop() method as often as possible - this keeps the network services running 56 | 57 | //Put application code here 58 | 59 | yield(); 60 | } 61 | 62 | void callback(char* topic, uint8_t* payload, unsigned int length) { 63 | //put mqtt callback code here 64 | } -------------------------------------------------------------------------------- /examples/GettingStarted/wifiCallback/wifiCallback.ino: -------------------------------------------------------------------------------- 1 | /* 2 | wifiCallback.ino 3 | Copyright (c) 2018 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | #include "ESPHelper32.h" 23 | 24 | netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT 25 | .mqttUser = "YOUR MQTT USERNAME", //can be blank 26 | .mqttPass = "YOUR MQTT PASSWORD", //can be blank 27 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 28 | .ssid = "YOUR SSID", 29 | .pass = "YOUR NETWORK PASS", 30 | .otaPassword = "YOUR OTA PASS", 31 | .hostname = "NEW-ESP8266"}; 32 | 33 | ESPHelper32 myESP(&homeNet); 34 | 35 | void setup() { 36 | 37 | Serial.begin(115200); //start the serial line 38 | delay(500); 39 | 40 | Serial.println("Starting Up, Please Wait..."); 41 | 42 | myESP.addSubscription("/test"); 43 | myESP.setWifiCallback(wifiCallback); 44 | myESP.setMQTTCallback(MQTTcallback); 45 | myESP.begin(); 46 | 47 | 48 | Serial.println("Initialization Finished."); 49 | } 50 | 51 | void loop(){ 52 | myESP.loop(); //run the loop() method as often as possible - this keeps the network services running 53 | 54 | //Put application code here 55 | 56 | yield(); 57 | } 58 | 59 | void MQTTcallback(char* topic, uint8_t* payload, unsigned int length) { 60 | //put mqtt callback code here 61 | } 62 | 63 | void wifiCallback(){ 64 | Serial.println("WiFi Connected!"); 65 | } -------------------------------------------------------------------------------- /src/ESPHelper32WebConfig.h: -------------------------------------------------------------------------------- 1 | /* 2 | ESPHelper32WebConfig.h 3 | Copyright (c) 2019 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | 23 | 24 | #ifndef ESPHELPER32_WEBCONFIG_H 25 | #define ESPHELPER32_WEBCONFIG_H 26 | 27 | #include "ESPHelper32.h" 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | 34 | class ESPHelper32WebConfig{ 35 | 36 | public: 37 | ESPHelper32WebConfig(int port, const char* URI); //constructor 38 | ESPHelper32WebConfig(WebServer *server, const char* URI); 39 | 40 | bool begin(const char* hostname); 41 | bool begin(); 42 | 43 | void fillConfig(netInfo* fillInfo); 44 | 45 | bool handle(); 46 | 47 | netInfo getConfig(); 48 | 49 | void setSpiffsReset(const char* uri); 50 | 51 | 52 | private: 53 | void handleGet(); 54 | void handlePost(); 55 | void handleNotFound(); 56 | void handleReset(); 57 | 58 | WebServer *_server; 59 | WebServer _localServer; 60 | 61 | char _newSsid[64]; 62 | char _newNetPass[64]; 63 | char _newOTAPass[64]; 64 | char _newHostname[64]; 65 | char _newMqttHost[64]; 66 | char _newMqttUser[64]; 67 | char _newMqttPass[64]; 68 | int _newMqttPort; 69 | 70 | const char* _resetURI; 71 | const char* _pageURI; 72 | 73 | netInfo* _fillData; 74 | bool _preFill = false; 75 | 76 | bool _resetSet = false; 77 | 78 | netInfo _config; 79 | bool _configLoaded = false; 80 | bool _runningLocal = false; 81 | 82 | 83 | }; 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /examples/GettingStarted/basicUserPass/basicUserPass.ino: -------------------------------------------------------------------------------- 1 | /* 2 | basicUserPass.ino 3 | Copyright (c) 2018 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | #include "ESPHelper32.h" 23 | #include "Metro.h" 24 | 25 | #define MQTT_TOPIC "/test" 26 | 27 | 28 | //Metro timer for 5 second intervals (used to time publishing to MQTT) 29 | Metro postMetro = Metro(5000); 30 | 31 | 32 | netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT 33 | .mqttUser = "YOUR MQTT USERNAME", //can be blank 34 | .mqttPass = "YOUR MQTT PASSWORD", //can be blank 35 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 36 | .ssid = "YOUR SSID", 37 | .pass = "YOUR NETWORK PASS", 38 | .otaPassword = "YOUR OTA PASS", 39 | .hostname = "NEW-ESP8266"}; 40 | 41 | ESPHelper32 myESP(&homeNet); 42 | 43 | 44 | int counter = 0; 45 | 46 | 47 | void setup() { 48 | Serial.begin(115200); 49 | 50 | //setup ESPHelper 51 | myESP.setMQTTCallback(callback); 52 | myESP.addSubscription(MQTT_TOPIC); 53 | myESP.begin(); 54 | } 55 | 56 | 57 | void loop(){ 58 | 59 | //check and make sure that we have a full connection to both WIFI and MQTT 60 | //and only post if the timer has gone off 61 | if(myESP.loop() == FULL_CONNECTION && postMetro.check()){ 62 | //print to the serial line 63 | Serial.print(counter); 64 | Serial.println(" Sent"); 65 | 66 | //generate a string from our counter variable 67 | char pubString[10]; 68 | itoa(counter, pubString, 10); 69 | 70 | //publish the data to MQTT 71 | myESP.publish(MQTT_TOPIC, pubString); 72 | 73 | //increment the counter 74 | counter++; 75 | } 76 | 77 | 78 | yield(); 79 | } 80 | 81 | 82 | void callback(char* topic, uint8_t* payload, unsigned int length) { 83 | 84 | //generate a new payload string that is null terminated 85 | char newPayload[40]; 86 | memcpy(newPayload, payload, length); 87 | newPayload[length] = '\0'; 88 | 89 | //print that info back out the the serial line 90 | Serial.print(newPayload); 91 | Serial.println(" Received"); 92 | } 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /examples/GettingStarted/Adafruit_IO/Adafruit_IO.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Adafruit_IO.ino 3 | Copyright (c) 2018 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | #include "ESPHelper32.h" 23 | #include "Metro.h" 24 | 25 | #define SSID "YOUR SSID" 26 | #define NETWORK_PASS "YOUR NETWORK PASS" 27 | 28 | #define AIO_USERNAME "YOUR_AIO_USERNAME" 29 | #define AIO_KEY "YOUR_AIO_KEY" 30 | #define AIO_FEED "AIO_FEED_NAME" 31 | 32 | 33 | //Metro timer for 5 second intervals (used to time publishing to MQTT) 34 | Metro postMetro = Metro(5000); 35 | 36 | 37 | netInfo homeNet = { .mqttHost = "io.adafruit.com", //can be blank if not using MQTT 38 | .mqttUser = AIO_USERNAME, //can be blank 39 | .mqttPass = AIO_KEY, //can be blank 40 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 41 | .ssid = SSID, 42 | .pass = NETWORK_PASS}; 43 | 44 | ESPHelper32 myESP(&homeNet); 45 | 46 | 47 | int counter = 0; 48 | 49 | 50 | void setup() { 51 | Serial.begin(115200); 52 | 53 | //setup ESPHelper 54 | myESP.setMQTTCallback(callback); 55 | myESP.addSubscription(AIO_USERNAME"/feeds/"AIO_FEED); 56 | myESP.begin(); 57 | 58 | 59 | } 60 | 61 | 62 | void loop(){ 63 | 64 | //check and make sure that we have a full connection to both WIFI and MQTT 65 | //and only post if the timer has gone off 66 | if(myESP.loop() == FULL_CONNECTION && postMetro.check()){ 67 | //print to the serial line 68 | Serial.print(counter); 69 | Serial.println(" Sent"); 70 | 71 | //generate a string from our counter variable 72 | char pubString[10]; 73 | itoa(counter, pubString, 10); 74 | 75 | //publish the data to MQTT 76 | myESP.publish(AIO_USERNAME"/feeds/"AIO_FEED, pubString); 77 | 78 | //increment the counter 79 | counter++; 80 | } 81 | 82 | 83 | yield(); 84 | } 85 | 86 | 87 | void callback(char* topic, uint8_t* payload, unsigned int length) { 88 | 89 | //generate a new payload string that is null terminated 90 | char newPayload[40]; 91 | memcpy(newPayload, payload, length); 92 | newPayload[length] = '\0'; 93 | 94 | //print that info back out the the serial line 95 | Serial.print(newPayload); 96 | Serial.println(" Received"); 97 | } 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /examples/GettingStarted/relayControl/relayControl.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 ItKindaWorks All right reserved. 3 | github.com/ItKindaWorks 4 | 5 | This file is part of ESPHelper32 6 | 7 | ESPHelper32 is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ESPHelper32 is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with ESPHelper32. If not, see . 19 | */ 20 | 21 | /* 22 | This is a simple MQTT relay/light controller program for the ESP8266. 23 | By sending a '1' or '0' to the relayTopic the relayPin can be toggled 24 | on or off. This program also posts a status update to the status topic 25 | which is the relayTopic plus "/status" (ex. if the relayTopic 26 | is "/home/light" then the statusTopic would be "home/light/status") 27 | */ 28 | 29 | #include "ESPHelper32.h" 30 | 31 | #define TOPIC "/your/mqtt/topic" 32 | #define STATUS TOPIC "/status" //dont change this - this is for the status topic which is whatever your mqtt topic is plus /status (ex /home/light/status) 33 | 34 | #define RELAY_PIN 3 //rx pin on esp 35 | #define BLINK_PIN 1 //tx/led on esp-01 36 | 37 | 38 | const char* relayTopic = TOPIC; 39 | const char* statusTopic = STATUS; 40 | 41 | const int relayPin = RELAY_PIN; 42 | const int blinkPin = BLINK_PIN; //tx pin on esp 43 | 44 | netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT 45 | .mqttUser = "YOUR MQTT USERNAME", //can be blank 46 | .mqttPass = "YOUR MQTT PASSWORD", //can be blank 47 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 48 | .ssid = "YOUR SSID", 49 | .pass = "YOUR NETWORK PASS", 50 | .otaPassword = "YOUR OTA PASS", 51 | .hostname = "NEW-ESP8266"}; 52 | 53 | ESPHelper32 myESP(&homeNet); 54 | 55 | void setup() { 56 | //setup ota 57 | myESP.OTA_enable(); 58 | myESP.OTA_setPassword(homeNet.otaPassword); 59 | myESP.OTA_setHostnameWithVersion(homeNet.hostname); 60 | 61 | 62 | //setup the rest of ESPHelper 63 | myESP.enableHeartbeat(blinkPin); //comment out to disable the heartbeat 64 | myESP.addSubscription(relayTopic); //add the relay topic to the subscription list 65 | myESP.setMQTTCallback(callback); 66 | myESP.begin(); 67 | 68 | 69 | pinMode(relayPin, OUTPUT); 70 | delay(100); 71 | } 72 | 73 | 74 | void loop(){ 75 | //loop ESPHelper and wait for commands from mqtt 76 | myESP.loop(); 77 | yield(); 78 | } 79 | 80 | 81 | //mqtt callback 82 | void callback(char* topic, byte* payload, unsigned int length) { 83 | String topicStr = topic; 84 | 85 | //if the payload from mqtt was 1, turn the relay on and update the status topic with 1 86 | if(payload[0] == '1'){ 87 | digitalWrite(relayPin, HIGH); 88 | myESP.publish(statusTopic, "1",true); 89 | } 90 | 91 | //else turn the relay off and update the status topic with 0 92 | else if (payload[0] == '0'){ 93 | digitalWrite(relayPin, LOW); 94 | myESP.publish(statusTopic, "0", true); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /examples/GettingStarted/buttonDemo/buttonDemo.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 ItKindaWorks All right reserved. 3 | github.com/ItKindaWorks 4 | 5 | This file is part of ESPHelper32 6 | 7 | ESPHelper32 is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ESPHelper32 is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with ESPHelper32. If not, see . 19 | */ 20 | 21 | /* 22 | This is a simple demo of an MQTT enabled button. A button is attahed 23 | to pin 0 with a pull-up resistor and each time the button is pressed, 24 | it toggles the state and publishes the new state to the MQTT broker. 25 | It is also subscribed to the same topic that it publishes to so that 26 | the state of the toggle can be updated from the MQTT side. 27 | */ 28 | #include "ESPHelper32.h" 29 | 30 | #define TOPIC "/your/mqtt/topic" 31 | #define NETWORK_HOSTNAME "YOUR OTA HOSTNAME" 32 | #define OTA_PASSWORD "YOUR OTA PASSWORD" 33 | 34 | #define BUTTON_PIN 0 //button on pin 0 with pull up resistor (pulled low on press) 35 | #define BLINK_PIN 1 36 | 37 | 38 | char* buttonTopic = TOPIC; 39 | char* hostnameStr = NETWORK_HOSTNAME; 40 | 41 | const int buttonPin = BUTTON_PIN; 42 | const int blinkPin = BLINK_PIN; 43 | 44 | bool currentState = false; 45 | 46 | bool lastButtonState = false; 47 | 48 | netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT 49 | .mqttUser = "YOUR MQTT USERNAME", //can be blank 50 | .mqttPass = "YOUR MQTT PASSWORD", //can be blank 51 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 52 | .ssid = "YOUR SSID", 53 | .pass = "YOUR NETWORK PASS", 54 | .otaPassword = "YOUR OTA PASS", 55 | .hostname = "NEW-ESP8266"}; 56 | 57 | ESPHelper32 myESP(&homeNet); 58 | 59 | void setup() { 60 | //setup ota on esphelper 61 | myESP.OTA_enable(); 62 | myESP.OTA_setPassword(OTA_PASSWORD); 63 | myESP.OTA_setHostnameWithVersion(hostnameStr); 64 | 65 | //enable the connection heartbeat 66 | myESP.enableHeartbeat(blinkPin); 67 | 68 | //subscribe to the button topic (this allows outside control of the state of the switch) 69 | myESP.addSubscription(buttonTopic); 70 | 71 | //setup the mqtt callback function 72 | myESP.setMQTTCallback(callback); 73 | 74 | //start ESPHelper 75 | myESP.begin(); 76 | 77 | //set the button pin as an input 78 | pinMode(buttonPin, INPUT); 79 | } 80 | 81 | 82 | void loop(){ 83 | if(myESP.loop() == FULL_CONNECTION){ 84 | 85 | //read the button (low on press, high on release) 86 | bool buttonState = digitalRead(buttonPin); 87 | 88 | //if the button is pressed (LOW) and previously was not pressed(HIGH) 89 | if(buttonState == LOW && lastButtonState == HIGH){ 90 | //invert the current state 91 | currentState = !currentState; 92 | 93 | //publish to mqtt based on current state 94 | if(currentState){ 95 | myESP.publish(buttonTopic, "1", true); 96 | } 97 | else{ 98 | myESP.publish(buttonTopic, "0", true); 99 | } 100 | 101 | //set the lastButtonState to LOW to prevent multiple triggers 102 | lastButtonState = LOW; 103 | 104 | //wait half a second (poor mans debounce) 105 | delay(500); 106 | } 107 | 108 | //else if the button is not pressed and set lastButtonState to HIGH 109 | else if(buttonState == HIGH){lastButtonState = HIGH;} 110 | } 111 | yield(); 112 | } 113 | 114 | 115 | void callback(char* topic, byte* payload, unsigned int length) { 116 | 117 | //if the payload is '1' then set the state to true 118 | if(payload[0] == '1'){ 119 | currentState = true; 120 | } 121 | 122 | //otherwise set the current state to false 123 | else{ 124 | currentState = false; 125 | } 126 | } 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /src/ESPHelper32FS.h: -------------------------------------------------------------------------------- 1 | /* 2 | ESPHelper32FS.h 3 | Copyright (c) 2019 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper 7 | 8 | ESPHelper is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper. If not, see . 20 | */ 21 | 22 | 23 | 24 | #ifndef ESPHelper32FS_H 25 | #define ESPHelper32FS_H 26 | 27 | #include "ESPHelper32.h" 28 | #include 29 | #include "FS.h" 30 | #include "SPIFFS.h" 31 | 32 | // #define DEBUG 33 | 34 | #ifdef DEBUG 35 | #define FSdebugPrint(x) Serial.print(x) //debug on 36 | #define FSdebugPrintln(x) Serial.println(x) //debug on 37 | #define DEBUG_PRINT_SPEED 250 38 | #else 39 | #define FSdebugPrint(x) {;} //debug off 40 | #define FSdebugPrintln(x) {;} //debug off 41 | #define DEBUG_PRINT_SPEED 1 42 | #endif 43 | 44 | const uint16_t JSON_SIZE = 512; 45 | 46 | enum validateStates {NO_CONFIG, CONFIG_TOO_BIG, CANNOT_PARSE, INCOMPLETE, GOOD_CONFIG}; 47 | 48 | class ESPHelper32FS{ 49 | 50 | public: 51 | ESPHelper32FS(); 52 | ESPHelper32FS(const char* filename); 53 | 54 | static bool begin(); 55 | static void end(); 56 | 57 | void printFile(); 58 | 59 | 60 | 61 | static int8_t validateConfig(const char* filename); 62 | 63 | bool createConfig(const char* filename); 64 | bool createConfig(const netInfo* config); 65 | static bool createConfig(const netInfo* config, const char* filename); 66 | 67 | bool loadNetworkConfig(); 68 | 69 | bool addKey(const char* keyName, const char* value); 70 | static bool addKey(const char* keyName, const char* value, const char* filename); 71 | 72 | String loadKey(const char* keyName); 73 | static String loadKey(const char* keyName, const char* filename); 74 | 75 | netInfo getNetInfo(); 76 | 77 | static bool createConfig( const char* filename, 78 | const char* _ssid, 79 | const char* _networkPass, 80 | const char* _deviceName, 81 | const char* _mqttIP, 82 | const char* _mqttUser, 83 | const char* _mqttPass, 84 | const int _mqttPort, 85 | const char* _otaPass, 86 | const char* _willTopic, 87 | const char* _willMessage, 88 | const int _willQoS, 89 | const int _willRetain); 90 | 91 | void printFSinfo(); 92 | 93 | 94 | static StaticJsonBuffer *_tmpBufPtr; 95 | private: 96 | static bool loadFile(const char* filename, std::unique_ptr &buf); 97 | 98 | 99 | 100 | char ssid[64]; 101 | char netPass[32]; 102 | char hostName[32]; 103 | char mqtt_ip[64]; 104 | char mqttUser[32]; 105 | char mqttPass[32]; 106 | char mqttPort[16]; 107 | char otaPass[32]; 108 | char willTopic[64]; 109 | char willMessage[64]; 110 | char willQoS[4]; 111 | char willRetain[4]; 112 | 113 | netInfo _networkData; 114 | 115 | const char* _filename; 116 | 117 | static bool saveConfig(JsonObject& json, const char* filename); 118 | 119 | const netInfo defaultConfig = { mqttHost : "0.0.0.0", //can be blank if not using MQTT 120 | mqttUser : "user", //can be blank 121 | mqttPass : "pass", //can be blank 122 | mqttPort : 1883, //default port for MQTT is 1883 - only change if needed. 123 | ssid : "networkSSID", 124 | pass : "networkPass", 125 | otaPassword : "otaPass", 126 | hostname : "NEW-ESP8266", 127 | willTopic : "defaultWillTopic", 128 | willMessage : "", 129 | willQoS : 1, 130 | willRetain : 1}; 131 | }; 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /examples/GettingStarted/RelayControlV2/RelayControlV2.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2018 ItKindaWorks All right reserved. 3 | github.com/ItKindaWorks 4 | 5 | This file is part of ESPHelper32 6 | 7 | ESPHelper32 is free software: you can redistribute it and/or modify 8 | it under the terms of the GNU General Public License as published by 9 | the Free Software Foundation, either version 3 of the License, or 10 | (at your option) any later version. 11 | 12 | ESPHelper32 is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with ESPHelper32. If not, see . 19 | */ 20 | 21 | #include "ESPHelper32.h" 22 | 23 | #define TOPIC "/your/mqtt/topic" 24 | #define STATUS TOPIC "/status" //dont change this - this is for the status topic which is whatever your mqtt topic is plus /status (ex /home/light/status) 25 | 26 | #define RELAY_PIN 3 //rx pin on esp 27 | #define BLINK_PIN 1 //tx/led on esp-01 28 | #define BUTTON_PIN 0 29 | 30 | 31 | const char* relayTopic = TOPIC; 32 | const char* statusTopic = STATUS; 33 | 34 | //initialized the pins 35 | const int buttonPin = BUTTON_PIN; 36 | const int relayPin = RELAY_PIN; 37 | const int blinkPin = BLINK_PIN; 38 | 39 | //this is the current state of the relay 40 | bool currentState = false; 41 | 42 | //flag to mark when a rising edge has been detected 43 | bool risingEdge = false; 44 | 45 | //keeps track of the previous button state for edge detection 46 | bool lastButtonState = false; 47 | 48 | netInfo homeNet = { .mqttHost = "YOUR MQTT-IP", //can be blank if not using MQTT 49 | .mqttUser = "YOUR MQTT USERNAME", //can be blank 50 | .mqttPass = "YOUR MQTT PASSWORD", //can be blank 51 | .mqttPort = 1883, //default port for MQTT is 1883 - only chance if needed. 52 | .ssid = "YOUR SSID", 53 | .pass = "YOUR NETWORK PASS", 54 | .otaPassword = "YOUR OTA PASS", 55 | .hostname = "NEW-ESP8266"}; 56 | 57 | ESPHelper32 myESP(&homeNet); 58 | 59 | 60 | void setup() { 61 | 62 | //setup Arduino OTA 63 | myESP.OTA_enable(); 64 | myESP.OTA_setPassword(homeNet.otaPassword); 65 | myESP.OTA_setHostnameWithVersion(homeNet.hostname); 66 | 67 | //enable the connection heartbeat 68 | myESP.enableHeartbeat(blinkPin); 69 | 70 | //add a subscription to the relatTopic 71 | myESP.addSubscription(relayTopic); 72 | 73 | //add in the MQTT callback 74 | myESP.setMQTTCallback(callback); 75 | 76 | //start ESPHelper 77 | myESP.begin(); 78 | 79 | //set the button as an input 80 | pinMode(buttonPin, INPUT); 81 | 82 | //set the relay pin as an output and set to off 83 | pinMode(relayPin, OUTPUT); 84 | digitalWrite(relayPin, LOW); 85 | } 86 | 87 | 88 | void loop(){ 89 | if(myESP.loop() == FULL_CONNECTION){ 90 | 91 | //read the state of the button (LOW is pressed) 92 | bool buttonState = digitalRead(buttonPin); 93 | 94 | //if the button is pressed (LOW) and previously was not pressed(HIGH) 95 | if(buttonState == LOW && lastButtonState == HIGH){ 96 | 97 | //debounce the signal and if the button is still pressed, mark as a rising edge 98 | delay(50); 99 | if(digitalRead(buttonPin) == LOW){ 100 | lastButtonState = LOW; 101 | risingEdge = true; 102 | } 103 | 104 | } 105 | 106 | //else if the button is not pressed and set lastButtonState to HIGH and reset the rising edge flag 107 | else if(buttonState == HIGH){ 108 | lastButtonState = HIGH; 109 | risingEdge = false; 110 | } 111 | 112 | 113 | //rising edge detected 114 | if(risingEdge){ 115 | 116 | //set the state to the opposite of the current state 117 | setState(!currentState); 118 | 119 | //reset the rising edge flag 120 | risingEdge = false; 121 | 122 | } 123 | } 124 | yield(); 125 | } 126 | 127 | 128 | void callback(char* topic, byte* payload, unsigned int length) { 129 | if(payload[0] == '1'){ 130 | setState(true); 131 | } 132 | else{ 133 | setState(false); 134 | } 135 | } 136 | 137 | //sets a new state for the relay and publishes to MQTT 138 | void setState(bool newState){ 139 | 140 | //dont do anything unless the newState and currentState are different 141 | if(newState != currentState){ 142 | 143 | //set the current state 144 | currentState = newState; 145 | 146 | //publish to the MQTT status topic 147 | if(currentState){myESP.publish(statusTopic, "1", true);} 148 | else{myESP.publish(statusTopic, "0", true);} 149 | 150 | //set the relay on or off 151 | digitalWrite(relayPin, currentState); 152 | } 153 | } 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /src/sharedData.h: -------------------------------------------------------------------------------- 1 | /* 2 | sharedTypes.h 3 | Copyright (c) 2018 ItKindaWorks Inc All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | 23 | 24 | #ifndef SHARED_TYPES_H 25 | #define SHARED_TYPES_H 26 | 27 | #define VERSION "0-9-1" 28 | 29 | 30 | //Maximum number of subscriptions that can be auto-subscribed 31 | //feel free to change this if you need more subsciptions 32 | #define MAX_SUBSCRIPTIONS 25 33 | 34 | #define DEFAULT_QOS 1; //at least once - devices are guarantee to get a message. 35 | 36 | 37 | enum connStatus {NO_CONNECTION, BROADCAST, WIFI_ONLY, FULL_CONNECTION}; 38 | 39 | struct netInfo { 40 | const char* name; 41 | const char* mqttHost; 42 | const char* mqttUser; 43 | const char* mqttPass; 44 | int mqttPort; 45 | const char* ssid; 46 | const char* pass; 47 | const char* otaPassword; 48 | const char* hostname; 49 | const char* willTopic; 50 | const char* willMessage; 51 | int willQoS; 52 | int willRetain; 53 | 54 | netInfo() : mqttPort(1883) {} 55 | 56 | //name | mqtt host | ssid | network pass 57 | netInfo(const char* _name, 58 | const char* _mqttHost, 59 | const char* _ssid, 60 | const char* _pass) : 61 | name(_name), 62 | mqttHost(_mqttHost), 63 | ssid(_ssid), 64 | pass(_pass), 65 | mqttPort(1883), 66 | mqttUser("defaultMqttUser"), 67 | mqttPass("defaultMqttPass"), 68 | otaPassword("defaultOTA_PASS"), 69 | hostname("defaultHostname"), 70 | willTopic("defaultWillTopic"), 71 | willMessage(""), 72 | willQoS(1), 73 | willRetain(1) {} 74 | 75 | //mqtt host | ssid | network pass | willTopic | willMessage 76 | netInfo(const char* _mqttHost, 77 | const char* _ssid, 78 | const char* _pass, 79 | const char* _willTopic, 80 | const char* _willMessage) : 81 | mqttHost(_mqttHost), 82 | ssid(_ssid), 83 | pass(_pass), 84 | mqttPort(1883), 85 | mqttUser("defaultMqttUser"), 86 | mqttPass("defaultMqttPass"), 87 | otaPassword("defaultOTA_PASS"), 88 | hostname("defaultHostname"), 89 | willTopic(_willTopic), 90 | willMessage(_willMessage), 91 | willQoS(1), 92 | willRetain(1) {} 93 | 94 | //mqtt host | mqtt user| mqtt pass| mqtt port| ssid | network pass 95 | netInfo(const char* _mqttHost, 96 | const char* _mqttUser, 97 | const char* _mqttPass, 98 | int _mqttPort, 99 | const char* _ssid, 100 | const char* _pass) : 101 | mqttHost(_mqttHost), 102 | mqttUser(_mqttUser), 103 | mqttPass(_mqttPass), 104 | mqttPort(_mqttPort), 105 | ssid(_ssid), 106 | pass(_pass), 107 | otaPassword("defaultOtaPASS"), 108 | hostname("defaultHostname"), 109 | willTopic("defaultWillTopic"), 110 | willMessage(""), 111 | willQoS(1), 112 | willRetain(1) {} 113 | 114 | 115 | //mqtt host | mqtt user| mqtt pass| mqtt port| ssid | network pass | ota pass | hostname 116 | netInfo(const char* _mqttHost, 117 | const char* _mqttUser, 118 | const char* _mqttPass, 119 | int _mqttPort, 120 | const char* _ssid, 121 | const char* _pass, 122 | const char* _otaPassword, 123 | const char* _hostname) : 124 | mqttHost(_mqttHost), 125 | mqttUser(_mqttUser), 126 | mqttPass(_mqttPass), 127 | mqttPort(_mqttPort), 128 | ssid(_ssid), 129 | pass(_pass), 130 | otaPassword(_otaPassword), 131 | hostname(_hostname), 132 | willTopic("defaultWillTopic"), 133 | willMessage(""), 134 | willQoS(1), 135 | willRetain(1) {} 136 | 137 | 138 | //mqtt host | mqtt user| mqtt pass| mqtt port| ssid | network pass | ota pass | hostname | willTopic | willMessage 139 | netInfo(const char* _mqttHost, 140 | const char* _mqttUser, 141 | const char* _mqttPass, 142 | int _mqttPort, 143 | const char* _ssid, 144 | const char* _pass, 145 | const char* _otaPassword, 146 | const char* _hostname, 147 | const char* _willTopic, 148 | const char* _willMessage) : 149 | mqttHost(_mqttHost), 150 | mqttUser(_mqttUser), 151 | mqttPass(_mqttPass), 152 | mqttPort(_mqttPort), 153 | ssid(_ssid), 154 | pass(_pass), 155 | otaPassword("defaultOtaPASS"), 156 | hostname("defaultHostname"), 157 | willTopic(_willTopic), 158 | willMessage(_willMessage), 159 | willQoS(1), 160 | willRetain(1) {} 161 | 162 | 163 | //mqtt host | mqtt user| mqtt pass| mqtt port| ssid | network pass | willTopic | willMessage | willRetain | willQoS 164 | netInfo(const char* _mqttHost, 165 | const char* _mqttUser, 166 | const char* _mqttPass, 167 | int _mqttPort, 168 | const char* _ssid, 169 | const char* _pass, 170 | const char* _willTopic, 171 | const char* _willMessage, 172 | int _willQoS, 173 | int _willRetain) : 174 | mqttHost(_mqttHost), 175 | mqttUser(_mqttUser), 176 | mqttPass(_mqttPass), 177 | mqttPort(_mqttPort), 178 | ssid(_ssid), 179 | pass(_pass), 180 | otaPassword("defaultOtaPASS"), 181 | hostname("defaultHostname"), 182 | willTopic(_willTopic), 183 | willMessage(_willMessage), 184 | willQoS(1), 185 | willRetain(1) {} 186 | 187 | 188 | //mqtt host | mqtt user| mqtt pass| mqtt port| ssid | network pass | ota pass | hostname | willTopic | willMessage | willRetain | willQoS 189 | netInfo(const char* _mqttHost, 190 | const char* _mqttUser, 191 | const char* _mqttPass, 192 | int _mqttPort, 193 | const char* _ssid, 194 | const char* _pass, 195 | const char* _otaPassword, 196 | const char* _hostname, 197 | const char* _willTopic, 198 | const char* _willMessage, 199 | int _willQoS, 200 | int _willRetain) : 201 | mqttHost(_mqttHost), 202 | mqttUser(_mqttUser), 203 | mqttPass(_mqttPass), 204 | mqttPort(_mqttPort), 205 | ssid(_ssid), 206 | pass(_pass), 207 | otaPassword(_otaPassword), 208 | hostname(_hostname), 209 | willTopic(_willTopic), 210 | willMessage(_willMessage), 211 | willQoS(_willQoS), 212 | willRetain(_willRetain) {} 213 | 214 | }; 215 | // typedef struct netInfo netInfo; 216 | 217 | 218 | struct subscription{ 219 | bool isUsed = false; 220 | const char* topic; 221 | }; 222 | typedef struct subscription subscription; 223 | 224 | 225 | 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /src/ESPHelper32.h: -------------------------------------------------------------------------------- 1 | /* 2 | ESPHelper32.h 3 | Copyright (c) 2019 ItKindaWorks Inc All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | 23 | 24 | #ifndef ESP_HELPER32_H 25 | #define ESP_HELPER32_H 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "sharedData.h" 32 | #include 33 | #include "Metro.h" 34 | 35 | // #define VERSION "1-5-6" 36 | 37 | // #define DEBUG 38 | 39 | #ifdef DEBUG 40 | #define debugPrint(x) Serial.print(x) //debug on 41 | #define debugPrintln(x) Serial.println(x) //debug on 42 | #else 43 | #define debugPrint(x) {;} //debug off 44 | #define debugPrintln(x) {;} //debug off 45 | #endif 46 | 47 | 48 | 49 | class ESPHelper32{ 50 | 51 | public: 52 | ESPHelper32(); 53 | ESPHelper32(const netInfo *startingNet); 54 | ESPHelper32(netInfo *netList[], uint8_t netCount, uint8_t startIndex = 0); //remember netInfo *netList[] is really netinfo** 55 | ESPHelper32(const char *ssid, const char *pass, const char *mqttIP); 56 | ESPHelper32(const char *ssid, const char *pass); 57 | ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort); 58 | ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *willTopic, const char *willMessage); 59 | ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain); 60 | ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain); 61 | ESPHelper32(const char* configFile); 62 | 63 | bool begin(const char* filename); 64 | bool begin(const netInfo *startingNet); 65 | bool begin(const char *ssid, const char *pass, const char *mqttIP); 66 | bool begin(const char *ssid, const char *pass); 67 | bool begin(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort); 68 | bool begin(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort, const char *willTopic, const char *willMessage); 69 | bool begin(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain); 70 | bool begin(); 71 | void end(); 72 | 73 | netInfo loadConfigFile(const char* filename); 74 | bool saveConfigFile(const netInfo config, const char* filename); 75 | 76 | void useSecureClient(const char* fingerprint); 77 | 78 | void broadcastMode(const char* ssid, const char* password, const IPAddress ip); 79 | void disableBroadcast(); 80 | 81 | int loop(); 82 | 83 | bool subscribe(const char* topic, int qos); 84 | bool addSubscription(const char* topic); 85 | bool removeSubscription(const char* topic); 86 | bool unsubscribe(const char* topic); 87 | 88 | void publish(const char* topic, const char* payload); 89 | void publish(const char* topic, const char* payload, bool retain); 90 | 91 | bool setCallback(MQTT_CALLBACK_SIGNATURE); 92 | void setMQTTCallback(MQTT_CALLBACK_SIGNATURE); 93 | 94 | void setWifiCallback(void (*callback)()); 95 | 96 | void reconnect(); 97 | 98 | void updateNetwork(); //manually disconnect and reconnecting to network/mqtt using current values (generally called after setting new network values) 99 | 100 | const char* getSSID(); 101 | void setSSID(const char *ssid); 102 | 103 | const char* getPASS(); 104 | void setPASS(const char *pass); 105 | 106 | const char* getMQTTIP(); 107 | void setMQTTIP(const char *mqttIP); 108 | void setMQTTIP(const char *mqttIP, const char *mqttUser, const char *mqttPass); 109 | 110 | int getMQTTQOS(); 111 | void setMQTTQOS(int qos); 112 | 113 | void setWill(const char *willTopic, const char *willMessage); 114 | void setWill(const char *willTopic, const char *willMessage, const int willQoS, const int willRetain); 115 | 116 | String getIP(); 117 | IPAddress getIPAddress(); 118 | 119 | int getStatus(); 120 | 121 | void setNetInfo(netInfo newNetwork); 122 | void setNetInfo(netInfo *newNetwork); 123 | // netInfo* getNetInfo(); 124 | netInfo getNetInfo(); 125 | 126 | void setHopping(bool canHop); 127 | 128 | void listSubscriptions(); 129 | 130 | void enableHeartbeat(int16_t pin); 131 | void disableHeartbeat(); 132 | void heartbeat(); 133 | 134 | void OTA_enable(); 135 | void OTA_disable(); 136 | void OTA_begin(); 137 | void OTA_setPassword(const char* pass); 138 | void OTA_setHostname(const char* hostname); 139 | void OTA_setHostnameWithVersion(const char* hostname); 140 | char* getHostname(); 141 | 142 | private: 143 | 144 | void init(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain); 145 | void validateConfig(); 146 | 147 | void changeNetwork(); 148 | 149 | String macToStr(const uint8_t* mac); 150 | 151 | bool checkParams(); 152 | 153 | void resubscribe(); 154 | 155 | int setConnectionStatus(); 156 | 157 | netInfo _currentNet; 158 | 159 | PubSubClient client; 160 | 161 | Metro reconnectMetro = Metro(500); 162 | 163 | WiFiClient wifiClient; 164 | WiFiClientSecure wifiClientSecure; 165 | const char* _fingerprint; 166 | bool _useSecureClient = false; 167 | 168 | String _clientName; 169 | 170 | void (*_wifiCallback)(); 171 | bool _wifiCallbackSet = false; 172 | 173 | void(*_mqttCallback)(char*, uint8_t*, unsigned int) ; 174 | bool _mqttCallbackSet = false; 175 | 176 | int _connectionStatus = NO_CONNECTION; 177 | 178 | //AP mode variables 179 | IPAddress _broadcastIP; 180 | char _broadcastSSID[64]; 181 | char _broadcastPASS[64]; 182 | 183 | //netInfo array vars (total + current index) 184 | uint8_t _netCount = 0; 185 | uint8_t _currentIndex = 0; 186 | 187 | bool _ssidSet = false; 188 | bool _passSet = false; 189 | bool _mqttSet = false; 190 | bool _mqttUserSet = false; 191 | bool _mqttPassSet = false; 192 | bool _willTopicSet = false; 193 | bool _willMessageSet = false; 194 | 195 | bool _useOTA = false; 196 | bool _OTArunning = false; 197 | 198 | bool _hoppingAllowed = false; 199 | 200 | bool _hasBegun = false; 201 | 202 | netInfo **_netList; 203 | 204 | int16_t _ledPin = 2; 205 | bool _heartbeatEnabled = false; 206 | 207 | subscription _subscriptions[MAX_SUBSCRIPTIONS]; 208 | 209 | char _hostname[64]; 210 | 211 | int _qos = DEFAULT_QOS; 212 | 213 | IPAddress _apIP = IPAddress(192, 168, 1, 1); 214 | 215 | 216 | }; 217 | 218 | #endif 219 | -------------------------------------------------------------------------------- /src/ESPHelper32WebConfig.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ESPHelper32WebConfig.cpp 3 | Copyright (c) 2019 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | #include "ESPHelper32WebConfig.h" 22 | #include "FS.h" 23 | #include "SPIFFS.h" 24 | 25 | ESPHelper32WebConfig::ESPHelper32WebConfig(int port, const char* URI) : _localServer(port){ 26 | _server = &_localServer; 27 | _runningLocal = true; 28 | _pageURI = URI; 29 | } 30 | 31 | ESPHelper32WebConfig::ESPHelper32WebConfig(WebServer *server, const char* URI){ 32 | _server = server; 33 | _runningLocal = false; 34 | _pageURI = URI; 35 | } 36 | 37 | bool ESPHelper32WebConfig::begin(const char* _hostname){ 38 | MDNS.begin(_hostname); 39 | return begin(); 40 | } 41 | 42 | bool ESPHelper32WebConfig::begin(){ 43 | //setup server handlers 44 | //these handler function definitions use lambdas to pass the funtion... more information can be found here: 45 | //https://stackoverflow.com/questions/39803135/c-unresolved-overloaded-function-type 46 | _server->on(_pageURI, HTTP_GET, [this](){handleGet();}); // Call the 'handleRoot' function when a client requests URI "/" 47 | _server->on(_pageURI, HTTP_POST, [this](){handlePost();}); // Call the 'handleLogin' function when a POST request is made to URI "/login" 48 | _server->onNotFound([this](){handleNotFound();}); // When a client requests an unknown URI (i.e. something other than "/"), call function "handleNotFound" 49 | 50 | if(_runningLocal){ 51 | _server->begin(); // Actually start the server 52 | } 53 | 54 | 55 | return true; 56 | } 57 | 58 | void ESPHelper32WebConfig::fillConfig(netInfo* fillInfo){ 59 | _fillData = fillInfo; 60 | _preFill = true; 61 | } 62 | 63 | bool ESPHelper32WebConfig::handle(){ 64 | _server->handleClient(); 65 | return _configLoaded; 66 | } 67 | 68 | netInfo ESPHelper32WebConfig::getConfig(){ 69 | _configLoaded = false; 70 | return _config; 71 | } 72 | 73 | 74 | 75 | 76 | //main config page that allows user to enter in configuration info 77 | void ESPHelper32WebConfig::handleGet() { 78 | String showReset; 79 | 80 | if(_resetSet){ 81 | showReset = "




\ 82 | (WARNING: Deletes all files on device!)
"; 83 | } 84 | else{ 85 | showReset = ""; 86 | } 87 | 88 | 89 | if(_preFill){ 90 | _server->send(200, "text/html", 91 | String("
\ 92 | hostname) + "\">
\ 93 | ssid) + "\">
\ 94 |
\ 95 |
\ 96 | mqttHost) + "\">
\ 97 | mqttUser) + "\">
\ 98 | mqttPort) + "\">
\ 99 |
\ 100 |
\ 101 |

Press Submit to update ESP8266 config file

" + showReset)); 102 | } 103 | 104 | 105 | 106 | else{ 107 | _server->send(200, "text/html", 108 | String("
\ 109 |
\ 110 |
\ 111 |
\ 112 |
\ 113 |
\ 114 |
\ 115 |
\ 116 |
\ 117 |
\ 118 |

Press Submit to update ESP8266 config file

" + showReset)); 119 | } 120 | 121 | } 122 | 123 | // If a POST request is made to URI /config 124 | void ESPHelper32WebConfig::handlePost() { 125 | 126 | //make sure that all the arguments exist and that at least an SSID and hostname have been entered 127 | if( ! _server->hasArg("ssid") || ! _server->hasArg("netPass") 128 | || ! _server->hasArg("hostname") || ! _server->hasArg("mqttHost") 129 | || ! _server->hasArg("mqttUser") || ! _server->hasArg("mqttPass") 130 | || ! _server->hasArg("mqttPort") || ! _server->hasArg("otaPassword") 131 | || _server->arg("ssid") == NULL || _server->arg("hostname") == NULL){ // If the POST request doesn't have username and password data 132 | 133 | _server->send(400, "text/plain", "400: Invalid Request - Did you make sure to specify an SSID and Hostname?"); // The request is invalid, so send HTTP status 400 134 | return; 135 | } 136 | 137 | //if there is an mqtt user/pass/port entered then there better also be a host! 138 | if((_server->arg("mqttUser") != NULL || _server->arg("mqttPass") != NULL) && _server->arg("mqttHost") == NULL){ 139 | 140 | _server->send(400, "text/plain", "400: Invalid Request - MQTT info specified without host"); // The request is invalid, so send HTTP status 400 141 | return; 142 | } 143 | 144 | 145 | //convert the Strings returned by _server->arg to char arrays that can be entered into netInfo 146 | 147 | 148 | //network pass 149 | if(_preFill && _server->arg("netPass").length() == 0){ 150 | strncpy(_newNetPass,_fillData->pass,64); 151 | _newNetPass[sizeof(_newNetPass) - 1] = '\0'; 152 | } 153 | else{_server->arg("netPass").toCharArray(_newNetPass, sizeof(_newNetPass));} 154 | 155 | //mqtt pass 156 | if(_preFill && _server->arg("mqttPass").length() == 0){ 157 | strncpy(_newMqttPass,_fillData->mqttPass,64); 158 | _newMqttPass[sizeof(_newNetPass) - 1] = '\0'; 159 | } 160 | else{_server->arg("mqttPass").toCharArray(_newMqttPass, sizeof(_newMqttPass));} 161 | 162 | //ota pass 163 | if(_preFill && _server->arg("otaPassword").length() == 0){ 164 | strncpy(_newOTAPass,_fillData->otaPassword,64); 165 | _newOTAPass[sizeof(_newNetPass) - 1] = '\0'; 166 | } 167 | else{_server->arg("otaPassword").toCharArray(_newOTAPass, sizeof(_newOTAPass));} 168 | 169 | //other non protected vars 170 | _server->arg("ssid").toCharArray(_newSsid, sizeof(_newSsid)); 171 | _server->arg("hostname").toCharArray(_newHostname, sizeof(_newHostname)); 172 | _server->arg("mqttHost").toCharArray(_newMqttHost, sizeof(_newMqttHost)); 173 | _server->arg("mqttUser").toCharArray(_newMqttUser, sizeof(_newMqttUser)); 174 | 175 | //the port is special because it doesnt get stored as a string so we take care of that 176 | 177 | if(_server->arg("mqttPort") != NULL){_newMqttPort = _server->arg("mqttPort").toInt();} 178 | else{_newMqttPort = 1883;} 179 | 180 | 181 | //tell the user that the config is loaded in and the module is restarting 182 | _server->send(200, "text/plain", "Config Info Loaded"); 183 | 184 | //enter in the new data 185 | _config = {mqttHost : _newMqttHost, 186 | mqttUser : _newMqttUser, 187 | mqttPass : _newMqttPass, 188 | mqttPort : _newMqttPort, 189 | ssid : _newSsid, 190 | pass : _newNetPass, 191 | otaPassword : _newOTAPass, 192 | hostname : _newHostname}; 193 | 194 | 195 | _configLoaded = true; 196 | } 197 | 198 | void ESPHelper32WebConfig::setSpiffsReset(const char* uri){ 199 | _resetURI = uri; 200 | _server->on(_resetURI, HTTP_POST, [this](){handleReset();}); 201 | _resetSet = true; 202 | } 203 | 204 | void ESPHelper32WebConfig::handleReset(){ 205 | //tell the user that the config is loaded in and the module is restarting 206 | _server->send(200, "text/plain", String("Resetting SPIFFS and restarting with default values")); 207 | 208 | SPIFFS.format(); 209 | ESP.restart(); 210 | } 211 | 212 | void ESPHelper32WebConfig::handleNotFound(){ 213 | _server->send(404, "text/plain", "404: Not found"); // Send HTTP status 404 (Not Found) when there's no handler for the URI in the request 214 | } 215 | -------------------------------------------------------------------------------- /src/ESPHelper32FS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ESPHelper32FS.cpp 3 | Copyright (c) 2019 ItKindaWorks All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper 7 | 8 | ESPHelper is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper. If not, see . 20 | */ 21 | 22 | #include "ESPHelper32FS.h" 23 | 24 | // StaticJsonBuffer* ESPHelper32FS::_tmpBufPtr = NULL; 25 | 26 | 27 | ESPHelper32FS::ESPHelper32FS() : _filename("/netConfig.json"){ 28 | _networkData = defaultConfig; 29 | } 30 | 31 | ESPHelper32FS::ESPHelper32FS(const char* filename){ 32 | _filename = filename; 33 | _networkData = defaultConfig; 34 | } 35 | 36 | bool ESPHelper32FS::begin(){ 37 | //load the config file 38 | if (SPIFFS.begin()) { 39 | // printFSinfo(); 40 | FSdebugPrintln("Loaded Filesystem"); 41 | return true; 42 | } 43 | return false; 44 | } 45 | 46 | void ESPHelper32FS::end(){ 47 | FSdebugPrintln("Filesystem Unloaded"); 48 | SPIFFS.end(); 49 | } 50 | 51 | 52 | 53 | 54 | void ESPHelper32FS::printFile(){ 55 | // this opens the file "f.txt" in read-mode 56 | File f = SPIFFS.open(_filename, "r"); 57 | 58 | if(f) { 59 | // we could open the file 60 | while(f.available()) { 61 | //Lets read line by line from the file 62 | String line = f.readStringUntil('\n'); 63 | FSdebugPrintln(line); 64 | } 65 | 66 | } 67 | f.close(); 68 | } 69 | 70 | 71 | 72 | void ESPHelper32FS::printFSinfo(){ 73 | FSdebugPrint("total bytes: "); 74 | FSdebugPrintln(SPIFFS.totalBytes); 75 | FSdebugPrint("used bytes: "); 76 | FSdebugPrintln(SPIFFS.usedBytes); 77 | } 78 | 79 | 80 | //load the file from FS into var buf 81 | bool ESPHelper32FS::loadFile(const char* filename, std::unique_ptr &buf){ 82 | 83 | FSdebugPrint("Opening File: "); 84 | FSdebugPrintln(filename); 85 | //open file as read only 86 | File configFile = SPIFFS.open(filename, "r"); 87 | 88 | //check to make sure opening was possible 89 | if (!configFile) { 90 | FSdebugPrintln("Failed to open config file"); 91 | configFile.close(); 92 | return false; 93 | } 94 | 95 | 96 | //make sure the config isnt too large to store in the JSON container 97 | size_t size = configFile.size(); 98 | FSdebugPrint("JSON File Size: "); 99 | FSdebugPrintln(size); 100 | if (size > JSON_SIZE) { 101 | FSdebugPrintln("JSON File too large - returning"); 102 | return false; 103 | } 104 | 105 | // Allocate a buffer to store contents of the file. 106 | std::unique_ptr newBuf(new char[size]); 107 | 108 | // We don't use String here because ArduinoJson library requires the input 109 | // buffer to be mutable. If you don't use ArduinoJson, you may as well 110 | // use configFile.readString instead. 111 | configFile.readBytes(newBuf.get(), size); 112 | 113 | //move the contents of newBuf into buf 114 | buf = std::move(newBuf); 115 | 116 | //close out the file 117 | configFile.close(); 118 | 119 | //sucess return true 120 | return true; 121 | 122 | } 123 | 124 | int8_t ESPHelper32FS::validateConfig(const char* filename){ 125 | 126 | //create a buffer for the file data 127 | std::unique_ptr buf(new char[JSON_SIZE]); 128 | loadFile(filename, buf); 129 | StaticJsonBuffer jsonBuffer; 130 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 131 | if(json.size() == 0){ return NO_CONFIG;} 132 | 133 | //return false if the file could not be parsed 134 | if (!json.success()) { 135 | FSdebugPrintln("JSON File corrupt"); 136 | 137 | return CANNOT_PARSE; 138 | } 139 | 140 | //check to make sure all netInfo keys exist 141 | if(!json.containsKey("ssid") 142 | || !json.containsKey("networkPass") 143 | || !json.containsKey("mqttIP") 144 | || !json.containsKey("mqttUSER") 145 | || !json.containsKey("mqttPASS") 146 | || !json.containsKey("mqttPORT") 147 | || !json.containsKey("hostname") 148 | || !json.containsKey("OTA_Password") 149 | || !json.containsKey("willTopic") 150 | || !json.containsKey("willMessage") 151 | || !json.containsKey("willQoS") 152 | || !json.containsKey("willRetain")){ 153 | 154 | FSdebugPrintln("Config incomplete"); 155 | 156 | return INCOMPLETE; 157 | } 158 | return GOOD_CONFIG; 159 | } 160 | 161 | bool ESPHelper32FS::loadNetworkConfig(){ 162 | 163 | //validate that the config file is good and if not create a new one 164 | if(validateConfig(_filename) != GOOD_CONFIG){ 165 | createConfig(&defaultConfig); 166 | return false; 167 | } 168 | 169 | 170 | else{ 171 | //create a buffer for the file data 172 | std::unique_ptr buf(new char[JSON_SIZE]); 173 | loadFile(_filename, buf); 174 | StaticJsonBuffer jsonBuffer; 175 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 176 | 177 | 178 | //copy the keys into char arrays 179 | strcpy(ssid, json["ssid"]); 180 | strcpy(netPass, json["networkPass"]); 181 | strcpy(hostName, json["hostname"]); 182 | strcpy(mqtt_ip, json["mqttIP"]); 183 | strcpy(otaPass, json["OTA_Password"]); 184 | strcpy(mqttPort, json["mqttPORT"]); 185 | strcpy(mqttUser, json["mqttUSER"]); 186 | strcpy(mqttPass, json["mqttPASS"]); 187 | strcpy(willTopic, json["willTopic"]); 188 | strcpy(willMessage, json["willMessage"]); 189 | strcpy(willQoS, json["willQoS"]); 190 | strcpy(willRetain, json["willRetain"]); 191 | 192 | int port = atoi(mqttPort); 193 | int numQoS = atoi(willQoS); 194 | int numRetain = atoi(willRetain); 195 | 196 | //then set that data into a netInfo object 197 | _networkData = {mqttHost : mqtt_ip, 198 | mqttUser : mqttUser, 199 | mqttPass : mqttPass, 200 | mqttPort : port, 201 | ssid : ssid, 202 | pass : netPass, 203 | otaPassword : otaPass, 204 | hostname : hostName, 205 | willTopic : willTopic, 206 | willMessage : willMessage, 207 | willQoS : numQoS, 208 | willRetain : numRetain}; 209 | 210 | 211 | 212 | FSdebugPrintln("Reading config file with values: "); 213 | FSdebugPrint("MQTT Server: "); 214 | FSdebugPrintln(_networkData.mqttHost); 215 | FSdebugPrint("MQTT User: "); 216 | FSdebugPrintln(_networkData.mqttUser); 217 | FSdebugPrint("MQTT Password: "); 218 | FSdebugPrintln(_networkData.mqttPass); 219 | FSdebugPrint("MQTT Port: "); 220 | FSdebugPrintln(_networkData.mqttPort); 221 | FSdebugPrint("SSID: "); 222 | FSdebugPrintln(_networkData.ssid); 223 | FSdebugPrint("Network Pass: "); 224 | FSdebugPrintln(_networkData.pass); 225 | FSdebugPrint("Device Name: "); 226 | FSdebugPrintln(_networkData.hostname); 227 | FSdebugPrint("OTA Password: "); 228 | FSdebugPrintln(_networkData.otaPassword); 229 | FSdebugPrint("Last Will Topic: "); 230 | FSdebugPrintln(_networkData.willTopic); 231 | FSdebugPrint("Last Will Message: "); 232 | FSdebugPrintln(_networkData.willMessage); 233 | FSdebugPrint("Last Will QoS: "); 234 | FSdebugPrintln(_networkData.willQoS); 235 | FSdebugPrint("Last Will Retain: "); 236 | FSdebugPrintln(_networkData.willRetain); 237 | 238 | // configFile.close(); 239 | } 240 | 241 | 242 | return true; 243 | } 244 | 245 | 246 | //add a key to a json file 247 | bool ESPHelper32FS::addKey(const char* keyName, const char* value){ 248 | if(_filename != ""){ 249 | return addKey(keyName, value, _filename); 250 | } 251 | else{return false;} 252 | } 253 | 254 | //add a key to a json file 255 | bool ESPHelper32FS::addKey(const char* keyName, const char* value, const char* filename){ 256 | if(!SPIFFS.exists(filename)){ 257 | File configFile = SPIFFS.open(filename, "w"); 258 | configFile.close(); 259 | } 260 | 261 | //create a buffer for the file data 262 | std::unique_ptr buf(new char[JSON_SIZE]); 263 | loadFile(filename, buf); 264 | StaticJsonBuffer jsonBuffer; 265 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 266 | if(json.success()){ 267 | //add the key to the json object 268 | json[keyName] = value; 269 | FSdebugPrint("Added Key "); 270 | FSdebugPrint(keyName); 271 | FSdebugPrint(" With Value "); 272 | FSdebugPrintln(value); 273 | 274 | //save the new config with added key 275 | saveConfig(json, filename); 276 | return true; 277 | } 278 | 279 | 280 | StaticJsonBuffer blankBuffer; 281 | JsonObject& blankJson = blankBuffer.createObject(); 282 | if(blankJson.success()){ 283 | //add the key to the json object 284 | blankJson[keyName] = value; 285 | FSdebugPrint("Added Key "); 286 | FSdebugPrint(keyName); 287 | FSdebugPrint(" With Value "); 288 | FSdebugPrintln(value); 289 | 290 | //save the new config with added key 291 | saveConfig(blankJson, filename); 292 | return true; 293 | } 294 | 295 | return false; 296 | } 297 | 298 | //read a key from a json file 299 | String ESPHelper32FS::loadKey(const char* keyName){ 300 | if(_filename != ""){ 301 | return loadKey(keyName, _filename); 302 | } 303 | else {return String();} 304 | } 305 | 306 | //read a key from a json file 307 | String ESPHelper32FS::loadKey(const char* keyName, const char* filename){ 308 | static String returnString = ""; 309 | 310 | //create a buffer for the file data 311 | std::unique_ptr buf(new char[JSON_SIZE]); 312 | loadFile(filename, buf); 313 | StaticJsonBuffer jsonBuffer; 314 | JsonObject& json = jsonBuffer.parseObject(buf.get()); 315 | if(json.success()){ 316 | 317 | //if the key does not exist then return an empty string 318 | if(!json.containsKey(keyName)){ 319 | FSdebugPrintln("Key not found"); 320 | 321 | return returnString; 322 | } 323 | 324 | //set the return value to that of the key 325 | returnString = (const char*)json[keyName]; 326 | } 327 | 328 | 329 | //return the key (blank if file could not be opened) 330 | return returnString; 331 | } 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | netInfo ESPHelper32FS::getNetInfo(){ 340 | return _networkData; 341 | } 342 | 343 | bool ESPHelper32FS::createConfig(const char* filename){ 344 | return createConfig(_filename, 345 | defaultConfig.ssid, 346 | defaultConfig.pass, 347 | defaultConfig.hostname, 348 | defaultConfig.mqttHost, 349 | defaultConfig.mqttUser, 350 | defaultConfig.mqttPass, 351 | defaultConfig.mqttPort, 352 | defaultConfig.otaPassword, 353 | defaultConfig.willTopic, 354 | defaultConfig.willMessage, 355 | defaultConfig.willQoS, 356 | defaultConfig.willRetain); 357 | } 358 | 359 | 360 | bool ESPHelper32FS::createConfig(const netInfo* config){ 361 | return createConfig(_filename, 362 | config->ssid, 363 | config->pass, 364 | config->hostname, 365 | config->mqttHost, 366 | config->mqttUser, 367 | config->mqttPass, 368 | config->mqttPort, 369 | config->otaPassword, 370 | config->willTopic, 371 | config->willMessage, 372 | config->willQoS, 373 | config->willRetain); 374 | } 375 | 376 | bool ESPHelper32FS::createConfig(const netInfo* config, const char* filename){ 377 | return createConfig(filename, 378 | config->ssid, 379 | config->pass, 380 | config->hostname, 381 | config->mqttHost, 382 | config->mqttUser, 383 | config->mqttPass, 384 | config->mqttPort, 385 | config->otaPassword, 386 | config->willTopic, 387 | config->willMessage, 388 | config->willQoS, 389 | config->willRetain); 390 | } 391 | 392 | bool ESPHelper32FS::createConfig( const char* filename, 393 | const char* _ssid, 394 | const char* _networkPass, 395 | const char* _deviceName, 396 | const char* _mqttIP, 397 | const char* _mqttUser, 398 | const char* _mqttPass, 399 | const int _mqttPort, 400 | const char* _otaPass, 401 | const char* _willTopic, 402 | const char* _willMessage, 403 | const int _willQoS, 404 | const int _willRetain) { 405 | 406 | FSdebugPrintln("Generating new config file with values: "); 407 | FSdebugPrint("SSID: "); 408 | FSdebugPrintln(_ssid); 409 | FSdebugPrint("Network Pass: "); 410 | FSdebugPrintln(_networkPass); 411 | FSdebugPrint("hostname: "); 412 | FSdebugPrintln(_deviceName); 413 | FSdebugPrint("MQTT Server: "); 414 | FSdebugPrintln(_mqttIP); 415 | FSdebugPrint("MQTT Username: "); 416 | FSdebugPrintln(_mqttUser); 417 | FSdebugPrint("MQTT Password: "); 418 | FSdebugPrintln(_mqttPass); 419 | FSdebugPrint("MQTT PORT: "); 420 | FSdebugPrintln(_mqttPort); 421 | FSdebugPrint("OTA Password: "); 422 | FSdebugPrintln(_otaPass); 423 | FSdebugPrint("Last Will Topic: "); 424 | FSdebugPrintln(_willTopic); 425 | FSdebugPrint("Last Will Message: "); 426 | FSdebugPrintln(_willMessage); 427 | FSdebugPrint("Last Will QoS: "); 428 | FSdebugPrintln(_willQoS); 429 | FSdebugPrint("Last Will Retain: "); 430 | FSdebugPrintln(_willRetain); 431 | 432 | char portString[10]; 433 | sprintf(portString, "%d", _mqttPort); 434 | 435 | char qoSString[10]; 436 | sprintf(qoSString, "%d", _willQoS); 437 | 438 | char retainString[10]; 439 | sprintf(retainString, "%d", _willRetain); 440 | 441 | FSdebugPrintln("creating json"); 442 | 443 | //create a buffer for the file data 444 | std::unique_ptr buf(new char[JSON_SIZE]); 445 | loadFile(filename, buf); 446 | StaticJsonBuffer jsonBuffer; 447 | 448 | //if a json file already exists then use that as the base 449 | JsonObject& json = validateConfig(filename) == GOOD_CONFIG ? jsonBuffer.parseObject(buf.get()) : jsonBuffer.createObject(); 450 | 451 | json["ssid"] = _ssid; 452 | json["networkPass"] = _networkPass; 453 | json["hostname"] = _deviceName; 454 | json["mqttIP"] = _mqttIP; 455 | json["mqttPORT"] = portString; 456 | json["mqttUSER"] = _mqttUser; 457 | json["mqttPASS"] = _mqttPass; 458 | json["OTA_Password"] = _otaPass; 459 | json["willTopic"] = _willTopic; 460 | json["willMessage"] = _willMessage; 461 | json["willQoS"] = qoSString; 462 | json["willRetain"] = retainString; 463 | 464 | FSdebugPrintln("done"); 465 | 466 | return saveConfig(json, filename); 467 | } 468 | 469 | bool ESPHelper32FS::saveConfig(JsonObject& json, const char* filename) { 470 | FSdebugPrintln("Saving File..."); 471 | 472 | if(SPIFFS.exists(filename)){ 473 | SPIFFS.remove(filename); 474 | } 475 | 476 | FSdebugPrintln("Opening File as write only"); 477 | 478 | 479 | File configFile = SPIFFS.open(filename, "w"); 480 | if (!configFile) { 481 | FSdebugPrintln("Failed to open config file for writing"); 482 | return false; 483 | } 484 | 485 | FSdebugPrintln("File open now writing"); 486 | 487 | json.printTo(configFile); 488 | 489 | FSdebugPrintln("Writing done now closing"); 490 | 491 | configFile.close(); 492 | 493 | FSdebugPrintln("done."); 494 | return true; 495 | } 496 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /src/ESPHelper32.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | ESPHelper32.cpp 3 | Copyright (c) 2019 ItKindaWorks Inc All right reserved. 4 | github.com/ItKindaWorks 5 | 6 | This file is part of ESPHelper32 7 | 8 | ESPHelper32 is free software: you can redistribute it and/or modify 9 | it under the terms of the GNU General Public License as published by 10 | the Free Software Foundation, either version 3 of the License, or 11 | (at your option) any later version. 12 | 13 | ESPHelper32 is distributed in the hope that it will be useful, 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | GNU General Public License for more details. 17 | 18 | You should have received a copy of the GNU General Public License 19 | along with ESPHelper32. If not, see . 20 | */ 21 | 22 | 23 | #include "ESPHelper32.h" 24 | #include "ESPHelper32FS.h" 25 | 26 | 27 | //empy initializer 28 | ESPHelper32::ESPHelper32(){ 29 | init("", "", "", "", "", 1883, "defaultWillTopic", "", 0, 1); 30 | } 31 | 32 | 33 | //Yes yes I know how messy it is to have all these different constructors that all call init AND 34 | //have a bunch of overloaded init methods that do the same thing more or less but this lets me 35 | //instantiate a blank ESPHelper globally and then in setup configure it without having to use new 36 | 37 | 38 | //initializer with single netInfo network 39 | ESPHelper32::ESPHelper32(const netInfo *startingNet){ 40 | init(startingNet->ssid, startingNet->pass, startingNet->mqttHost, startingNet->mqttUser, startingNet->mqttPass, startingNet->mqttPort, startingNet->willTopic, startingNet->willMessage, startingNet->willQoS, startingNet->willRetain); 41 | } 42 | 43 | //initializer with single network information and MQTT broker 44 | ESPHelper32::ESPHelper32(const char *ssid, const char *pass, const char *mqttIP){ 45 | init(ssid, pass, mqttIP, "", "", 1883, "defaultWillTopic", "", 0, 1); 46 | } 47 | 48 | //initializer with single network information, MQTT broker and MQTT Last Will 49 | ESPHelper32::ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *willTopic, const char *willMessage){ 50 | init(ssid, pass, mqttIP, "", "", 1883, willTopic, willMessage, 0, 1); 51 | } 52 | 53 | //initializer with single network information, MQTT broker, MQTT Last Will and Testament options 54 | ESPHelper32::ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain){ 55 | init(ssid, pass, mqttIP, "", "", 1883, willTopic, willMessage, 0, 1); 56 | } 57 | 58 | //initializer with single network information (MQTT user/pass) 59 | ESPHelper32::ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort){ 60 | init(ssid, pass, mqttIP, mqttUser, mqttPass, mqttPort, "defaultWillTopic", "", 0, 1); 61 | } 62 | 63 | //initializer with single network information (MQTT user/pass) + Testament 64 | ESPHelper32::ESPHelper32(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain){ 65 | init(ssid, pass, mqttIP, mqttUser, mqttPass, mqttPort, willTopic, willMessage, willQoS, willRetain); 66 | } 67 | 68 | //initializer with single network information (no MQTT) 69 | ESPHelper32::ESPHelper32(const char *ssid, const char *pass){ 70 | init(ssid, pass, "", "", "", 1883, "defaultWillTopic","",0,1); 71 | } 72 | 73 | //initializer with netInfo array and index 74 | ESPHelper32::ESPHelper32(netInfo *netList[], uint8_t netCount, uint8_t startIndex){ 75 | _netList = netList; 76 | _netCount = netCount; 77 | _currentIndex = startIndex; 78 | 79 | //enable hopping since we have an array of networks to use 80 | _hoppingAllowed = true; 81 | 82 | //disable ota by default 83 | _useOTA = false; 84 | 85 | netInfo* tmp = netList[constrain(_currentIndex, 0, _netCount)]; 86 | init(tmp->ssid, tmp->pass, tmp->mqttHost, tmp->mqttUser, tmp->mqttPass, tmp->mqttPort, tmp->willTopic, tmp->willMessage, tmp->willQoS, tmp->willRetain); 87 | } 88 | 89 | ESPHelper32::ESPHelper32(const char* configFile){ 90 | netInfo ESPConfig = loadConfigFile(configFile); 91 | init(ESPConfig.ssid, ESPConfig.pass, ESPConfig.mqttHost, ESPConfig.mqttUser, ESPConfig.mqttPass, ESPConfig.mqttPort, ESPConfig.willTopic, ESPConfig.willMessage, ESPConfig.willQoS, ESPConfig.willRetain); 92 | } 93 | 94 | 95 | //initialize the netinfo data and reset wifi. set hopping and OTA to off 96 | void ESPHelper32::init(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain){ 97 | //diconnect from and previous wifi networks 98 | WiFi.softAPdisconnect(); 99 | WiFi.disconnect(); 100 | 101 | _currentNet.ssid = ssid; 102 | _currentNet.pass = pass; 103 | _currentNet.mqttHost= mqttIP; 104 | _currentNet.mqttUser = mqttUser; 105 | _currentNet.mqttPass = mqttPass; 106 | _currentNet.mqttPort = mqttPort; 107 | _currentNet.willTopic = willTopic; 108 | _currentNet.willMessage = willMessage; 109 | _currentNet.willQoS = willQoS; 110 | _currentNet.willRetain = willRetain; 111 | 112 | 113 | //validate various bits of network/MQTT info 114 | validateConfig(); 115 | } 116 | 117 | void ESPHelper32::validateConfig(){ 118 | //network pass 119 | if(_currentNet.pass[0] == '\0'){_passSet = false;} 120 | else{_passSet = true;} 121 | 122 | //ssid 123 | if(_currentNet.ssid[0] == '\0'){_ssidSet = false;} 124 | else{_ssidSet = true;} 125 | 126 | //mqtt host 127 | if(_currentNet.mqttHost[0] == '\0'){_mqttSet = false;} 128 | else{_mqttSet = true;} 129 | 130 | //mqtt port 131 | if(_currentNet.mqttPort == 0){_currentNet.mqttPort = 1883;} 132 | 133 | //mqtt username 134 | if(_currentNet.mqttUser[0] == '\0'){_mqttUserSet = false;} 135 | else{_mqttUserSet = true;} 136 | 137 | //mqtt password 138 | if(_currentNet.mqttPass[0] == '\0'){_mqttPassSet = false;} 139 | else{_mqttPassSet = true;} 140 | 141 | //Will Topic 142 | if(_currentNet.willTopic[0] == '\0'){_willTopicSet = false;} 143 | else{_willTopicSet = true;} 144 | 145 | //Will Message 146 | if(_currentNet.willMessage[0] == '\0'){_willMessageSet = false;} 147 | else{_willMessageSet = true;} 148 | 149 | } 150 | 151 | bool ESPHelper32::begin(const char* filename){ 152 | _currentNet = loadConfigFile(filename); 153 | bool returnVal = begin(_currentNet.ssid, _currentNet.pass, _currentNet.mqttHost, _currentNet.mqttUser, _currentNet.mqttPass, _currentNet.mqttPort, _currentNet.willTopic, _currentNet.willMessage, _currentNet.willQoS, _currentNet.willRetain); 154 | 155 | return returnVal; 156 | } 157 | 158 | bool ESPHelper32::begin(const netInfo *startingNet){ 159 | return begin(startingNet->ssid, startingNet->pass, startingNet->mqttHost, startingNet->mqttUser, startingNet->mqttPass, startingNet->mqttPort, startingNet->willTopic, startingNet->willMessage, startingNet->willQoS, startingNet->willRetain); 160 | } 161 | 162 | //initializer with single network information and MQTT broker 163 | bool ESPHelper32::begin(const char *ssid, const char *pass, const char *mqttIP){ 164 | return begin(ssid, pass, mqttIP, "", "", 1883, "defaultWillTopic","",0,1); 165 | } 166 | 167 | //initializer with single network information (no MQTT) 168 | bool ESPHelper32::begin(const char *ssid, const char *pass){ 169 | return begin(ssid, pass, "", "", "", 1883, "defaultWillTopic","",0,1); 170 | } 171 | 172 | bool ESPHelper32::begin(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort, const char *willTopic, const char *willMessage, const int willQoS, const int willRetain){ 173 | init(ssid, pass, mqttIP, mqttUser, mqttPass, mqttPort, willTopic, willMessage, willQoS, willRetain); 174 | return begin(); 175 | } 176 | 177 | bool ESPHelper32::begin(const char *ssid, const char *pass, const char *mqttIP, const char *mqttUser, const char *mqttPass, const int mqttPort){ 178 | return begin(ssid, pass, mqttIP, mqttUser, mqttPass, mqttPort, "defaultWillTopic","",0,1); 179 | } 180 | //start the wifi & mqtt systems and attempt connection (currently blocking) 181 | //true on: parameter check validated 182 | //false on: parameter check failed 183 | bool ESPHelper32::begin(){ 184 | if(_ssidSet){ 185 | //set the wifi mode to station and begin the wifi (connect using either ssid or ssid/pass) 186 | WiFi.mode(WIFI_STA); 187 | if(_passSet){WiFi.begin(_currentNet.ssid, _currentNet.pass);} 188 | else{WiFi.begin(_currentNet.ssid);} 189 | 190 | // Generate client name based on MAC address and last 8 bits of microsecond counter 191 | _clientName += "esp32-"; 192 | uint8_t mac[6]; 193 | WiFi.macAddress(mac); 194 | _clientName += macToStr(mac); 195 | 196 | //as long as an mqtt ip has been set create an instance of PubSub for client 197 | if(_mqttSet){ 198 | //make mqtt client use either the secure or non-secure wifi client depending on the setting 199 | 200 | //make mqtt client use either the secure or non-secure wifi client depending on the setting 201 | if(_useSecureClient){client = PubSubClient(_currentNet.mqttHost, _currentNet.mqttPort, wifiClientSecure);} 202 | else{client = PubSubClient(_currentNet.mqttHost, _currentNet.mqttPort, wifiClient);} 203 | 204 | 205 | //set the mqtt message callback if needed 206 | if(_mqttCallbackSet){ 207 | client.setCallback(_mqttCallback); 208 | } 209 | } 210 | 211 | //define a dummy instance of mqtt so that it is instantiated if no mqtt ip is set 212 | else{ 213 | //make mqtt client use either the secure or non-secure wifi client depending on the setting 214 | //(this shouldnt be needed if making a dummy connection since the idea would be that there wont be mqtt in this case) 215 | if(_useSecureClient){client = PubSubClient("192.0.2.0", _currentNet.mqttPort, wifiClientSecure);} 216 | else{client = PubSubClient("192.0.2.0", _currentNet.mqttPort, wifiClient);} 217 | 218 | } 219 | 220 | 221 | //ota event handlers 222 | ArduinoOTA.onStart([]() {/* ota start code */}); 223 | ArduinoOTA.onEnd([]() { 224 | //give the arduino a bit of time to finish up any remaining network activity 225 | delay(500); 226 | //on ota end we disconnect from wifi cleanly before restarting. 227 | WiFi.softAPdisconnect(); 228 | WiFi.disconnect(); 229 | int timeout = 0; 230 | //max timeout of 2seconds before just dropping out and restarting 231 | while(WiFi.status() != WL_DISCONNECTED && timeout < 200){ 232 | delay(10); 233 | timeout++; 234 | } 235 | }); 236 | ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {/* ota progress code */}); 237 | ArduinoOTA.onError([](ota_error_t error) {/* ota error code */}); 238 | 239 | //initially attempt to connect to wifi when we begin (but only block for 2 seconds before timing out) 240 | int timeout = 0; //counter for begin connection attempts 241 | while (((!client.connected() && _mqttSet) || WiFi.status() != WL_CONNECTED) && timeout < 200 ) { //max 2 sec before timeout 242 | reconnect(); 243 | delay(10); 244 | timeout++; 245 | } 246 | 247 | //attempt to start ota if needed 248 | OTA_begin(); 249 | 250 | //mark the system as started and return 251 | _hasBegun = true; 252 | return true; 253 | } 254 | 255 | //if no ssid was set even then dont try to begin and return false 256 | return false; 257 | } 258 | 259 | //end the instance of ESPHelper (shutdown wifi, ota, mqtt) 260 | void ESPHelper32::end(){ 261 | ESPHelper32FS::end(); 262 | OTA_disable(); 263 | client.disconnect(); 264 | WiFi.softAPdisconnect(); 265 | WiFi.disconnect(); 266 | 267 | int timeout = 0; 268 | while(WiFi.status() != WL_DISCONNECTED && timeout < 200){ 269 | delay(10); 270 | timeout++; 271 | } 272 | 273 | _connectionStatus = NO_CONNECTION; 274 | 275 | } 276 | 277 | 278 | //attempts to load a config file from the filesystem - returns blank netInfo on failure 279 | //This will also create a new config with default values if none currently exists or is corrupted. 280 | netInfo ESPHelper32::loadConfigFile(const char* filename){ 281 | bool configLoaded = false; 282 | netInfo returnConfig; 283 | 284 | //create a static instance of the FS handler so that one isnt created by default but is left in memory if we 285 | //need to load a config 286 | static ESPHelper32FS configLoader(filename); 287 | 288 | //attempt to load the config 3 times (really if it fails once it's probably going to fail again but why not try...) 289 | for(int tryCount = 0; tryCount < 3 && configLoaded == false; tryCount++){ 290 | 291 | //attempt to start the filesystem 292 | if(configLoader.begin()){ 293 | //attempt to load a configuration 294 | configLoaded = configLoader.loadNetworkConfig(); 295 | 296 | //if no config loaded (either from corruption or no file), create a new config and close the FS 297 | if(!configLoaded){ 298 | debugPrintln("Could not load config - generating new config and restarting..."); 299 | configLoader.createConfig(filename); 300 | configLoader.end(); 301 | debugPrintln("Config File loading failed. Retrying..."); 302 | } 303 | 304 | //if there is a good config, load it and close the FS 305 | else{ 306 | debugPrintln("Config loaded, getting info"); 307 | returnConfig = configLoader.getNetInfo(); 308 | configLoader.end(); 309 | debugPrintln("done."); 310 | } 311 | } 312 | } 313 | 314 | //return either a loaded config or a blank one 315 | return returnConfig; 316 | } 317 | 318 | //attempts to saves a new config file with a given netInfo and filename 319 | //Returns true on success /// false on failure 320 | bool ESPHelper32::saveConfigFile(const netInfo config, const char* filename){ 321 | 322 | //init ESPHelper FS and begin 323 | ESPHelper32FS configLoader(filename); 324 | if(configLoader.begin()){ 325 | configLoader.createConfig(&config); 326 | configLoader.end(); 327 | return true; 328 | } 329 | 330 | //if the FS could not be started then return false (failed) 331 | return false; 332 | } 333 | 334 | 335 | //enables the use of a secure (SSL) connection to an MQTT broker. 336 | //(Make sure your mqtt port is set to one expecting a secure connection) 337 | void ESPHelper32::useSecureClient(const char* fingerprint){ 338 | _fingerprint = fingerprint; 339 | 340 | //fall back to wifi only connection if it was previously at full connection 341 | //(because we just changed how the device is going to connect to the mqtt broker) 342 | if(setConnectionStatus() == FULL_CONNECTION){ 343 | _connectionStatus = WIFI_ONLY; 344 | } 345 | 346 | //if use of secure connection is set retroactivly (after begin), then re-instantiate client 347 | if(_hasBegun){client = PubSubClient(_currentNet.mqttHost, _currentNet.mqttPort, wifiClientSecure);} 348 | 349 | //flag use of secure client 350 | _useSecureClient = true; 351 | } 352 | 353 | 354 | //enables and sets up broadcast mode rather than station mode. This allows users to create a network from the ESP 355 | //and upload using OTA even if there is no network already present. This disables all MQTT connections 356 | void ESPHelper32::broadcastMode(const char* ssid, const char* password, const IPAddress ip){ 357 | //disconnect from any previous wifi networks (max timeout of 2 seconds) 358 | WiFi.softAPdisconnect(); 359 | WiFi.disconnect(); 360 | int timeout = 0; 361 | while(WiFi.status() != WL_DISCONNECTED && timeout < 200){ 362 | delay(10); 363 | timeout++; 364 | } 365 | //set the mode for access point 366 | WiFi.mode(WIFI_AP); 367 | //config the AP 368 | WiFi.softAPConfig(ip, ip, IPAddress(255, 255, 255, 0)); 369 | //set the ssid and password 370 | WiFi.softAP(ssid, password); 371 | 372 | //update the connection status 373 | _connectionStatus = BROADCAST; 374 | _broadcastIP = ip; 375 | strcpy(_broadcastSSID, ssid); 376 | strcpy(_broadcastPASS, password); 377 | 378 | } 379 | 380 | //disable broadcast mode and reset to station mode (causes a call to begin - may want to change this in the future...) 381 | void ESPHelper32::disableBroadcast(){ 382 | //disconnect from any previous wifi networks (max timeout of 2 seconds) 383 | WiFi.softAPdisconnect(); 384 | WiFi.disconnect(); 385 | int timeout = 0; 386 | while(WiFi.status() != WL_DISCONNECTED && timeout < 200){ 387 | delay(10); 388 | timeout++; 389 | } 390 | _connectionStatus = NO_CONNECTION; 391 | begin(); 392 | } 393 | 394 | //main loop - should be called as often as possible - handles wifi/mqtt connection and mqtt handler 395 | //true on: network/server connected 396 | //false on: network or server disconnected 397 | int ESPHelper32::loop(){ 398 | if(_ssidSet){ 399 | 400 | //check for good connections and attempt a reconnect if needed 401 | if (((_mqttSet && !client.connected()) || setConnectionStatus() < WIFI_ONLY) && _connectionStatus != BROADCAST) { 402 | reconnect(); 403 | } 404 | 405 | //run the wifi loop as long as the connection status is at a minimum of BROADCAST 406 | if(_connectionStatus >= BROADCAST){ 407 | 408 | //run the MQTT loop if we have a full connection 409 | if(_connectionStatus == FULL_CONNECTION){client.loop();} 410 | 411 | //run the heartbeat 412 | heartbeat(); 413 | 414 | //check for whether we want to use OTA and whether the system is running 415 | if(_useOTA && _OTArunning) {ArduinoOTA.handle();} 416 | 417 | //if we want to use OTA but its not running yet, start it up. 418 | else if(_useOTA && !_OTArunning){ 419 | OTA_begin(); 420 | ArduinoOTA.handle(); 421 | } 422 | 423 | 424 | return _connectionStatus; 425 | } 426 | } 427 | 428 | //return -1 for no connection because of bad network info 429 | return -1; 430 | } 431 | 432 | //subscribe to a speicifc topic (does not add to topic list) 433 | //true on: subscription success 434 | //false on: subscription failed (either from PubSub lib or network is disconnected) 435 | bool ESPHelper32::subscribe(const char* topic, int qos){ 436 | if(_connectionStatus == FULL_CONNECTION){ 437 | //set the return value to the output of subscribe 438 | bool returnVal = client.subscribe(topic, qos); 439 | 440 | //loop mqtt client 441 | client.loop(); 442 | return returnVal; 443 | } 444 | 445 | //if not fully connected return false 446 | else{return false;} 447 | } 448 | 449 | //add a topic to the list of subscriptions and attempt to subscribe to the topic on the spot 450 | //true on: subscription added to list (does not guarantee that the topic was subscribed to, only that it was added to the list) 451 | //false on: subscription not added to list 452 | bool ESPHelper32::addSubscription(const char* topic){ 453 | //default return value is false 454 | bool subscribed = false; 455 | 456 | //loop throough finding the next available slot for a subscription and add it 457 | for(int i = 0; i < MAX_SUBSCRIPTIONS; i++){ 458 | if(_subscriptions[i].isUsed == false){ 459 | _subscriptions[i].topic = topic; 460 | _subscriptions[i].isUsed = true; 461 | subscribed = true; 462 | break; 463 | } 464 | } 465 | 466 | //if added to the list, subscibe to the topic 467 | if(subscribed){subscribe(topic, _qos);} 468 | 469 | return subscribed; 470 | } 471 | 472 | //loops through list of subscriptions and attempts to subscribe to all topics 473 | void ESPHelper32::resubscribe(){ 474 | for(int i = 0; i < MAX_SUBSCRIPTIONS; i++){ 475 | if(_subscriptions[i].isUsed){ 476 | subscribe(_subscriptions[i].topic, _qos); 477 | yield(); 478 | } 479 | } 480 | } 481 | 482 | //attempts to remove a topic from the topic list 483 | //true on: subscription removed from list (does not guarantee that the topic was unsubscribed from, only that it was removed from the list) 484 | //false on: topic was not found in list and therefore cannot be removed 485 | bool ESPHelper32::removeSubscription(const char* topic){ 486 | bool returnVal = false; 487 | String topicStr = topic; 488 | 489 | //loop through all subscriptions 490 | for(int i = 0; i < MAX_SUBSCRIPTIONS; i++){ 491 | //if an element is used, check for it being the one we want to remove 492 | if(_subscriptions[i].isUsed){ 493 | String subStr = _subscriptions[i].topic; 494 | if(subStr.equals(topicStr)){ 495 | //reset the used flag to false 496 | _subscriptions[i].isUsed = false; 497 | 498 | //unsubscribe 499 | client.unsubscribe(_subscriptions[i].topic); 500 | returnVal = true; 501 | break; 502 | } 503 | } 504 | } 505 | 506 | return returnVal; 507 | } 508 | 509 | //manually unsubscribes from a topic (This is basically just a wrapper for the pubsubclient function) 510 | bool ESPHelper32::unsubscribe(const char* topic){ 511 | return client.unsubscribe(topic); 512 | } 513 | 514 | //publish to a specified topic 515 | void ESPHelper32::publish(const char* topic, const char* payload){ 516 | publish(topic, payload, false); 517 | } 518 | 519 | //publish to a specified topic with a given retain level 520 | void ESPHelper32::publish(const char* topic, const char* payload, bool retain){ 521 | client.publish(topic, payload, retain); 522 | } 523 | 524 | //set the callback function for MQTT 525 | void ESPHelper32::setMQTTCallback(MQTT_CALLBACK_SIGNATURE){ 526 | _mqttCallback = callback; 527 | 528 | //only set the callback if using mqtt AND the system has already been started. Otherwise just save it for later 529 | if(_hasBegun && _mqttSet) { 530 | client.setCallback(_mqttCallback); 531 | } 532 | _mqttCallbackSet = true; 533 | } 534 | 535 | //legacy funtion - here for compatibility. Sets the callback function for MQTT (see function above) 536 | bool ESPHelper32::setCallback(MQTT_CALLBACK_SIGNATURE){ 537 | setMQTTCallback(callback); 538 | return true; 539 | } 540 | 541 | 542 | 543 | 544 | //sets a custom function to run when connection to wifi is established 545 | void ESPHelper32::setWifiCallback(void (*callback)()){ 546 | _wifiCallback = callback; 547 | _wifiCallbackSet = true; 548 | } 549 | 550 | //attempts to connect to wifi & mqtt server if not connected 551 | void ESPHelper32::reconnect() { 552 | static int tryCount = 0; 553 | 554 | if(reconnectMetro.check() && _connectionStatus != BROADCAST && setConnectionStatus() != FULL_CONNECTION){ 555 | debugPrintln("Attempting WiFi Connection..."); 556 | //attempt to connect to the wifi if connection is lost 557 | if(WiFi.status() != WL_CONNECTED){ 558 | _connectionStatus = NO_CONNECTION; 559 | 560 | //increment try count each time it cannot connect (this is used to determine when to hop to a new network) 561 | tryCount++; 562 | if(tryCount == 20){ 563 | //change networks (if possible) when we have tried to connnect 20 times unsucessfully 564 | changeNetwork(); 565 | tryCount = 0; 566 | return; 567 | } 568 | } 569 | 570 | // make sure we are connected to WIFI before attemping to reconnect to MQTT 571 | //----note---- maybe want to reset tryCount whenever we succeed at getting wifi connection? 572 | if(WiFi.status() == WL_CONNECTED){ 573 | //if the wifi previously wasnt connected but now is, run the callback 574 | if(_connectionStatus < WIFI_ONLY && _wifiCallbackSet){ 575 | _wifiCallback(); 576 | } 577 | 578 | 579 | debugPrintln("\n---WIFI Connected!---"); 580 | _connectionStatus = WIFI_ONLY; 581 | 582 | 583 | //attempt to connect to mqtt when we finally get connected to WiFi 584 | if(_mqttSet){ 585 | 586 | static int timeout = 0; //allow a max of 5 mqtt connection attempts before timing out 587 | if (!client.connected() && timeout < 5) { 588 | debugPrint("Attemping MQTT connection"); 589 | 590 | 591 | int connected = 0; 592 | 593 | //connect to mqtt with user/pass 594 | if (_mqttUserSet && _willMessageSet) { 595 | debugPrintln(" - Using user & last will"); 596 | debugPrintln(String("\t Client Name: " + String(_clientName.c_str()))); 597 | debugPrintln(String("\t User Name: " + String(_currentNet.mqttUser))); 598 | debugPrintln(String("\t Password: " + String(_currentNet.mqttPass))); 599 | debugPrintln(String("\t Will Topic: " + String(_currentNet.willTopic))); 600 | debugPrintln(String("\t Will QOS: " + String(_currentNet.willQoS))); 601 | debugPrintln(String("\t Will Retain?: " + String(_currentNet.willRetain))); 602 | debugPrintln(String("\t Will Message: " + String(_currentNet.willMessage))); 603 | connected = client.connect((char*) _clientName.c_str(), _currentNet.mqttUser, _currentNet.mqttPass, _currentNet.willTopic, (int) _currentNet.willQoS, _currentNet.willRetain, (char*) _currentNet.willMessage); 604 | } 605 | 606 | //connect to mqtt without credentials 607 | else if (!_mqttUserSet && _willMessageSet) { 608 | debugPrintln(" - Using last will"); 609 | debugPrintln(String("\t Client Name: " + String(_clientName.c_str()))); 610 | debugPrintln(String("\t Will Topic: " + String(_currentNet.willTopic))); 611 | debugPrintln(String("\t Will QOS: " + String(_currentNet.willQoS))); 612 | debugPrintln(String("\t Will Retain?: " + String(_currentNet.willRetain))); 613 | debugPrintln(String("\t Will Message: " + String(_currentNet.willMessage))); 614 | connected = client.connect((char*) _clientName.c_str(), _currentNet.willTopic, (int) _currentNet.willQoS, _currentNet.willRetain, (char*) _currentNet.willMessage); 615 | } else if (_mqttUserSet && !_willMessageSet) { 616 | debugPrintln(" - Using user"); 617 | debugPrintln(String("\t Client Name: " + String(_clientName.c_str()))); 618 | debugPrintln(String("\t User Name: " + String(_currentNet.mqttUser))); 619 | debugPrintln(String("\t Password: " + String(_currentNet.mqttPass))); 620 | connected = client.connect((char*) _clientName.c_str(), _currentNet.mqttUser, _currentNet.mqttPass); 621 | } else { 622 | debugPrintln(" - Using default"); 623 | debugPrintln(String("\t Client Name: " + String(_clientName.c_str()))); 624 | connected = client.connect((char*) _clientName.c_str()); 625 | } 626 | 627 | //if connected, subscribe to the topic(s) we want to be notified about 628 | if (connected) { 629 | debugPrintln(" -- Connected"); 630 | 631 | //if using https, verify the fingerprint of the server before setting full connection (return on fail) 632 | if(_useSecureClient){ 633 | if (wifiClientSecure.verify(_fingerprint, _currentNet.mqttHost)) { 634 | debugPrintln("Certificate Matches - SUCESS"); 635 | } else { 636 | debugPrintln("Certificate Doesn't Match - FAIL"); 637 | return; 638 | } 639 | } 640 | 641 | _connectionStatus = FULL_CONNECTION; 642 | resubscribe(); 643 | timeout = 0; 644 | } 645 | else{ 646 | debugPrintln(" -- Failed"); 647 | } 648 | timeout++; 649 | 650 | } 651 | 652 | //if we still cant connect to mqtt after 10 attempts increment the try count 653 | if(timeout >= 5 && !client.connected()){ 654 | timeout = 0; 655 | tryCount++; 656 | if(tryCount == 20){ 657 | changeNetwork(); 658 | tryCount = 0; 659 | return; 660 | } 661 | } 662 | } 663 | 664 | 665 | } 666 | 667 | //reset the reconnect metro 668 | reconnectMetro.reset(); 669 | } 670 | } 671 | 672 | int ESPHelper32::setConnectionStatus(){ 673 | 674 | //assume no connection 675 | int returnVal = NO_CONNECTION; 676 | 677 | //make sure were not in broadcast mode 678 | if(_connectionStatus != BROADCAST){ 679 | 680 | //if connected to wifi set the mode to wifi only and run the callback if needed 681 | if(WiFi.status() == WL_CONNECTED){ 682 | if(_connectionStatus < WIFI_ONLY && _wifiCallbackSet){ //if the wifi previously wasnt connected but now is, run the callback 683 | _wifiCallback(); 684 | } 685 | returnVal = WIFI_ONLY; 686 | 687 | //if mqtt is connected as well then set the status to full connection 688 | if(client.connected()){ 689 | returnVal = FULL_CONNECTION; 690 | } 691 | } 692 | } 693 | 694 | 695 | else{ 696 | returnVal = BROADCAST; 697 | } 698 | 699 | //set the connection status and return 700 | _connectionStatus = returnVal; 701 | return returnVal; 702 | } 703 | 704 | //changes the current network settings to the next listed network if network hopping is allowed 705 | void ESPHelper32::changeNetwork(){ 706 | 707 | //only attempt to change networks if hopping is allowed 708 | if(_hoppingAllowed){ 709 | //change the index/reset to 0 if we've hit the last network setting 710 | _currentIndex++; 711 | if(_currentIndex >= _netCount){_currentIndex = 0;} 712 | 713 | //set the current netlist to the new network 714 | _currentNet = *_netList[_currentIndex]; 715 | 716 | //verify various bits of network info 717 | 718 | //network password 719 | if(_currentNet.pass[0] == '\0'){_passSet = false;} 720 | else{_passSet = true;} 721 | 722 | //ssid 723 | if(_currentNet.ssid[0] == '\0'){_ssidSet = false;} 724 | else{_ssidSet = true;} 725 | 726 | //mqtt host 727 | if(_currentNet.mqttHost[0] == '\0'){_mqttSet = false;} 728 | else{_mqttSet = true;} 729 | 730 | //mqtt username 731 | if(_currentNet.mqttUser[0] == '\0'){_mqttUserSet = false;} 732 | else{_mqttUserSet = true;} 733 | 734 | //mqtt password 735 | if(_currentNet.mqttPass[0] == '\0'){_mqttPassSet = false;} 736 | else{_mqttPassSet = true;} 737 | 738 | //Will Topic 739 | if(_currentNet.willTopic[0] == '\0'){_willTopicSet = false;} 740 | else{_willTopicSet = true;} 741 | 742 | //Will Message 743 | if(_currentNet.willTopic[0] == '\0'){_willMessageSet = false;} 744 | else{_willMessageSet = true;} 745 | 746 | debugPrint("Trying next network: "); 747 | debugPrintln(_currentNet.ssid); 748 | 749 | //update the network connection 750 | updateNetwork(); 751 | } 752 | } 753 | 754 | void ESPHelper32::updateNetwork(){ 755 | debugPrintln("\tDisconnecting from WiFi"); 756 | WiFi.disconnect(); 757 | debugPrintln("\tAttempting to begin on new network"); 758 | 759 | //set the wifi mode 760 | WiFi.mode(WIFI_STA); 761 | 762 | //connect to the network 763 | if(_passSet && _ssidSet){WiFi.begin(_currentNet.ssid, _currentNet.pass);} 764 | else if(_ssidSet){WiFi.begin(_currentNet.ssid);} 765 | else{WiFi.begin("NO_SSID_SET");} 766 | 767 | debugPrintln("\tSetting new MQTT server"); 768 | //setup the mqtt broker info 769 | if(_mqttSet){client.setServer(_currentNet.mqttHost, _currentNet.mqttPort);} 770 | else{client.setServer("192.0.2.0", 1883);} 771 | 772 | debugPrintln("\tDone - Ready for next reconnect attempt"); 773 | } 774 | 775 | //generate unique MQTT name from MAC addr 776 | String ESPHelper32::macToStr(const uint8_t* mac){ 777 | 778 | String result; 779 | 780 | for (int i = 0; i < 6; ++i) { 781 | result += String(mac[i], 16); 782 | 783 | if (i < 5){ 784 | result += ':'; 785 | } 786 | } 787 | 788 | return result; 789 | } 790 | 791 | //change the current network info to a new netInfo - does not automatically disconnect from current network if already connected 792 | void ESPHelper32::setNetInfo(netInfo newNetwork){ 793 | _currentNet = newNetwork; 794 | _ssidSet = true; 795 | _passSet = true; 796 | _mqttSet = true; 797 | _mqttUserSet = true; 798 | } 799 | 800 | //change the current network info to a new *netInfo - does not automatically disconnect from current network if already connected 801 | void ESPHelper32::setNetInfo(netInfo *newNetwork){ 802 | _currentNet = *newNetwork; 803 | _ssidSet = true; 804 | _passSet = true; 805 | _mqttSet = true; 806 | _mqttUserSet = true; 807 | } 808 | 809 | //return the current netInfo state 810 | // netInfo* ESPHelper32::getNetInfo(){ 811 | // return &_currentNet; 812 | // } 813 | 814 | //return the current netInfo state 815 | netInfo ESPHelper32::getNetInfo(){ 816 | return _currentNet; 817 | } 818 | 819 | //return the current SSID 820 | const char* ESPHelper32::getSSID(){ 821 | if(_ssidSet && _connectionStatus != BROADCAST){return _currentNet.ssid;} 822 | else if(_connectionStatus == BROADCAST){return _broadcastSSID;} 823 | return "SSID NOT SET"; 824 | } 825 | //set a new SSID - does not automatically disconnect from current network if already connected 826 | void ESPHelper32::setSSID(const char* ssid){ 827 | _currentNet.ssid = ssid; 828 | _ssidSet = true; 829 | } 830 | 831 | //return the current network password 832 | const char* ESPHelper32::getPASS(){ 833 | if(_passSet && _connectionStatus != BROADCAST){return _currentNet.pass;} 834 | else if(_connectionStatus == BROADCAST){return _broadcastPASS;} 835 | return "PASS NOT SET"; 836 | } 837 | //set a new network password - does not automatically disconnect from current network if already connected 838 | void ESPHelper32::setPASS(const char* pass){ 839 | _currentNet.pass = pass; 840 | _passSet = true; 841 | } 842 | 843 | //return the current MQTT server IP 844 | const char* ESPHelper32::getMQTTIP(){ 845 | if(_mqttSet){return _currentNet.mqttHost;} 846 | return "MQTT IP NOT SET"; 847 | } 848 | //set a new MQTT server IP - does not automatically disconnect from current network/server if already connected 849 | void ESPHelper32::setMQTTIP(const char* mqttIP){ 850 | _currentNet.mqttHost= mqttIP; 851 | _mqttSet = true; 852 | } 853 | 854 | //set a new MQTT server IP - does not automatically disconnect from current network/server if already connected 855 | void ESPHelper32::setMQTTIP(const char* mqttIP, const char* mqttUser, const char* mqttPass){ 856 | _currentNet.mqttHost = mqttIP; 857 | _currentNet.mqttUser = mqttUser; 858 | _currentNet.mqttPass = mqttPass; 859 | _mqttSet = true; 860 | _mqttUserSet = true; 861 | } 862 | 863 | //set a new MQTT Will - does not automatically disconnect from current network/server if already connected 864 | void ESPHelper32::setWill(const char *willTopic, const char *willMessage){ 865 | _currentNet.willTopic = willTopic; 866 | _currentNet.willMessage = willMessage; 867 | _willTopicSet = true; 868 | _willMessageSet = true; 869 | } 870 | 871 | //set a new MQTT Will - does not automatically disconnect from current network/server if already connected 872 | void ESPHelper32::setWill(const char *willTopic, const char *willMessage, const int willQoS, const int willRetain){ 873 | _currentNet.willTopic = willTopic; 874 | _currentNet.willMessage = willMessage; 875 | _currentNet.willQoS = willQoS; 876 | _currentNet.willRetain = willRetain; 877 | _willTopicSet = true; 878 | _willMessageSet = true; 879 | } 880 | 881 | //return the QOS level for mqtt 882 | int ESPHelper32::getMQTTQOS(){ 883 | return _qos; 884 | 885 | } 886 | 887 | //set the QOS level for mqtt 888 | void ESPHelper32::setMQTTQOS(int qos){ 889 | _qos = qos; 890 | } 891 | 892 | //return the local IP address of the ESP as a string 893 | String ESPHelper32::getIP(){ 894 | if(_connectionStatus != BROADCAST){ 895 | return WiFi.localIP().toString(); 896 | } 897 | else{ 898 | return _broadcastIP.toString(); 899 | } 900 | 901 | } 902 | 903 | //return the local IP address of the ESP 904 | IPAddress ESPHelper32::getIPAddress(){ 905 | if(_connectionStatus != BROADCAST){ 906 | return WiFi.localIP(); 907 | } 908 | else{ 909 | return _broadcastIP; 910 | } 911 | } 912 | 913 | //get the current connection status of ESPHelper 914 | int ESPHelper32::getStatus(){ 915 | return _connectionStatus; 916 | } 917 | 918 | //enable or disable hopping - generally set automatically by initializer 919 | void ESPHelper32::setHopping(bool canHop){ 920 | _hoppingAllowed = canHop; 921 | } 922 | 923 | //DEBUG ONLY - print the subscribed topics list to the serial line 924 | void ESPHelper32::listSubscriptions(){ 925 | for(int i = 0; i < MAX_SUBSCRIPTIONS; i++){ 926 | if(_subscriptions[i].isUsed){ 927 | debugPrintln(_subscriptions[i].topic); 928 | } 929 | } 930 | } 931 | 932 | 933 | 934 | //enable the connection heartbeat on a given pin 935 | void ESPHelper32::enableHeartbeat(int16_t pin){ 936 | #ifdef DEBUG 937 | if(pin == 1){_heartbeatEnabled = false;} 938 | else{ 939 | _heartbeatEnabled = true; 940 | _ledPin = pin; 941 | pinMode(_ledPin, OUTPUT); 942 | digitalWrite(_ledPin, HIGH); 943 | } 944 | #else 945 | _heartbeatEnabled = true; 946 | _ledPin = pin; 947 | pinMode(_ledPin, OUTPUT); 948 | digitalWrite(_ledPin, HIGH); 949 | #endif 950 | } 951 | 952 | //disable the connection heartbeat 953 | void ESPHelper32::disableHeartbeat(){ 954 | _heartbeatEnabled = false; 955 | } 956 | 957 | //heartbeat to indicate network connection 958 | void ESPHelper32::heartbeat(){ 959 | static Metro heartbeatMetro = Metro(10); 960 | static int counter = 0; 961 | 962 | static bool ledState = true; 963 | 964 | if(heartbeatMetro.check() && _heartbeatEnabled){ 965 | if(counter == 1){ 966 | digitalWrite(_ledPin, ledState); 967 | heartbeatMetro.interval(10); 968 | ledState = !ledState; 969 | } 970 | else if(counter == 2){ 971 | digitalWrite(_ledPin, ledState); 972 | heartbeatMetro.interval(300); 973 | ledState = !ledState; 974 | } 975 | else if(counter == 3){ 976 | digitalWrite(_ledPin, ledState); 977 | heartbeatMetro.interval(10); 978 | ledState = !ledState; 979 | } 980 | else{ 981 | digitalWrite(_ledPin, ledState); 982 | heartbeatMetro.interval(1000); 983 | ledState = !ledState; 984 | counter = 0; 985 | } 986 | counter++; 987 | } 988 | } 989 | 990 | //enable use of OTA updates 991 | void ESPHelper32::OTA_enable(){ 992 | _useOTA = true; 993 | OTA_begin(); 994 | } 995 | 996 | //begin the OTA subsystem but with a check for connectivity and enabled use of OTA 997 | void ESPHelper32::OTA_begin(){ 998 | if(_connectionStatus >= BROADCAST && _useOTA){ 999 | ArduinoOTA.begin(); 1000 | _OTArunning = true; 1001 | } 1002 | } 1003 | 1004 | //disable use of OTA updates 1005 | void ESPHelper32::OTA_disable(){ 1006 | _useOTA = false; 1007 | _OTArunning = false; 1008 | } 1009 | 1010 | //set a password for OTA updates 1011 | void ESPHelper32::OTA_setPassword(const char* pass){ 1012 | ArduinoOTA.setPassword(pass); 1013 | } 1014 | 1015 | 1016 | //set the hostname of the ESP for OTA uploads 1017 | void ESPHelper32::OTA_setHostname(const char* hostname){ 1018 | strcpy(_hostname, hostname); 1019 | ArduinoOTA.setHostname(_hostname); 1020 | } 1021 | 1022 | //set the hostname of the ESP for OTA uploads and append the ESPHelper version number 1023 | void ESPHelper32::OTA_setHostnameWithVersion(const char* hostname){ 1024 | strcpy(_hostname, hostname); 1025 | strcat(_hostname, "----"); 1026 | strcat(_hostname, VERSION); 1027 | 1028 | ArduinoOTA.setHostname(_hostname); 1029 | } 1030 | 1031 | char* ESPHelper32::getHostname(){ 1032 | return _hostname; 1033 | } 1034 | --------------------------------------------------------------------------------