Skip to content

Commit c3796a4

Browse files
authored
Graph example (#7299)
* New Graph Example * Now using isFlashInterfacePin() no define default GPIO mask. * Added info about zooming. * Adressed requested changes (boolean > bool, using esp8266::polledTimeout::periodicMs, reducing complexity)
1 parent 8ee67ab commit c3796a4

File tree

3 files changed

+907
-0
lines changed

3 files changed

+907
-0
lines changed

Diff for: libraries/ESP8266WebServer/examples/Graph/Graph.ino

+332
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
/*
2+
Graph - A web-based Graph display of ESP8266 data
3+
4+
This file is part of the ESP8266WebServer library for Arduino environment.
5+
6+
This library is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU Lesser General Public
8+
License as published by the Free Software Foundation; either
9+
version 2.1 of the License, or (at your option) any later version.
10+
11+
This library is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
Lesser General Public License for more details.
15+
16+
You should have received a copy of the GNU Lesser General Public
17+
License along with this library; if not, write to the Free Software
18+
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19+
20+
See readme.md for more information.
21+
*/
22+
23+
////////////////////////////////
24+
25+
// Select the FileSystem by uncommenting one of the lines below
26+
27+
//#define USE_SPIFFS
28+
#define USE_LITTLEFS
29+
//#define USE_SDFS
30+
31+
////////////////////////////////
32+
33+
#include <ESP8266WiFi.h>
34+
#include <WiFiClient.h>
35+
#include <ESP8266WebServer.h>
36+
#include <ESP8266mDNS.h>
37+
#include <SPI.h>
38+
39+
#if defined USE_SPIFFS
40+
#include <FS.h>
41+
FS* fileSystem = &SPIFFS;
42+
SPIFFSConfig fileSystemConfig = SPIFFSConfig();
43+
#elif defined USE_LITTLEFS
44+
#include <LittleFS.h>
45+
FS* fileSystem = &LittleFS;
46+
LittleFSConfig fileSystemConfig = LittleFSConfig();
47+
#elif defined USE_SDFS
48+
#include <SDFS.h>
49+
FS* fileSystem = &SDFS;
50+
SDFSConfig fileSystemConfig = SDFSConfig();
51+
// fileSystemConfig.setCSPin(chipSelectPin);
52+
#else
53+
#error Please select a filesystem first by uncommenting one of the "#define USE_xxx" lines at the beginning of the sketch.
54+
#endif
55+
56+
57+
#define DBG_OUTPUT_PORT Serial
58+
59+
#ifndef STASSID
60+
#define STASSID "your-ssid"
61+
#define STAPSK "your-password"
62+
#endif
63+
64+
// Indicate which digital I/Os should be displayed on the chart.
65+
// From GPIO16 to GPIO0, a '1' means the corresponding GPIO will be shown
66+
// e.g. 0b11111000000111111
67+
unsigned int gpioMask;
68+
69+
const char* ssid = STASSID;
70+
const char* password = STAPSK;
71+
const char* host = "graph";
72+
73+
ESP8266WebServer server(80);
74+
75+
static const char TEXT_PLAIN[] PROGMEM = "text/plain";
76+
static const char FS_INIT_ERROR[] PROGMEM = "FS INIT ERROR";
77+
static const char FILE_NOT_FOUND[] PROGMEM = "FileNotFound";
78+
79+
////////////////////////////////
80+
// Utils to return HTTP codes
81+
82+
void replyOK() {
83+
server.send(200, FPSTR(TEXT_PLAIN), "");
84+
}
85+
86+
void replyOKWithMsg(String msg) {
87+
server.send(200, FPSTR(TEXT_PLAIN), msg);
88+
}
89+
90+
void replyNotFound(String msg) {
91+
server.send(404, FPSTR(TEXT_PLAIN), msg);
92+
}
93+
94+
void replyBadRequest(String msg) {
95+
DBG_OUTPUT_PORT.println(msg);
96+
server.send(400, FPSTR(TEXT_PLAIN), msg + "\r\n");
97+
}
98+
99+
void replyServerError(String msg) {
100+
DBG_OUTPUT_PORT.println(msg);
101+
server.send(500, FPSTR(TEXT_PLAIN), msg + "\r\n");
102+
}
103+
104+
////////////////////////////////
105+
// Request handlers
106+
107+
/*
108+
Read the given file from the filesystem and stream it back to the client
109+
*/
110+
bool handleFileRead(String path) {
111+
DBG_OUTPUT_PORT.println(String("handleFileRead: ") + path);
112+
113+
if (path.endsWith("/")) {
114+
path += "index.htm";
115+
}
116+
117+
String contentType = mime::getContentType(path);
118+
119+
if (!fileSystem->exists(path)) {
120+
// File not found, try gzip version
121+
path = path + ".gz";
122+
}
123+
if (fileSystem->exists(path)) {
124+
File file = fileSystem->open(path, "r");
125+
if (server.streamFile(file, contentType) != file.size()) {
126+
DBG_OUTPUT_PORT.println("Sent less data than expected!");
127+
}
128+
file.close();
129+
return true;
130+
}
131+
132+
return false;
133+
}
134+
135+
136+
/*
137+
The "Not Found" handler catches all URI not explicitely declared in code
138+
First try to find and return the requested file from the filesystem,
139+
and if it fails, return a 404 page with debug information
140+
*/
141+
void handleNotFound() {
142+
String uri = ESP8266WebServer::urlDecode(server.uri()); // required to read paths with blanks
143+
144+
if (handleFileRead(uri)) {
145+
return;
146+
}
147+
148+
// Dump debug data
149+
String message;
150+
message.reserve(100);
151+
message = F("Error: File not found\n\nURI: ");
152+
message += uri;
153+
message += F("\nMethod: ");
154+
message += (server.method() == HTTP_GET) ? "GET" : "POST";
155+
message += F("\nArguments: ");
156+
message += server.args();
157+
message += '\n';
158+
for (uint8_t i = 0; i < server.args(); i++) {
159+
message += F(" NAME:");
160+
message += server.argName(i);
161+
message += F("\n VALUE:");
162+
message += server.arg(i);
163+
message += '\n';
164+
}
165+
message += "path=";
166+
message += server.arg("path");
167+
message += '\n';
168+
DBG_OUTPUT_PORT.print(message);
169+
170+
return replyNotFound(message);
171+
}
172+
173+
void setup(void) {
174+
////////////////////////////////
175+
// SERIAL INIT
176+
DBG_OUTPUT_PORT.begin(115200);
177+
DBG_OUTPUT_PORT.setDebugOutput(true);
178+
DBG_OUTPUT_PORT.print('\n');
179+
180+
////////////////////////////////
181+
// FILESYSTEM INIT
182+
183+
fileSystemConfig.setAutoFormat(false);
184+
fileSystem->setConfig(fileSystemConfig);
185+
bool fsOK = fileSystem->begin();
186+
DBG_OUTPUT_PORT.println(fsOK ? F("Filesystem initialized.") : F("Filesystem init failed!"));
187+
188+
////////////////////////////////
189+
// PIN INIT
190+
pinMode(4, INPUT);
191+
pinMode(12, OUTPUT);
192+
pinMode(13, OUTPUT);
193+
pinMode(15, OUTPUT);
194+
195+
////////////////////////////////
196+
// WI-FI INIT
197+
DBG_OUTPUT_PORT.printf("Connecting to %s\n", ssid);
198+
WiFi.mode(WIFI_STA);
199+
WiFi.begin(ssid, password);
200+
// Wait for connection
201+
while (WiFi.status() != WL_CONNECTED) {
202+
delay(500);
203+
DBG_OUTPUT_PORT.print(".");
204+
}
205+
DBG_OUTPUT_PORT.println("");
206+
DBG_OUTPUT_PORT.print(F("Connected! IP address: "));
207+
DBG_OUTPUT_PORT.println(WiFi.localIP());
208+
209+
////////////////////////////////
210+
// MDNS INIT
211+
if (MDNS.begin(host)) {
212+
MDNS.addService("http", "tcp", 80);
213+
DBG_OUTPUT_PORT.print(F("Open http://"));
214+
DBG_OUTPUT_PORT.print(host);
215+
DBG_OUTPUT_PORT.println(F(".local to open the graph page"));
216+
}
217+
218+
////////////////////////////////
219+
// WEB SERVER INIT
220+
221+
//get heap status, analog input value and all GPIO statuses in one json call
222+
server.on("/espData", HTTP_GET, []() {
223+
String json;
224+
json.reserve(88);
225+
json = "{\"time\":";
226+
json += millis();
227+
json += ", \"heap\":";
228+
json += ESP.getFreeHeap();
229+
json += ", \"analog\":";
230+
json += analogRead(A0);
231+
json += ", \"gpioMask\":";
232+
json += gpioMask;
233+
json += ", \"gpioData\":";
234+
json += (uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16));
235+
json += "}";
236+
server.send(200, "text/json", json);
237+
});
238+
239+
// Default handler for all URIs not defined above
240+
// Use it to read files from filesystem
241+
server.onNotFound(handleNotFound);
242+
243+
244+
// Start server
245+
server.begin();
246+
DBG_OUTPUT_PORT.println("HTTP server started");
247+
248+
DBG_OUTPUT_PORT.println("Please pull GPIO4 low (e.g. press button) to switch output mode:");
249+
DBG_OUTPUT_PORT.println(" 0 (OFF): outputs are off and hidden from chart");
250+
DBG_OUTPUT_PORT.println(" 1 (AUTO): outputs are rotated automatically every second");
251+
DBG_OUTPUT_PORT.println(" 2 (MANUAL): outputs can be toggled from the web page");
252+
253+
}
254+
255+
// Return default GPIO mask, that is all I/Os except SD card ones
256+
unsigned int defaultMask() {
257+
unsigned int mask = 0b11111111111111111;
258+
for (auto pin = 0; pin <= 16; pin++) {
259+
if (isFlashInterfacePin(pin)) {
260+
mask &= ~(1 << pin);
261+
}
262+
}
263+
return mask;
264+
}
265+
266+
int rgbMode = 1; // 0=off - 1=auto - 2=manual
267+
int rgbValue = 0;
268+
esp8266::polledTimeout::periodicMs timeToChange(1000);
269+
bool modeChangeRequested = false;
270+
271+
void loop(void) {
272+
server.handleClient();
273+
MDNS.update();
274+
275+
if (digitalRead(4) == 0) {
276+
// button pressed
277+
modeChangeRequested = true;
278+
}
279+
280+
// see if one second has passed since last change, otherwise stop here
281+
if (!timeToChange) {
282+
return;
283+
}
284+
285+
// see if a mode change was requested
286+
if (modeChangeRequested) {
287+
// increment mode (reset after 2)
288+
rgbMode++;
289+
if (rgbMode > 2) {
290+
rgbMode = 0;
291+
}
292+
293+
modeChangeRequested = false;
294+
}
295+
296+
// act according to mode
297+
switch (rgbMode) {
298+
case 0: // off
299+
gpioMask = defaultMask();
300+
gpioMask &= ~(1 << 12); // Hide GPIO 12
301+
gpioMask &= ~(1 << 13); // Hide GPIO 13
302+
gpioMask &= ~(1 << 15); // Hide GPIO 15
303+
304+
// reset outputs
305+
digitalWrite(12, 0);
306+
digitalWrite(13, 0);
307+
digitalWrite(15, 0);
308+
break;
309+
310+
case 1: // auto
311+
gpioMask = defaultMask();
312+
313+
// increment value (reset after 7)
314+
rgbValue++;
315+
if (rgbValue > 7) {
316+
rgbValue = 0;
317+
}
318+
319+
// output new values
320+
digitalWrite(12, rgbValue & 0b001);
321+
digitalWrite(13, rgbValue & 0b010);
322+
digitalWrite(15, rgbValue & 0b100);
323+
break;
324+
325+
case 2: // manual
326+
gpioMask = defaultMask();
327+
328+
// keep outputs unchanged
329+
break;
330+
}
331+
}
332+

0 commit comments

Comments
 (0)