Skip to content

Instantly share code, notes, and snippets.

@gjlawran
Forked from DeanCording/Template_ESP8266.ino
Last active January 9, 2023 23:38
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gjlawran/0488d55901a89a45d2460bacad02fb2e to your computer and use it in GitHub Desktop.
Save gjlawran/0488d55901a89a45d2460bacad02fb2e to your computer and use it in GitHub Desktop.
ESP8266 Arduino project template with optional OTA firmware update
/**
* ESP8266 project template with optional:
* - WiFi config portal - auto or manual trigger
* - OTA update - Arduino or web server
* - Deep sleep
* - Process timeout watchdog
*
* Copyright (c) 2016 Dean Cording <dean@cording.id.au>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* ESP8266 Pin Connections
*
* GPIO0/SPI-CS2/_FLASH_ - Pull low for Flash download by UART
* GPIO1/TXD0/SPI-CS1 - _LED_
* GPIO2/TXD1/I2C-SDA/I2SO-WS -
* GPIO3/RXD0/I2SO-DATA -
* GPIO4 -
* GPIO5/IR-Rx -
* GPIO6/SPI-CLK - Flash CLK
* GPIO7/SPI-MISO - Flash DI
* GPIO8/SPI-MOSI/RXD1 - Flash DO
* GPIO9/SPI-HD - Flash _HD_
* GPIO10/SPI-WP - Flash _WP_
* GPIO11/SPI-CS0 - Flash _CS_
* GPIO12/MTDI/HSPI-MISO/I2SI-DATA/IR-Tx -
* GPIO13/MTCK/CTS0/RXD2/HSPI-MOSI/I2S-BCK -
* GPIO14/MTMS/HSPI-CLK/I2C-SCL/I2SI_WS -
* GPIO15/MTDO/RTS0/TXD2/HSPI-CS/SD-BOOT/I2SO-BCK - Pull low for Flash boot
* GPIO16/WAKE -
* ADC -
* EN -
* RST -
* GND -
* VCC -
*/
#include <Arduino.h>
String reqString; // define a request string to build and use to make OTA request
// Optional functionality. Comment out defines to disable feature
#define WIFI_PORTAL // Enable WiFi config portal
//#define ARDUINO_OTA // Enable Arduino IDE OTA updates
#define HTTP_OTA // Enable OTA updates from http server
#define LED_STATUS_FLASH // Enable flashing LED status
//#define DEEP_SLEEP_SECONDS 5 // Define for sleep period between process repeats. No sleep if not defined
#define STATUS_LED 2 // Built-in blue LED on pin 2
#include <ESP8266WiFi.h>
#ifdef WIFI_PORTAL
#include <DNSServer.h> // Local DNS Server used for redirecting all requests to the configuration portal
#include <ESP8266WebServer.h> // Local WebServer used to serve the configuration portal
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager WiFi Configuration Magic
WiFiManager wifiManager;
#define WIFI_PORTAL_TRIGGER_PIN 4 // A low input on this pin will trigger the Wifi Manager Console at boot. Comment out to disable.
#else
#define WIFI_SSID "SSID"
#define WIFI_PASSWORD "password"
#endif
#ifdef ARDUINO_OTA
/* Over The Air updates directly from Arduino IDE */
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#define ARDUINO_OTA_PORT 8266
#define ARDUINO_OTA_HOSTNAME "esp8266"
#define ARDUINO_OTA_PASSWD "123"
#endif
#ifdef HTTP_OTA
/* Over The Air automatic firmware update from a web server. ESP8266 will contact the
* server on every boot and check for a firmware update. If available, the update will
* be downloaded and installed. Server can determine the appropriate firmware for this
* device from any combination of HTTP_OTA_VERSION, MAC address, and firmware MD5 checksums.
*/
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#define HTTP_OTA_ADDRESS F("sub.domain.com") // Address of OTA update server
#define HTTP_OTA_PATH F("/esp8266-ota/update") // Path to update firmware
#define HTTP_OTA_PORT 1880 // Port of update server
// Name of firmware
// #define HTTP_OTA_VERSION String(__FILE__).substring(String(__FILE__).lastIndexOf('/')+1) + ".generic" //unix
#define HTTP_OTA_VERSION String(__FILE__).substring(String(__FILE__).lastIndexOf('\\')+1) + ".generic" //windows
#endif
const char* SSID = (String("ESP") + String(ESP.getChipId())).c_str();
/* Watchdog to guard against the ESP8266 wasting battery power looking for
* non-responsive wifi networks and servers. Expiry of the watchdog will trigger
* either a deep sleep cycle or a delayed reboot. The ESP8266 OS has another built-in
* watchdog to protect against infinite loops and hangups in user code.
*/
#include <Ticker.h>
Ticker watchdog;
#define WATCHDOG_SETUP_SECONDS 30 // Setup should complete well within this time limit
#define WATCHDOG_LOOP_SECONDS 20 // Loop should complete well within this time limit
void timeout_cb() {
// This sleep happened because of timeout. Do a restart after a sleep
Serial.println(F("Watchdog timeout..."));
#ifdef DEEP_SLEEP_SECONDS
// Enter DeepSleep so that we don't exhaust our batteries by countinuously trying to
// connect to a network that isn't there.
ESP.deepSleep(DEEP_SLEEP_SECONDS * 1000, WAKE_RF_DEFAULT);
// Do nothing while we wait for sleep to overcome us
while(true){};
#else
delay(1000);
ESP.restart();
#endif
}
#ifdef LED_STATUS_FLASH
Ticker flasher;
void flash() {
digitalWrite(STATUS_LED, !digitalRead(STATUS_LED));
}
#endif
#ifdef WIFI_PORTAL
// Callback for entering config mode
void configModeCallback (WiFiManager *myWiFiManager) {
// Config mode has its own timeout
watchdog.detach();
#ifdef LED_STATUS_FLASH
flasher.attach(0.2, flash);
#endif
}
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Put any project specific initialisation here
//////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
Serial.println(F("Booting"));
#ifdef LED_STATUS_FLASH
pinMode(STATUS_LED, OUTPUT);
flasher.attach(0.6, flash);
#endif
// Watchdog timer - resets if setup takes longer than allocated time
watchdog.once(WATCHDOG_SETUP_SECONDS, &timeout_cb);
// Set up WiFi connection
// Previous connection details stored in eeprom
#ifdef WIFI_PORTAL
#ifdef WIFI_PORTAL_TRIGGER_PIN
pinMode(WIFI_PORTAL_TRIGGER_PIN, INPUT_PULLUP);
delay(100);
if ( digitalRead(WIFI_PORTAL_TRIGGER_PIN) == LOW ) {
watchdog.detach();
if (!wifiManager.startConfigPortal(SSID, NULL)) {
Serial.println(F("Config Portal Failed!"));
timeout_cb();
}
} else {
#endif
wifiManager.setConfigPortalTimeout(180);
wifiManager.setAPCallback(configModeCallback);
if (!wifiManager.autoConnect()) {
Serial.println(F("Connection Failed!"));
timeout_cb();
}
#ifdef WIFI_PORTAL_TRIGGER_PIN
}
#endif
#else
// Save boot up time by not configuring them if they haven't changed
if (WiFi.SSID() != WIFI_SSID) {
Serial.println(F("Initialising Wifi..."));
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
WiFi.persistent(true);
WiFi.setAutoConnect(true);
WiFi.setAutoReconnect(true);
}
#endif
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println(F("Connection Failed!"));
timeout_cb();
}
Serial.print(F("IP address: "));
Serial.println(WiFi.localIP());
#ifdef LED_STATUS_FLASH
flasher.detach();
digitalWrite(STATUS_LED, HIGH);
#endif
Serial.println(); // show the MAC address of the device
Serial.print("MAC: ");
Serial.println(WiFi.macAddress());
Serial.println(); // show the version updating
Serial.print("VER: ");
Serial.println( HTTP_OTA_VERSION);
#ifdef HTTP_OTA
// Check server for firmware updates
Serial.print("Checking for firmware updates from server ");
reqString = String("http://");
reqString = reqString + String(HTTP_OTA_ADDRESS);
reqString = reqString + String(':') + HTTP_OTA_PORT ;
reqString = reqString + HTTP_OTA_PATH;
reqString = reqString + HTTP_OTA_VERSION;
Serial.println(reqString);
//review code below
/*
Serial.print("Checking for firmware updates from server ");
Serial.print(HTTP_OTA_ADDRESS);
Serial.print(":");
Serial.print(HTTP_OTA_PORT);
Serial.println(HTTP_OTA_PATH);
switch(ESPhttpUpdate.update(HTTP_OTA_ADDRESS, HTTP_OTA_PORT, HTTP_OTA_PATH, HTTP_OTA_VERSION)) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP update failed: Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
*/
switch (ESPhttpUpdate.update(reqString)) {
case HTTP_UPDATE_FAILED:
Serial.printf("HTTP update failed: Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println(F("No updates"));
break;
case HTTP_UPDATE_OK:
Serial.println(F("Update OK"));
break;
}
#endif
#ifdef ARDUINO_OTA
// Arduino OTA Initalisation
ArduinoOTA.setPort(ARDUINO_OTA_PORT);
ArduinoOTA.setHostname(SSID);
ArduinoOTA.setPassword(ARDUINO_OTA_PASSWD);
ArduinoOTA.onStart([]() {
watchdog.detach();
Serial.println("Start");
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
else if (error == OTA_END_ERROR) Serial.println("End Failed");
});
ArduinoOTA.begin();
#endif
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// Put any project specific setup code here
//////////////////////////////////////////////////////////////////////////////////////////////////////////
Serial.println(F("Ready"));
watchdog.detach();
}
void loop() {
// Watchdog timer - resets if setup takes longer than allocated time
watchdog.once(WATCHDOG_LOOP_SECONDS, &timeout_cb);
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// put your main code here, to run repeatedly:
//////////////////////////////////////////////////////////////////////////////////////////////////////////
delay(10000);
watchdog.detach();
#ifdef ARDUINO_OTA
// Handle any OTA upgrade
ArduinoOTA.handle();
#endif
#ifdef DEEP_SLEEP_SECONDS
// Enter DeepSleep
Serial.println(F("Sleeping..."));
ESP.deepSleep(DEEP_SLEEP_SECONDS * 1000000, WAKE_RF_DEFAULT);
// Do nothing while we wait for sleep to overcome us
while(true){};
#endif
}
@gjlawran
Copy link
Author

While the node-red server software can take an MD5 hash and the MAC address of the board this script is not writtent to send these.

This script if unmodifed sends a call to http://hostname/esp8266-ota/update/ plus HTTP_OTA_VERSION - which is a string of the directory and filename of the location of the firmware itself.

Looking at the node-red server software with debug turned on requests made by the ESP8266 to update URL are not being logged by the debug node. So the request is not actually making it to the OTA update - likely because of the slashes included in the filename. I think I need to change what this script is sending to the update node - so that it is consistent with the filename logged in the firmware directory

@gjlawran
Copy link
Author

gjlawran commented Dec 9, 2017

added a couple of blocks to make finding the initialization, setup and loop blocks easier to find
change the request method to build string
made it possible to use arduino names from windows

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment