Schematic
Connect 3 wires to A0, GPIO4, and GPIO5 of NodeMCU as shown below.
Testing The Arduino Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | /* Source: https://github.com/IU5HKU/ESP8266-ServerSentEvents/blob/master/ESP8266_ServerSentEvents/ESP8266_ServerSentEvents.ino Server-Sent Events / EventSource DEMO forked from Claudius Coenen repository based on Web Server example by David A. Mellis and Tom Igoe Adapted to the new ESP8266 SDK 2.4.2 by Marco Campinoti Circuit: * Analog input attached to pins A0 (optional) * Digital input attached to pins 5 or 6 (optional) This is free software. Use, modify and tinker with it however you like! LICENSED UNDER CC-BY-4.0 http://creativecommons.org/licenses/by/4.0/ */ #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> //declare the webserver ESP8266WebServer server(80); void setup() { // Open serial communications and wait for port to open: Serial.begin(115200); while (!Serial) { ; // wait for serial port to connect } if (WiFi.status() != WL_CONNECTED) { Serial.print(F("Connecting")); WiFi.persistent(false); // WiFi config isn't saved in flash WiFi.mode(WIFI_STA); // use WIFI_AP_STA if you want an AP WiFi.hostname("ESP8266"); // must be called before wifi.begin() WiFi.begin("SSID", "SSID_Password"); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print(F(".")); } } Serial.println(); Serial.print(F("IP address: ")); Serial.println(WiFi.localIP()); //start the webserver server.begin(); //Server Sent Events will be handled from this URI server.on("/ssedata", handleSSEdata); } void loop() { // listen for incoming clients server.handleClient(); } void handleSSEdata(){ WiFiClient client = server.client(); if (client) { Serial.println("new client"); serverSentEventHeader(client); while (client.connected()) { serverSentEvent(client); delay(16); // round about 60 messages per second } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); Serial.println("client disconnected"); } } void serverSentEventHeader(WiFiClient client) { client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/event-stream;charset=UTF-8"); client.println("Connection: close"); // the connection will be closed after completion of the response client.println("Access-Control-Allow-Origin: *"); // allow any connection. We don't want Arduino to host all of the website ;-) client.println("Cache-Control: no-cache"); // refresh the page automatically every 5 sec client.println(); client.flush(); } void serverSentEvent(WiFiClient client) { client.println("event: esp8266"); // this name could be anything, really. client.print("data: {"); client.print("\"A0\": "); client.print(1.0 * analogRead(0) / 1024.0); client.print(", \"in5\": "); client.print(digitalRead(5)); client.print(", \"in4\": "); client.print(digitalRead(4)); //client.print(", \"text\": ESP8266"); // added just to show how you can add your own parameters client.print(", \"text\": \"ESP8266\""); // Be sure to add " around ESP8266; otherwise, it won't be correctly parsed in the web UI!!! client.println("}"); client.println(); client.flush(); } |
Assuming the IP address assigned to the NodeMCU is 192.168.31.148, launch a web browser that's running on a computer which is on the same network segment as the NodeMCU and put http://192.168.31.148/ssedata in the URL field of the web browser..
Below is the output on the web browser.
Testing The PHP Code (source.php)
With the above Arduino code still running on the NodeMCU module, put the code below on a computer that already has PHP and Apache Web Server installed. The code is to be placed under "/var/www/html".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <?php /* Server-Sent Events / EventSource DEMO Claudius Coenen This is free software. Use, modify and tinker with it however you like! LICENSED UNDER CC-BY-4.0 http://creativecommons.org/licenses/by/4.0/ */ error_log('script starting'); header('Content-Type: text/event-stream'); header('Access-Control-Allow-Origin: *'); header('Cache-Control: no-cache'); echo "retry: 3000\n"; $seed = rand(); $count = 0; function sendMsg($msg) { global $count, $seed; error_log('message sent: ' . $msg); echo "event: testeventcc\n"; echo "data: $msg $count $seed\n\n"; ob_flush(); flush(); } while (!connection_aborted()) { $count++; sendMsg('server time: ' . date("H:i:s")); usleep(16000); // 16ms per message -> 60msg/s } error_log("connection closed"); |
Assuming the IP of the computer that hosts the PHP code is 192.168.31.77, launch a web browser and put http://192.168.31.77/source.php in the URL field.
Below is the output on the web browser.
Testing The index.html Code - with SSE data source from source.php
Here is source of data is from source.php (highlighted in yellow below).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <html> <head> <style> body { font-size: 3em; font-family: sans-serif; } </style> </head> <body> <p id="output">Nothing received so far...</p> <script> // change this line to match the IP address of your Arduino // var source = new EventSource('http://192.168.31.148/ssedata'); // or, in case you're using the PHP Script, use this line instead. var source = new EventSource('source.php'); var outputElement = document.getElementById('output'); var eventCounter = 0; source.addEventListener('testeventcc', function(e) { //source.addEventListener('arduino', function(e) { eventCounter++; outputElement.innerText = e.data + " (" + eventCounter + " Events)"; }, false); //source.addEventListener('arduino', function(e) { source.addEventListener('esp8266', function(e) { eventCounter++; outputElement.innerText = e.data + " (" + eventCounter + " Events)"; var inputs = JSON.parse(e.data); document.body.style.backgroundColor = inputs.in5 > 0 ? '#ff0000' : '#ffffff'; document.body.style.color = inputs.in6 > 0 ? 'fuchsia' : 'black'; outputElement.style.opacity = inputs.A0; }, false); source.addEventListener('open', function(e) { console.log("connected"); }, false); source.addEventListener('error', function(e) { console.error(e); if (e.readyState == EventSource.CLOSED) { } }, false); </script> </body> </html> |
Below is the output from the web browser.
I use Wireshark to capture and analyze the traffic. In the pic below, 192.168.31.77 is the IP address of the Raspberry Pi that has index.html and source.php running on it, 192.168.31.178 is the IP address of the computer browsing the output of source.php.
Testing The index.html Code - with SSE data source from ESP8266
Replace the previous 'index.html" in "/var/www/html" with the one below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <html> <head> <style> body { font-size: 3em; font-family: sans-serif; } </style> </head> <body> <p id="output">Nothing received so far...</p> <script> // change this line to match the IP address of your Arduino var source = new EventSource('http://192.168.31.148/ssedata'); // or, in case you're using the PHP Script, use this line instead. // var source = new EventSource('source.php'); var outputElement = document.getElementById('output'); var eventCounter = 0; source.addEventListener('testeventcc', function(e) { eventCounter++; outputElement.innerText = e.data + " (" + eventCounter + " Events_1)"; }, false); source.addEventListener('esp8266', function(e) { eventCounter++; outputElement.innerText = e.data + " (" + eventCounter + " Events_2)"; //console.log(e); var inputs = JSON.parse(e.data); document.body.style.backgroundColor = inputs.in5 > 0 ? '#ff0000' : '#ffffff'; document.body.style.color = inputs.in4 > 0 ? 'fuchsia' : 'black'; outputElement.style.opacity = inputs.A0; }, false); source.addEventListener('open', function(e) { console.log("connected"); }, false); source.addEventListener('error', function(e) { console.error(e); if (e.readyState == EventSource.CLOSED) { } }, false); </script> </body> </html> |
***IMPORTANT***
Be sure to close all other browser / browser tab that is accessing the web UI running on ESP8266 (in this case "http://192.168.31.148/ssedata"); otherwise, you will see "Nothing received so far" when accessing the URL that gets its SSE data from ESP8266.
For example, in the pic below, when the browser on the left is accessing "http://192.168.31.148/ssedata", the one on the left is receiving nothing.
In the pic below, when the browser on the left stops accessing "http://192.168.31.148/ssedata", the one on the left is receiving and showing the SSE data.
I think this issue could be solved by using async web server...
Overall Architecture
There are 2 data sources, one is generated by the Arduino code running on NodeMCU. The other is from the PHP code running on the Raspberry Pi.
The index.html file is running on the Raspberry Pi.
Reference:
How to use Server-Sent Events / EventSource from PHP and ESP8266
https://github.com/IU5HKU/ESP8266-ServerSentEvents
How to use Server-Sent Events / EventSource from PHP and Arduino
https://github.com/ccoenen/server-sent-events-demo/
Generating Server-Sent Events on Arduino
https://www.claudiuscoenen.de/2015/09/generating-server-sent-events-on-arduino/
HTML5 Server-Sent Events
https://www.w3schools.com/html/html5_serversentevents.asp
No comments:
Post a Comment