diff --git a/README.md b/README.md index fa0bee8..5db69f5 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,7 @@ Some sketches will add other constants to that file as well. These files are ign * [SimplerWebServer](https://github.com/tigoe/Wifi_examples/tree/main/Servers/SimplerWebServer) - a stripped-down example of how to respond to HTTP requests * [NetworkClientLogger](https://github.com/tigoe/Wifi_examples/tree/main/Servers/NetworkClientLogger) - listens on a number of popular ports (HTTP, SMTP, SSH, etc) and logs to an SD card all client connnection attempts * [UptimeServer](https://github.com/tigoe/Wifi_examples/tree/main/Servers/UptimeServer) - a web server that reports the device's uptime when it receives an HTTP request. +* [SensorWebServerWithCSSandJS](https://github.com/tigoe/Wifi_examples/tree/main/Servers/Servers/SensorWebServerWithCSSandJS) - a web server that reports reads sensors and delivers them as JSON when it receives an HTTP request. This example also shows how to serve an index.html, styles.css, and script.js file separately. ## TCP and UDP Examples * [simpleTCPClient](https://github.com/tigoe/Wifi_examples/tree/main/simpleTCPClient) - makes a TCP connection to a remote * host and sends a message every ten seconds diff --git a/Servers/SensorWebServerWithCSSandJS/SensorWebServerWithCSSandJS.ino b/Servers/SensorWebServerWithCSSandJS/SensorWebServerWithCSSandJS.ino new file mode 100644 index 0000000..a4ac284 --- /dev/null +++ b/Servers/SensorWebServerWithCSSandJS/SensorWebServerWithCSSandJS.ino @@ -0,0 +1,147 @@ +/* + Web Server to serve temperature and humidity data + + This example uses the MCP9808 precision temperature sensor + and the DHT22 temperature and humidity sensor + to serve temperature and humidity data. It also shows how + to parse client requests for the GET line, and to + separate server responses for multiple documents. + Each document to be served (index.html, styles.css, script.js) + is defined in a different #define, and stored in a separate + file to make editing convenient. + + MCP9808 sensor is attached to the I2C pins + DHT22 sensor is attached to digital pin 2 + + created 28 Jul 2024 + by Tom Igoe +*/ + +// include the sensor libraries: +#include "Adafruit_MCP9808.h" +#include "DHT.h" + +// Digital pin that the DHT sensor is connected to: +#include +#include +// include the WiFi network SSID and password: +#include "arduino_secrets.h" +// include the content documents: +#include "index.h" +#include "styles.h" +#include "script.h" + +// initialize the web server: +WiFiServer server(80); +// set the DHT22 sensor input pin: +const int DHTPin = 2; +// initialize the sensors: +DHT dhtSensor(DHTPin, DHT22); +Adafruit_MCP9808 MCPSensor = Adafruit_MCP9808(); + +void setup() { + // initialize serial communications: + Serial.begin(9600); + // attempt to connect to WiFi: + while (WiFi.status() != WL_CONNECTED) { + if (Serial) Serial.print("Attempting to connect to Network named: "); + if (Serial) Serial.println(SECRET_SSID); // print the network name (SSID) + WiFi.begin(SECRET_SSID, SECRET_PASS); // try to connect + delay(2000); + } + // When you're connected, print out the device's network status: + IPAddress ip = WiFi.localIP(); + if (Serial) Serial.print("IP Address: "); + if (Serial) Serial.println(ip); + // start the server: + server.begin(); + // start the MCP sensor: + while (!MCPSensor.begin(0x18)) { + if (Serial) Serial.println("sensor not found. Check connections."); + delay(1000); + } + // Set the MCS sensor to 0.5°C resolution: + MCPSensor.setResolution(0); + MCPSensor.wake(); + // start the DHT22 sensor: + dhtSensor.begin(); +} + +void loop() { + // wait for a new client: + WiFiClient client = server.available(); + + // when you get a new client: + if (client) { + if (Serial) Serial.println("new client"); + // prepare a response string and content type: + String response = ""; + String contentType = "text/"; + // while the client is connected, read the strings it sends: + while (client.connected()) { + if (client.available()) { + // read until you get a newline character + String input = client.readStringUntil('\n'); + if (Serial) Serial.println(input); + // if you only get a return character, then you've reached the end + // of the request. You can send a response: + if (input == "\r") { + Serial.println("request finished"); + // send a standard HTTP response header + client.println("HTTP/1.1 200 OK"); + // set the content type (HTML, CSS, or JS): + client.println("Content-Type: " + contentType); + // the connection will be closed after completion of the response + client.println("Connection: close"); + client.println(); + // send the response and a blank line after: + client.println(response); + client.println(); + break; + } + // trim any whitespace from the response: + input.trim(); + // check what the GET request is (always ends with /HTTP/1.1): + // the index page request: + if (input.endsWith("/ HTTP/1.1") || input.endsWith("/index.html HTTP/1.1")) { + response = String(INDEXHTML); + contentType += "html"; + } + // the stylesheet request: + if (input.endsWith("/styles.css HTTP/1.1")) { + response = String(STYLESCSS); + contentType += "css"; + } + // the javascript response: + if (input.endsWith("/script.js HTTP/1.1")) { + response = String(SCRIPTJS); + contentType += "js"; + } + // a custom response that sends the readings as JSON: + if (input.endsWith("/readings HTTP/1.1")) { + response = getReadings(); + contentType += "json"; + } + } + } + // if the client is diconnected, close the connection: + client.stop(); + if (Serial) Serial.println("client disconnected"); + } +} + +// read all the sensors and send them as a JSON string: +String getReadings() { + // get the MCP9808 reading: + String text = "{\"mcpTemp\":"; + text += String(MCPSensor.readTempF(), 4); + // get the DHT22 readings: + text += ",\"humidity\":"; + float humidity = dhtSensor.readHumidity(); + text += String(humidity, 4); + text += ",\"dhtTemp\":"; + float DhtTempF = dhtSensor.readTemperature(true); + text += String(DhtTempF, 4); + text += "}"; + return text; +} \ No newline at end of file diff --git a/Servers/SensorWebServerWithCSSandJS/index.h b/Servers/SensorWebServerWithCSSandJS/index.h new file mode 100644 index 0000000..f7e7847 --- /dev/null +++ b/Servers/SensorWebServerWithCSSandJS/index.h @@ -0,0 +1,18 @@ +/* + This is the HTML file. You can take a HTML file, paste it here in quotes, + add \ at the end of each line, escape the internal quotes with \, and you're done +*/ + +#define INDEXHTML " \ + \ + \ + \ + \ + Temperature \ + \ + \ + MCP9808 Temp: °F
\ + DHT22 Temp: °F
\ + DHT22 Humidity: %
\ + \ +" \ No newline at end of file diff --git a/Servers/SensorWebServerWithCSSandJS/script.h b/Servers/SensorWebServerWithCSSandJS/script.h new file mode 100644 index 0000000..62fb4ac --- /dev/null +++ b/Servers/SensorWebServerWithCSSandJS/script.h @@ -0,0 +1,28 @@ +/* + This is the javaScript file. You can take a JavaScript, paste it here in quotes, + add \ at the end of each line, escape the internal quotes with \, and you're done +*/ + +#define SCRIPTJS "function setup(event) { \ + console.log(\"begin\"); \ +setInterval(fetchJSON, 3000); \ +} \ +function fetchJSON() { \ + fetch(\'/readings\') \ + .then(response => response.json()) \ + .then(data => getResponse(data)) \ + .catch(error => getResponse(error)); \ +} \ +function getResponse(data) { \ + console.log(data); \ + for (property in data) { \ + let label = property; \ + let value = data[property]; \ + console.log(label); \ + console.log(value); \ + if (document.getElementById(label) != null) { \ + document.getElementById(label).innerHTML = value; \ + } \ + } \ +} \ +window.addEventListener(\'DOMContentLoaded\', setup);" \ No newline at end of file diff --git a/Servers/SensorWebServerWithCSSandJS/styles.h b/Servers/SensorWebServerWithCSSandJS/styles.h new file mode 100644 index 0000000..7e2735c --- /dev/null +++ b/Servers/SensorWebServerWithCSSandJS/styles.h @@ -0,0 +1,17 @@ +/* + This is the stylesheet. You can take a CSS file, paste it here in quotes, + add \ at the end of each line, escape the internal quotes with \, and you're done +*/ + +#define STYLESCSS "span.name { \ + position: sticky; \ + left: 20px; \ +} \ +span.value { \ + position:sticky; \ + left: 150px; \ +} \ +span.units { \ + position:sticky; \ + left: 200px; \ +}\n" \ No newline at end of file