├── .gitignore ├── README.md ├── extra_scripts.py ├── include └── README ├── lib └── README ├── platformio.ini ├── src └── main.cpp └── test └── README /.gitignore: -------------------------------------------------------------------------------- 1 | .pio 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PlatformIO + ESP32 + Ethernet + OTA Demo 2 | 3 | ## Prerequisites 4 | 5 | Must have 6 | * an ESP32 dev board 7 | * a W5500 Ethernet shield or module 8 | * those must be connected via the SPI bus (see [default SPI connections](https://learn.sparkfun.com/tutorials/esp32-thing-hookup-guide/using-the-arduino-addon)) 9 | * for upoloading via this method, the system must have curl installed 10 | * for Windows, install via https://curl.haxx.se/windows/ and [put it into your system's PATH variable](https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/) so that you can call it from anywhere inside your `cmd.exe`. Reboot your system if necessary. 11 | 12 | ## Initial Sketch Upload 13 | 14 | Use the given `esp32dev` environment to first transport the initial OTA code to the ESP32 module. 15 | 16 | This is already the default environment in the `platformio.ini` (`default_envs = ...`). 17 | 18 | Make sure the W5500 module is recognized and prints its DHCP address. Expected output: 19 | 20 | ``` 21 | Initialize Ethernet with DHCP: 22 | DHCP assigned IP 192.168.1.237 23 | Link status: ON 24 | ``` 25 | 26 | If an error occurs, make sure you have 27 | 28 | * sufficiently good 3.3V power 29 | * all connections are sturdy and not loose 30 | * RESET of the W5500 module is connected to 3V3 31 | * Ethernet cable is connected 32 | 33 | Also note down theh IP address of the module. 34 | 35 | Note that in the sketch, we initialize the authorization parmaters 36 | 37 | ```cpp 38 | ArduinoOTA.begin(Ethernet.localIP(), "Arduino", "password", InternalStorage); 39 | ``` 40 | 41 | With a username `Arduino` and password `password`. 42 | 43 | ## OTA upload 44 | 45 | To upload via OTA, review the upload parameters inside the `platformio.ini`. Inside the `upload_flags` parameter, make sure to adapt the username, password, IP address and port (if changed). 46 | 47 | Then use the upload method of the `esp32dev_ota` environment. Either select the environment via the `platformio.ini` by changing the `default_env`, press the Upload button in the environment that VSCode shows or use the commandline to select the environment, e.g. via 48 | 49 | 50 | ``` 51 | pio run -e esp32dev_ota -t upload -v 52 | ``` 53 | 54 | This should invoke your system's CURL to push the sketch to the ESP 55 | 56 | ``` 57 | CURRENT: upload_protocol = custom 58 | curl --request POST --data-binary @"C:\Users\Maxi\Desktop\esp32_eth_ota\.pio\build\esp32dev_ota\firmware.bin" http://arduino:password@192.168.1.237:65280/sketch 59 | % Total % Received % Xferd Average Speed Time Time Time Current 60 | Dload Upload Total Spent Left Speed 61 | 62 | 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 63 | 0 302k 0 0 0 0 0 0 --:--:-- 0:00:01 --:--:-- 0 64 | 26 302k 0 0 26 81920 0 81920 0:00:03 0:00:01 0:00:02 57007 65 | 52 302k 0 0 52 160k 0 81920 0:00:03 0:00:02 0:00:01 62060 66 | 74 302k 0 0 74 224k 0 76458 0:00:04 0:00:03 0:00:01 67344 67 | 95 302k 0 0 95 288k 0 73728 0:00:04 0:00:04 --:--:-- 66707 68 | 100 302k 0 0 100 302k 0 61875 0:00:05 0:00:05 --:--:-- 62664 69 | 100 302k 0 0 100 302k 0 51562 0:00:06 0:00:06 --:--:-- 45067 70 | 100 302k 0 0 100 302k 0 51562 0:00:06 0:00:06 --:--:-- 37860 71 | =============================== [SUCCESS] Took 15.30 seconds =============== 72 | 73 | Environment Status Duration 74 | ------------- -------- ------------ 75 | esp32dev IGNORED 76 | esp32dev_ota SUCCESS 00:00:15.296 77 | ==== 1 succeeded in 00:00:15.296 ==================== 78 | ``` 79 | 80 | And thus we have a successful OTA upload. 81 | 82 | ## Upload SPIFFS? 83 | 84 | Arduino OTA has the possibility of uploading the SPIFFS via the `/spiffs` URL. This is not implemented in the PlatformIO integration, it only does sketch data. Feel free to expand. -------------------------------------------------------------------------------- /extra_scripts.py: -------------------------------------------------------------------------------- 1 | Import("env", "projenv") 2 | 3 | env.Replace( 4 | UPLOADCMD="curl --request POST --data-binary @\"$BUILD_DIR\\${PROGNAME}.bin\" $UPLOADERFLAGS" 5 | ) 6 | 7 | if False: 8 | env.AddPostAction( 9 | "$BUILD_DIR/${PROGNAME}.elf", 10 | env.VerboseAction(" ".join([ 11 | "$OBJCOPY", "-O", "binary", 12 | "\"$BUILD_DIR\\${PROGNAME}.elf", "\"$BUILD_DIR\\${PROGNAME}.bin" 13 | ]), "Building $BUILD_DIR/${PROGNAME}.bin") 14 | ) -------------------------------------------------------------------------------- /include/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project header files. 3 | 4 | A header file is a file containing C declarations and macro definitions 5 | to be shared between several project source files. You request the use of a 6 | header file in your project source file (C, C++, etc) located in `src` folder 7 | by including it, with the C preprocessing directive `#include'. 8 | 9 | ```src/main.c 10 | 11 | #include "header.h" 12 | 13 | int main (void) 14 | { 15 | ... 16 | } 17 | ``` 18 | 19 | Including a header file produces the same results as copying the header file 20 | into each source file that needs it. Such copying would be time-consuming 21 | and error-prone. With a header file, the related declarations appear 22 | in only one place. If they need to be changed, they can be changed in one 23 | place, and programs that include the header file will automatically use the 24 | new version when next recompiled. The header file eliminates the labor of 25 | finding and changing all the copies as well as the risk that a failure to 26 | find one copy will result in inconsistencies within a program. 27 | 28 | In C, the usual convention is to give header files names that end with `.h'. 29 | It is most portable to use only letters, digits, dashes, and underscores in 30 | header file names, and at most one dot. 31 | 32 | Read more about using header files in official GCC documentation: 33 | 34 | * Include Syntax 35 | * Include Operation 36 | * Once-Only Headers 37 | * Computed Includes 38 | 39 | https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html 40 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link into executable file. 4 | 5 | The source code of each library should be placed in a an own separate directory 6 | ("lib/your_library_name/[here are source files]"). 7 | 8 | For example, see a structure of the following two libraries `Foo` and `Bar`: 9 | 10 | |--lib 11 | | | 12 | | |--Bar 13 | | | |--docs 14 | | | |--examples 15 | | | |--src 16 | | | |- Bar.c 17 | | | |- Bar.h 18 | | | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html 19 | | | 20 | | |--Foo 21 | | | |- Foo.c 22 | | | |- Foo.h 23 | | | 24 | | |- README --> THIS FILE 25 | | 26 | |- platformio.ini 27 | |--src 28 | |- main.c 29 | 30 | and a contents of `src/main.c`: 31 | ``` 32 | #include 33 | #include 34 | 35 | int main (void) 36 | { 37 | ... 38 | } 39 | 40 | ``` 41 | 42 | PlatformIO Library Dependency Finder will find automatically dependent 43 | libraries scanning project source files. 44 | 45 | More information about PlatformIO Library Dependency Finder 46 | - https://docs.platformio.org/page/librarymanager/ldf.html 47 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | default_envs = esp32dev 13 | 14 | [env:esp32dev] 15 | platform = espressif32 16 | board = esp32dev 17 | framework = arduino 18 | lib_deps = 19 | ArduinoOTA=https://github.com/jandrassy/ArduinoOTA.git 20 | Ethernet=https://github.com/maxgerhardt/Ethernet.git 21 | 22 | [env:esp32dev_ota] 23 | platform = espressif32 24 | board = esp32dev 25 | framework = arduino 26 | lib_deps = 27 | ArduinoOTA=https://github.com/jandrassy/ArduinoOTA.git 28 | Ethernet=https://github.com/maxgerhardt/Ethernet.git 29 | 30 | extra_scripts = post:extra_scripts.py 31 | upload_protocol = custom 32 | upload_flags = 33 | http://arduino:password@192.168.1.237:65280/sketch 34 | 35 | ; DOES NOT WORK, ENTIRELY DIFFERENT PROTOCOL 36 | ;upload_protocol = espota 37 | ;upload_port = 192.168.1.237 38 | ;upload_flags = 39 | ; --port=65280 40 | ; --auth=password 41 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This example polls for sketch updates over Ethernet, sketches 4 | can be updated by selecting a network port from within 5 | the Arduino IDE: Tools -> Port -> Network Ports ... 6 | 7 | Circuit: 8 | * W5100, W5200 or W5500 Ethernet shield attached 9 | 10 | created 13 July 2010 11 | by dlf (Metodo2 srl) 12 | modified 31 May 2012 13 | by Tom Igoe 14 | modified 16 January 2017 15 | by Sandeep Mistry 16 | Ethernet version August 2018 17 | by Juraj Andrassy 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | //#define Serial SerialUSB 26 | 27 | // Enter a MAC address for your controller below. 28 | // Newer Ethernet shields have a MAC address printed on a sticker on the shield 29 | byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 30 | 31 | unsigned long last_time = 0; 32 | 33 | #ifndef LED_BUILTIN 34 | //red LED on my esp32 dev board is on IO2 35 | #define LED_BUILTIN 2 36 | #endif 37 | bool led_state = false; 38 | 39 | void setup() { 40 | //Initialize serial: 41 | Serial.begin(115200); 42 | while (!Serial); 43 | 44 | pinMode(LED_BUILTIN, OUTPUT); 45 | 46 | //voltage stablilizer lol 47 | delay(1000); 48 | 49 | SPI.begin(); 50 | Ethernet.init(5); 51 | // start the Ethernet connection: 52 | Serial.println("Initialize Ethernet with DHCP:"); 53 | if (Ethernet.begin(mac) == 0) { 54 | Serial.println("Failed to configure Ethernet using DHCP"); 55 | if (Ethernet.hardwareStatus() == EthernetNoHardware) { 56 | Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :("); 57 | } else if (Ethernet.linkStatus() == LinkOFF) { 58 | Serial.println("Ethernet cable is not connected."); 59 | } 60 | } else { 61 | Serial.print(" DHCP assigned IP "); 62 | Serial.println(Ethernet.localIP()); 63 | } 64 | 65 | // start the OTEthernet library with internal (flash) based storage 66 | ArduinoOTA.begin(Ethernet.localIP(), "Arduino", "password", InternalStorage); 67 | } 68 | 69 | void loop() { 70 | // check for updates 71 | ArduinoOTA.poll(); 72 | //constantly maintain DHCP ip in the long run 73 | Ethernet.maintain(); 74 | //every second, print link status and toggle LED 75 | if(millis() - last_time >= 1000) { 76 | last_time = millis(); 77 | auto link = Ethernet.linkStatus(); 78 | Serial.print("[V2] Link status: "); 79 | switch (link) { 80 | case Unknown: 81 | Serial.println("Unknown"); 82 | break; 83 | case LinkON: 84 | Serial.println("ON"); 85 | break; 86 | case LinkOFF: 87 | Serial.println("OFF"); 88 | break; 89 | } 90 | //toggle 91 | led_state = !led_state; 92 | digitalWrite(LED_BUILTIN, led_state ? HIGH : LOW); 93 | } 94 | } 95 | 96 | -------------------------------------------------------------------------------- /test/README: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for PIO Unit Testing and project tests. 3 | 4 | Unit Testing is a software testing method by which individual units of 5 | source code, sets of one or more MCU program modules together with associated 6 | control data, usage procedures, and operating procedures, are tested to 7 | determine whether they are fit for use. Unit testing finds problems early 8 | in the development cycle. 9 | 10 | More information about PIO Unit Testing: 11 | - https://docs.platformio.org/page/plus/unit-testing.html 12 | --------------------------------------------------------------------------------