Compare commits
9 Commits
68a4afdb12
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 629e5017ac | |||
| c367091adf | |||
| 65a1a3027b | |||
| f00091ec99 | |||
| 7bb74a43b9 | |||
| 4b571786ef | |||
| 392a2523c0 | |||
| e8c88665b9 | |||
| 3d8ef27978 |
@@ -2,21 +2,23 @@
|
||||
* Libraries and global scope code
|
||||
*/
|
||||
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <time.h>
|
||||
|
||||
BearSSL::WiFiClientSecure net;
|
||||
time_t now;
|
||||
unsigned long lastMillis = 0;
|
||||
|
||||
String devname; // Device identifier for MQTT
|
||||
|
||||
struct Settings {
|
||||
String name = "";
|
||||
String ip = "";
|
||||
} settings;
|
||||
|
||||
time_t now;
|
||||
|
||||
/*
|
||||
* Modules will plug in to this thing via function pointers
|
||||
*/
|
||||
// see also http://www.gammon.com.au/forum/?id=12607
|
||||
//void module_message(const String& shorttopic, const String& message) { //@@@@FIXME@@@@ instead of brightness, adjust mode?
|
||||
//void module_message(const String& shorttopic, const String& message) {
|
||||
//
|
||||
//}
|
||||
|
||||
|
||||
/*
|
||||
* Debugging might be nice sometimes
|
||||
*/
|
||||
|
||||
148
10_wifi_conf.ino
Normal file
148
10_wifi_conf.ino
Normal file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Wifi and OTA related stuff
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <ESP8266httpUpdate.h>
|
||||
|
||||
WiFiManager WifiManager;
|
||||
WiFiClientSecure net;
|
||||
|
||||
//BearSSL::WiFiClientSecure net;
|
||||
|
||||
unsigned long ota_lastcheck = 0;
|
||||
|
||||
//
|
||||
// If the WifiManager configuration portal is called, we can do stuff
|
||||
//
|
||||
//void WifiManagerCallback(WiFiManager *myWiFiManager) {
|
||||
// PRINTLN_SERIAL("Entered AP config mode");
|
||||
//}
|
||||
|
||||
void wifi_associate() {
|
||||
char apname[80];
|
||||
settings.name.toCharArray(apname, 80);
|
||||
|
||||
WifiManager.setConfigPortalTimeout(300); // If no configuration is done in 5 mins, exit/restart quietly
|
||||
if (WifiManager.autoConnect(apname)) { // @@@FIXME@@@ we should really set a PSK for the AP (but in my brief testing it crashed the ESP, so what's up with that)
|
||||
settings.ip = WiFi.localIP().toString();
|
||||
PRINTLN_SERIAL("Figured out my network \\O/");
|
||||
|
||||
//wificlient.setFingerprint(WTR_SHA1);
|
||||
net.setInsecure(); // Do not check fingerprint
|
||||
net.setTimeout(15000); // 15 Seconds
|
||||
|
||||
PRINT_SERIAL("Setting time using SNTP");
|
||||
configTime(-5 * 3600, 0, "pool.ntp.org", "time.nist.gov");
|
||||
now = time(nullptr);
|
||||
while (now < 1510592825) {
|
||||
delay(500);
|
||||
APPEND_SERIAL(".");
|
||||
now = time(nullptr);
|
||||
}
|
||||
APPENDLN_SERIAL(" done!");
|
||||
struct tm timeinfo;
|
||||
gmtime_r(&now, &timeinfo);
|
||||
PRINT_SERIAL("Current time: ");
|
||||
APPENDLN_SERIAL(asctime(&timeinfo));
|
||||
}
|
||||
}
|
||||
|
||||
void wifi_checkin() {
|
||||
// 'Native' in WiFiClient because we need to push the entire clientbuffer in the API
|
||||
// As a result copying the buffer in to a new String for HTTPClient library use is highly inefficient
|
||||
if (!net.connect(OTA_SERVER, OTA_PORT)) {
|
||||
Serial.println("HTTPS connection failed");
|
||||
} else {
|
||||
Serial.println("HTTPS connection up");
|
||||
|
||||
// Check for firmware upgrades
|
||||
String version = settings.name;
|
||||
version.concat("-v");
|
||||
version.concat(FW_VERSION);
|
||||
|
||||
String json = "{\"mac\":\"" + WiFi.macAddress() + "\",";
|
||||
json.concat("\"version\":\"" + version + "\",");
|
||||
json.concat("\"millis\":" + String(millis()) + "}");
|
||||
|
||||
// Send request to the server:
|
||||
net.println("POST " OTA_CHECKIN " HTTP/1.1");
|
||||
net.println("Host: " OTA_SERVER);
|
||||
net.println("Accept: */*");
|
||||
net.println("Content-Type: application/json");
|
||||
net.print("Content-Length: ");
|
||||
net.println(json.length());
|
||||
net.println("Connection: close");
|
||||
net.println();
|
||||
// Construct the REST/JSON POST data
|
||||
net.print(json);
|
||||
Serial.println("POST sent");
|
||||
|
||||
while (net.connected()) {
|
||||
String line = net.readStringUntil('\n');
|
||||
if (line == "\r") {
|
||||
Serial.println("Headers received");
|
||||
break;
|
||||
}
|
||||
}
|
||||
String line = net.readStringUntil('\n');
|
||||
Serial.println("reply was:");
|
||||
Serial.println("==========");
|
||||
Serial.println(line);
|
||||
Serial.println("==========");
|
||||
Serial.println("closing connection");
|
||||
net.stop(); // DISCONNECT FROM THE SERVER
|
||||
}
|
||||
}
|
||||
|
||||
void wifi_setup() {
|
||||
// WifiManager.setAPCallback(WifiManagerCallback); // Enable WifiManager callback to clear the cache
|
||||
wifi_associate();
|
||||
}
|
||||
|
||||
void wifi_loop() {
|
||||
|
||||
if(WiFi.status() != WL_CONNECTED) {
|
||||
PRINTLN_SERIAL("Wifi disconnected, trying to reconnect");
|
||||
wifi_associate();
|
||||
}
|
||||
|
||||
// OTA routine to be run once every X seconds
|
||||
unsigned long ota_check = millis()/1000;
|
||||
if((ota_lastcheck == 0) || ((ota_check - ota_lastcheck) > OTA_UPDATE_INTERVAL)) {
|
||||
PRINTLN_SERIAL("Checking for OTA update");
|
||||
|
||||
// Check for firmware upgrades
|
||||
String version = settings.name;
|
||||
version.concat("-v");
|
||||
version.concat(FW_VERSION);
|
||||
PRINTLN_SERIAL("net.status: " + String(net.status()));
|
||||
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(net, OTA_SERVER, OTA_PORT, OTA_URI, version);
|
||||
PRINTLN_SERIAL("after httpupdate check net.status: " + String(net.status()));
|
||||
|
||||
switch(ret) {
|
||||
case HTTP_UPDATE_FAILED: // HTTP 403, 404
|
||||
PRINT_SERIAL("Connection error, update failed ");
|
||||
APPEND_SERIAL("(ERR ");
|
||||
APPEND_SERIAL(String(ESPhttpUpdate.getLastError()));
|
||||
APPEND_SERIAL(") ");
|
||||
APPENDLN_SERIAL(ESPhttpUpdate.getLastErrorString().c_str());
|
||||
break;
|
||||
case HTTP_UPDATE_NO_UPDATES: // HTTP 304
|
||||
PRINTLN_SERIAL("No firmware upgrade available");
|
||||
break;
|
||||
case HTTP_UPDATE_OK: // HTTP 200
|
||||
PRINTLN_SERIAL("Firmware upgrade available, upgraded ok."); // may not called we reboot the ESP
|
||||
break;
|
||||
}
|
||||
ota_lastcheck = ota_check;
|
||||
|
||||
// Check in with IoT server
|
||||
wifi_checkin();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
// Future use
|
||||
@@ -1,20 +1,13 @@
|
||||
#ifdef ENABLE_MQTT
|
||||
|
||||
/*
|
||||
* Define a function newcmd in your module to be able to accept mqtt commands
|
||||
* Syntax and parameters are like this:
|
||||
*/
|
||||
void newcmd(String cmd);
|
||||
void module_message(const String& shorttopic, const String& message);
|
||||
// sample schema's to use: https://www.home-assistant.io/integrations/light.mqtt/
|
||||
|
||||
#include <PubSubClient.h>
|
||||
|
||||
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
|
||||
// Setup the MQTT client class by passing in the WiFi client
|
||||
PubSubClient mqtt(net);
|
||||
String deviceprefix;
|
||||
|
||||
const char* fingerprint = "EA:2A:2B:80:C1:00:57:35:66:26:FF:FC:FA:27:EA:5F:3D:91:5A:F9";
|
||||
|
||||
long logtimerMillis = 0;
|
||||
|
||||
void mqtt_subscribe(const String& topic) {
|
||||
@@ -72,40 +65,23 @@ void mqtt_callback(char* topic, byte* payload, unsigned int length) {
|
||||
}
|
||||
}
|
||||
|
||||
void WifiMQTTconnect() {
|
||||
void mqtt_connect() {
|
||||
/* bool success= false;
|
||||
success = net.connect(MQTT_SERVER, MQTT_SERVERPORT);
|
||||
if (success) {
|
||||
PRINTLN_SERIAL("Connection complete, valid cert, valid fingerprint.");
|
||||
} else {
|
||||
PRINTLN_SERIAL("Connection failed!");
|
||||
} */
|
||||
PRINTLN_SERIAL("prepare mqtt connect check net.status: " + String(net.status()));
|
||||
|
||||
if(WiFi.status() != WL_CONNECTED) {
|
||||
PRINTLN_SERIAL("Wifi not connected, connecting...");
|
||||
WiFi.mode(WIFI_STA); // Weird MQTT connection bug, https://github.com/knolleary/pubsubclient/issues/138#issuecomment-326113915
|
||||
WiFi.begin(WLAN_SSID, WLAN_PASS);
|
||||
while (WiFi.status() != WL_CONNECTED) {
|
||||
PRINTLN_SERIAL("Waiting for Wifi...");
|
||||
delay(500);
|
||||
}
|
||||
settings.ip = WiFi.localIP().toString();
|
||||
PRINTLN_SERIAL("Wifi connected");
|
||||
}
|
||||
|
||||
PRINT_SERIAL("Setting time using SNTP");
|
||||
configTime(-5 * 3600, 0, "pool.ntp.org", "time.nist.gov");
|
||||
now = time(nullptr);
|
||||
while (now < 1510592825) {
|
||||
delay(500);
|
||||
APPEND_SERIAL(".");
|
||||
now = time(nullptr);
|
||||
}
|
||||
APPENDLN_SERIAL(" done!");
|
||||
struct tm timeinfo;
|
||||
gmtime_r(&now, &timeinfo);
|
||||
PRINT_SERIAL("Current time: ");
|
||||
APPENDLN_SERIAL(asctime(&timeinfo));
|
||||
net.setInsecure(); // verification options set to none
|
||||
mqtt.setServer(MQTT_SERVER, MQTT_SERVERPORT);
|
||||
mqtt.setCallback(mqtt_callback);
|
||||
PRINTLN_SERIAL("before mqtt connect check net.status: " + String(net.status()));
|
||||
|
||||
if(!mqtt.connected()) {
|
||||
while (!mqtt.connected()) {
|
||||
PRINTLN_SERIAL("MQTT not connected, connecting...");
|
||||
PRINTLN_SERIAL("while mqtt connecting check net.status: " + String(net.status()));
|
||||
|
||||
// Attempt to connect
|
||||
// Note - the default maximum packet size is 128 bytes. If the
|
||||
@@ -114,11 +90,14 @@ void WifiMQTTconnect() {
|
||||
// PubSubClient.h
|
||||
if (mqtt.connect(settings.name.c_str(), MQTT_USERNAME, MQTT_PASSWORD)) {
|
||||
PRINTLN_SERIAL("MQTT connected");
|
||||
PRINTLN_SERIAL("mqtt just connected check net.status: " + String(net.status()));
|
||||
|
||||
} else {
|
||||
PRINTLN_SERIAL("MQTT connection failed, rc=" + String(mqtt.state()) + "...");
|
||||
PRINTLN_SERIAL("mqtt failed connected check net.status: " + String(net.status()));
|
||||
|
||||
delay(10000); // @@@FIXME@@@ delays are not cool
|
||||
}
|
||||
}
|
||||
|
||||
// (re)subscribe to the topics we need
|
||||
deviceprefix = MQTT_PREFIX;
|
||||
@@ -128,12 +107,13 @@ void WifiMQTTconnect() {
|
||||
mqtt_subscribe(deviceprefix + "#");
|
||||
mqtt_publish(deviceprefix + "log", "Connected " + settings.name + " running v" + FW_VERSION + " at " + settings.ip);
|
||||
mqtt_publish(deviceprefix + "log", "Free Heap: " + String(ESP.getFreeHeap()));
|
||||
PRINTLN_SERIAL("after mqtt connect check net.status: " + String(net.status()));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void mqtt_setup() {
|
||||
PRINTLN_SERIAL(devname + "initialising module MQTT");
|
||||
PRINTLN_SERIAL("Initialising MQTT");
|
||||
}
|
||||
|
||||
void mqtt_loop() {
|
||||
@@ -141,7 +121,7 @@ void mqtt_loop() {
|
||||
|
||||
// Check for MQTT instructions
|
||||
if(!mqtt.connected()) {
|
||||
WifiMQTTconnect();
|
||||
mqtt_connect();
|
||||
} else {
|
||||
mqtt.loop();
|
||||
|
||||
|
||||
@@ -6,14 +6,10 @@
|
||||
void newcmd(String cmd) {
|
||||
cmd.toLowerCase();
|
||||
if(cmd.equals("off")) {
|
||||
settings.mode = 0;
|
||||
PRINTLN_SERIAL("Lights off");
|
||||
state.text = "Sonoff switched off";
|
||||
}
|
||||
if(cmd.equals("on")) {
|
||||
settings.mode = 1;
|
||||
PRINTLN_SERIAL("Lights on");
|
||||
state.text = "Sonoff switched off";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,9 @@ void setup() {
|
||||
// If we run in to trouble, this can painlessly be removed and the resulting device name will just be longer
|
||||
settings.name.remove(devlen+1, 6);
|
||||
|
||||
PRINTLN_SERIAL("device name generated");
|
||||
PRINTLN_SERIAL("Figured out who I am \\O/");
|
||||
|
||||
wifi_setup();
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
mqtt_setup();
|
||||
@@ -36,10 +37,11 @@ void setup() {
|
||||
moon_setup();
|
||||
#endif
|
||||
// Start the cooperative scheduler loops
|
||||
PRINTLN_SERIAL(devname + "done setting up, ready for main loop");
|
||||
PRINTLN_SERIAL("Done setting up, ready for main loop \\O/");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
wifi_loop();
|
||||
#ifdef ENABLE_MQTT
|
||||
mqtt_loop();
|
||||
#endif
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// Implement versioning so that new firmware can be done OTA
|
||||
|
||||
// Todo:
|
||||
// Split the wifi and mqtt code in order to support http interface
|
||||
// maybe: loading settings on SPIFFS or similar so we can create more generic firmware? https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout
|
||||
// Stay on the lookout for watchdog crashes, see also https://www.sigmdel.ca/michel/program/esp8266/arduino/watchdogs_en.html#ESP8266_WDT_RECOV
|
||||
// Keeps crashing after a few days. Dunno why. https://www.pieterverhees.nl/sparklesagarbage/esp8266/130-difference-between-esp-reset-and-esp-restart
|
||||
// More on this subject https://github.com/esp8266/Arduino/issues/1017
|
||||
@@ -22,49 +22,24 @@
|
||||
// Implement OTA https://www.bakke.online/index.php/2017/06/02/self-updating-ota-firmware-for-esp8266/
|
||||
// Refactoring sources: https://www.arduinolibraries.info/architectures/esp8266
|
||||
// Refactor String usage to minimize heap pollution. https://cpp4arduino.com/2018/11/21/eight-tips-to-use-the-string-class-efficiently.html
|
||||
// Chec Michael Teeuw's MQTT/SSL workaround: https://github.com/MichMich/ESP8266-AWS/blob/master/src/main.ino
|
||||
|
||||
#define DEVICEPREFIX "Gadget" // Should be no longer than 8(?) chars or the MQTT clientId will become too long
|
||||
const int FW_VERSION = 12;
|
||||
// More WDT fixing:
|
||||
// https://www.sigmdel.ca/michel/program/esp8266/arduino/watchdogs_en.html
|
||||
// (background: https://internetofhomethings.com/homethings/?p=396
|
||||
// (background: http://iot-bits.com/esp8266/esp8266-reset-causes-rst-cause/
|
||||
|
||||
// Version history:
|
||||
// v14: Initial OTA support
|
||||
// v13: Refactored so config-settings are in config.h, move from Adafruit Neopixel to WS2812FX library
|
||||
// v12: Refactored inbound commands to hook in to the modules (module_message function), completed assimilation of (never-published) Moon_Connected sketch
|
||||
// v11: Simplified scheduler, back to cooperative looping
|
||||
// v10: First 'production' run. MQTT over TLS, but no OTA support.
|
||||
const int FW_VERSION = 14;
|
||||
|
||||
/*
|
||||
* Compile time settings
|
||||
*/
|
||||
|
||||
/************************* WiFi Access Point *********************************/
|
||||
#define WLAN_SSID "MY_SSID"
|
||||
#define WLAN_PASS "MY_WIFIPASSWD"
|
||||
//
|
||||
// Configuration settings
|
||||
//
|
||||
#include "config.h"
|
||||
|
||||
|
||||
/*********************** Select active modules *******************************/
|
||||
#define ENABLE_MQTT
|
||||
//#define ENABLE_SONOFF
|
||||
#define ENABLE_MOON
|
||||
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
/*************************** MQTT settings ***********************************/
|
||||
#define MQTT_SERVER "MY_MQTT_SERVER"
|
||||
#define MQTT_SERVERPORT 8883 // 8883 for MQTTS
|
||||
#define MQTT_USERNAME "MY_MQTT_USER"
|
||||
#define MQTT_PASSWORD "MY_MQTT_PASSWD"
|
||||
#define MQTT_PREFIX "iot/" // MQTT publish/subscribe will be prefixed by this (mind the trailing slash)
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SONOFF
|
||||
/*************************** MQTT settings ***********************************/
|
||||
#define SONOFF_BUTTON 0
|
||||
#define SONOFF_RELAY 12
|
||||
#define SONOFF_LED 13
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_MOON
|
||||
/*********************** NeoPixel Moon settings ******************************/
|
||||
#define MOON_PIXEL 4 // Which GPIO pin is the NeoPixel connected to
|
||||
#define MOON_PIXEL_LEDS 7 // Amount of leds in the string
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user