In my previous blog entry, Evolution of LED Lighting – hardware and tools, I only managed to describe the tools and hardware as well as a first project to test the ability to upload new programs to the device.
Some of the more interesting articles on the internet are about using the ESP8266 and setting it up as a web server. It is a totally fascinating solution but the reason I don’t want a web browser is that I am planning on having more than one device in my network and I don’t want to bring up a web page for each one when I am controlling them. I would rather have a separate server, perhaps a home dashboard, which will allow me to control the all devices.
My devices won’t be heart pacemakers and won’t be internet facing so I am going to use the UDP protocol. If for any reason a message gets lost, then I will simply send it again. If someone is already sniffing my network packets this is probably the least sensitive information that I have to steal.
The standard Arduino libraries actually have some classes to support WiFi bundled with the IDE. When I did my searching on the internet I found some Arduino examples that were using the WiFi, WiFiClient, and WiFiServer and that led me down the wrong path.
Indeed part of my problem was that the ESP8266 environment also has these classes but either I had forgotten to initialize some object or there are other differences.
One of the additional counter intuitive situations is that to do UDP messages you don’t include the WiFIUdp code, but rather just include the ESP8266WiFi.h file instead.
Once you look at the right kind of example it is actually trivial to connect to your device to the network using WiFi.
ESP8266 device
#include <ESP8266WiFi.h> #include <WiFiUDP.h> // pins for this device #define ESP8266_LED1 16 // center #define ESP8266_LED2 2 // edge // wifi connection variables const char* ssid = "your-ssid"; const char* password = "your-ssid-password"; boolean wifiConnected = false; ///////////////////// // UDP variables ///////////////////// WiFiUDP UDP; boolean udpConnected = false; char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; // buffer to hold incoming packet, char ReplyBuffer[UDP_TX_PACKET_MAX_SIZE]; // a string to send back char ack[] = "acknowledged"; // my default response ///////////////////// // my IoT device info ///////////////////// boolean debug = false; unsigned int localPort = 8192; void setup() { // Initialise Serial connection Serial.begin(74880); Serial.println("begin serial"); // turn off both leds on board pinMode(ESP8266_LED1, OUTPUT); pinMode(ESP8266_LED2, OUTPUT); digitalWrite(ESP8266_LED1, HIGH); digitalWrite(ESP8266_LED2, HIGH); delay(2000); // Initialise wifi connection wifiConnected = connectWifi(); // do UDP setup if wifi connection exists if (wifiConnected) { udpConnected = connectUDP(); if (udpConnected) { // show we are connected digitalWrite(ESP8266_LED1, LOW); } } } void loop() { // check if the WiFi and UDP connections were successful if (wifiConnected) { if (udpConnected) { // if there’s data available, read a packet int packetSize = UDP.parsePacket(); if (packetSize) { IPAddress remoteIP = UDP.remoteIP(); int remotePort = UDP.remotePort(); Serial.print("\nReceived packet of size "); Serial.println(packetSize); Serial.print("From "); Serial.print(remoteIP); Serial.print(", port "); Serial.println(remotePort); // read the packet into packetBufffer UDP.read(packetBuffer, sizeof(packetBuffer)); // make a zero terminated character array packetBuffer[packetSize] = 0; Serial.println("Contents:"); Serial.println(packetBuffer); // send a reply, to the IP address and port that sent us the packet we received UDP.beginPacket(UDP.remoteIP(), UDP.remotePort()); UDP.write(ReplyBuffer); UDP.endPacket(); } delay(10); } } } // connect to UDP – returns true if successful or false if not boolean connectUDP() { boolean state = false; if (UDP.begin(localPort) == 1) { Serial.println("\nUDP Connection successful\nlocal port: "); Serial.println(localPort); state = true; } else { Serial.println("\nUDP Connection failed"); } return state; } // connect to wifi – returns true if successful or false if not boolean connectWifi() { boolean connected = true; int idx = 0; WiFi.begin(ssid, password); Serial.println("\nConnecting to WiFi"); // Wait for connection, up to 5 seconds while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); if (idx > 10) { connected = false; break; } idx++; } return connected; }
This code is great. It actually allows me to get an IP address from my DHCP server and to start to listen for some UDP messages.
Most of this example code is nothing special. Of the 135 lines only about about a dozen are required to setup and do all of the networking.
function loop
Lines 64 determines that if a UDP packet exists line 78 reads the packet into our buffer.
Lines 86 – 88 simply send back a response to the machine that sent us the packet.
function connectUDP
The only interesting line is 100. This is setting up which port that we wish to monitor.
function connectWifi
Lines 119 and 123 perform the connection to our local WiFi network.
It is really a tribute to the people who put together all of supporting code that make these small devices possible.
Testing
The advantage to the web server solution is that at this point you are done. Simply point your browser at the device and start to click on buttons to control it. I choose to send UDP packets to my device so now I need a special program on my personal computer that can send commands to the device.
I am not a network programmer so I was happy to see that there are a number of different examples available on the internet. I will use the Java UDP example on laptop during testing but may ultimately end up using the C UDP example from my home automation server.
Everything at this point looks pretty good. I have a device that can connect to my network and I have a small client program that can send it messages. I now have my very own starting point for any generic device that should be controlled via WiFi.