envirstation first commit

This commit is contained in:
Laurent Deleers
2020-04-10 10:47:07 +02:00
commit f72662c8d3
6 changed files with 1311 additions and 0 deletions

385
DHT.cpp Normal file
View File

@@ -0,0 +1,385 @@
/*!
* @file DHT.cpp
*
* @mainpage DHT series of low cost temperature/humidity sensors.
*
* @section intro_sec Introduction
*
* This is a library for DHT series of low cost temperature/humidity sensors.
*
* You must have Adafruit Unified Sensor Library library installed to use this
* class.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit andopen-source hardware by purchasing products
* from Adafruit!
*
* @section author Author
*
* Written by Adafruit Industries.
*
* @section license License
*
* MIT license, all text above must be included in any redistribution
*/
#include "DHT.h"
#define MIN_INTERVAL 2000 /**< min interval value */
#define TIMEOUT -1 /**< timeout on */
/*!
* @brief Instantiates a new DHT class
* @param pin
* pin number that sensor is connected
* @param type
* type of sensor
* @param count
* number of sensors
*/
DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
_pin = pin;
_type = type;
#ifdef __AVR
_bit = digitalPinToBitMask(pin);
_port = digitalPinToPort(pin);
#endif
_maxcycles =
microsecondsToClockCycles(1000); // 1 millisecond timeout for
// reading pulses from DHT sensor.
// Note that count is now ignored as the DHT reading algorithm adjusts itself
// based on the speed of the processor.
}
/*!
* @brief Setup sensor pins and set pull timings
* @param usec
* Optionally pass pull-up time (in microseconds) before DHT reading
*starts. Default is 55 (see function declaration in DHT.h).
*/
void DHT::begin(uint8_t usec) {
// set up the pins!
pinMode(_pin, INPUT_PULLUP);
// Using this value makes sure that millis() - lastreadtime will be
// >= MIN_INTERVAL right away. Note that this assignment wraps around,
// but so will the subtraction.
_lastreadtime = millis() - MIN_INTERVAL;
DEBUG_PRINT("DHT max clock cycles: ");
DEBUG_PRINTLN(_maxcycles, DEC);
pullTime = usec;
}
/*!
* @brief Read temperature
* @param S
* Scale. Boolean value:
* - true = Fahrenheit
* - false = Celcius
* @param force
* true if in force mode
* @return Temperature value in selected scale
*/
float DHT::readTemperature(bool S, bool force) {
float f = NAN;
if (read(force)) {
switch (_type) {
case DHT11:
f = data[2];
if (data[3] & 0x80) {
f = -1 - f;
}
f += (data[3] & 0x0f) * 0.1;
if (S) {
f = convertCtoF(f);
}
break;
case DHT12:
f = data[2];
f += (data[3] & 0x0f) * 0.1;
if (data[2] & 0x80) {
f *= -1;
}
if (S) {
f = convertCtoF(f);
}
break;
case DHT22:
case DHT21:
f = ((word)(data[2] & 0x7F)) << 8 | data[3];
f *= 0.1;
if (data[2] & 0x80) {
f *= -1;
}
if (S) {
f = convertCtoF(f);
}
break;
}
}
return f;
}
/*!
* @brief Converts Celcius to Fahrenheit
* @param c
* value in Celcius
* @return float value in Fahrenheit
*/
float DHT::convertCtoF(float c) { return c * 1.8 + 32; }
/*!
* @brief Converts Fahrenheit to Celcius
* @param f
* value in Fahrenheit
* @return float value in Celcius
*/
float DHT::convertFtoC(float f) { return (f - 32) * 0.55555; }
/*!
* @brief Read Humidity
* @param force
* force read mode
* @return float value - humidity in percent
*/
float DHT::readHumidity(bool force) {
float f = NAN;
if (read(force)) {
switch (_type) {
case DHT11:
case DHT12:
f = data[0] + data[1] * 0.1;
break;
case DHT22:
case DHT21:
f = ((word)data[0]) << 8 | data[1];
f *= 0.1;
break;
}
}
return f;
}
/*!
* @brief Compute Heat Index
* Simplified version that reads temp and humidity from sensor
* @param isFahrenheit
* true if fahrenheit, false if celcius (default
*true)
* @return float heat index
*/
float DHT::computeHeatIndex(bool isFahrenheit) {
float hi = computeHeatIndex(readTemperature(isFahrenheit), readHumidity(),
isFahrenheit);
return hi;
}
/*!
* @brief Compute Heat Index
* Using both Rothfusz and Steadman's equations
* (http://www.wpc.ncep.noaa.gov/html/heatindex_equation.shtml)
* @param temperature
* temperature in selected scale
* @param percentHumidity
* humidity in percent
* @param isFahrenheit
* true if fahrenheit, false if celcius
* @return float heat index
*/
float DHT::computeHeatIndex(float temperature, float percentHumidity,
bool isFahrenheit) {
float hi;
if (!isFahrenheit)
temperature = convertCtoF(temperature);
hi = 0.5 * (temperature + 61.0 + ((temperature - 68.0) * 1.2) +
(percentHumidity * 0.094));
if (hi > 79) {
hi = -42.379 + 2.04901523 * temperature + 10.14333127 * percentHumidity +
-0.22475541 * temperature * percentHumidity +
-0.00683783 * pow(temperature, 2) +
-0.05481717 * pow(percentHumidity, 2) +
0.00122874 * pow(temperature, 2) * percentHumidity +
0.00085282 * temperature * pow(percentHumidity, 2) +
-0.00000199 * pow(temperature, 2) * pow(percentHumidity, 2);
if ((percentHumidity < 13) && (temperature >= 80.0) &&
(temperature <= 112.0))
hi -= ((13.0 - percentHumidity) * 0.25) *
sqrt((17.0 - abs(temperature - 95.0)) * 0.05882);
else if ((percentHumidity > 85.0) && (temperature >= 80.0) &&
(temperature <= 87.0))
hi += ((percentHumidity - 85.0) * 0.1) * ((87.0 - temperature) * 0.2);
}
return isFahrenheit ? hi : convertFtoC(hi);
}
/*!
* @brief Read value from sensor or return last one from less than two
*seconds.
* @param force
* true if using force mode
* @return float value
*/
bool DHT::read(bool force) {
// Check if sensor was read less than two seconds ago and return early
// to use last reading.
uint32_t currenttime = millis();
if (!force && ((currenttime - _lastreadtime) < MIN_INTERVAL)) {
return _lastresult; // return last correct measurement
}
_lastreadtime = currenttime;
// Reset 40 bits of received data to zero.
data[0] = data[1] = data[2] = data[3] = data[4] = 0;
#if defined(ESP8266)
yield(); // Handle WiFi / reset software watchdog
#endif
// Send start signal. See DHT datasheet for full signal diagram:
// http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf
// Go into high impedence state to let pull-up raise data line level and
// start the reading process.
pinMode(_pin, INPUT_PULLUP);
delay(1);
// First set data line low for a period according to sensor type
pinMode(_pin, OUTPUT);
digitalWrite(_pin, LOW);
switch (_type) {
case DHT22:
case DHT21:
delayMicroseconds(1100); // data sheet says "at least 1ms"
break;
case DHT11:
default:
delay(20); // data sheet says at least 18ms, 20ms just to be safe
break;
}
uint32_t cycles[80];
{
// End the start signal by setting data line high for 40 microseconds.
pinMode(_pin, INPUT_PULLUP);
// Delay a moment to let sensor pull data line low.
delayMicroseconds(pullTime);
// Now start reading the data line to get the value from the DHT sensor.
// Turn off interrupts temporarily because the next sections
// are timing critical and we don't want any interruptions.
InterruptLock lock;
// First expect a low signal for ~80 microseconds followed by a high signal
// for ~80 microseconds again.
if (expectPulse(LOW) == TIMEOUT) {
DEBUG_PRINTLN(F("DHT timeout waiting for start signal low pulse."));
_lastresult = false;
return _lastresult;
}
if (expectPulse(HIGH) == TIMEOUT) {
DEBUG_PRINTLN(F("DHT timeout waiting for start signal high pulse."));
_lastresult = false;
return _lastresult;
}
// Now read the 40 bits sent by the sensor. Each bit is sent as a 50
// microsecond low pulse followed by a variable length high pulse. If the
// high pulse is ~28 microseconds then it's a 0 and if it's ~70 microseconds
// then it's a 1. We measure the cycle count of the initial 50us low pulse
// and use that to compare to the cycle count of the high pulse to determine
// if the bit is a 0 (high state cycle count < low state cycle count), or a
// 1 (high state cycle count > low state cycle count). Note that for speed
// all the pulses are read into a array and then examined in a later step.
for (int i = 0; i < 80; i += 2) {
cycles[i] = expectPulse(LOW);
cycles[i + 1] = expectPulse(HIGH);
}
} // Timing critical code is now complete.
// Inspect pulses and determine which ones are 0 (high state cycle count < low
// state cycle count), or 1 (high state cycle count > low state cycle count).
for (int i = 0; i < 40; ++i) {
uint32_t lowCycles = cycles[2 * i];
uint32_t highCycles = cycles[2 * i + 1];
if ((lowCycles == TIMEOUT) || (highCycles == TIMEOUT)) {
DEBUG_PRINTLN(F("DHT timeout waiting for pulse."));
_lastresult = false;
return _lastresult;
}
data[i / 8] <<= 1;
// Now compare the low and high cycle times to see if the bit is a 0 or 1.
if (highCycles > lowCycles) {
// High cycles are greater than 50us low cycle count, must be a 1.
data[i / 8] |= 1;
}
// Else high cycles are less than (or equal to, a weird case) the 50us low
// cycle count so this must be a zero. Nothing needs to be changed in the
// stored data.
}
DEBUG_PRINTLN(F("Received from DHT:"));
DEBUG_PRINT(data[0], HEX);
DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[1], HEX);
DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[2], HEX);
DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[3], HEX);
DEBUG_PRINT(F(", "));
DEBUG_PRINT(data[4], HEX);
DEBUG_PRINT(F(" =? "));
DEBUG_PRINTLN((data[0] + data[1] + data[2] + data[3]) & 0xFF, HEX);
// Check we read 40 bits and that the checksum matches.
if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
_lastresult = true;
return _lastresult;
} else {
DEBUG_PRINTLN(F("DHT checksum failure!"));
_lastresult = false;
return _lastresult;
}
}
// Expect the signal line to be at the specified level for a period of time and
// return a count of loop cycles spent at that level (this cycle count can be
// used to compare the relative time of two pulses). If more than a millisecond
// ellapses without the level changing then the call fails with a 0 response.
// This is adapted from Arduino's pulseInLong function (which is only available
// in the very latest IDE versions):
// https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_pulse.c
uint32_t DHT::expectPulse(bool level) {
#if (F_CPU > 16000000L)
uint32_t count = 0;
#else
uint16_t count = 0; // To work fast enough on slower AVR boards
#endif
// On AVR platforms use direct GPIO port access as it's much faster and better
// for catching pulses that are 10's of microseconds in length:
#ifdef __AVR
uint8_t portState = level ? _bit : 0;
while ((*portInputRegister(_port) & _bit) == portState) {
if (count++ >= _maxcycles) {
return TIMEOUT; // Exceeded timeout, fail.
}
}
// Otherwise fall back to using digitalRead (this seems to be necessary on
// ESP8266 right now, perhaps bugs in direct port access functions?).
#else
while (digitalRead(_pin) == level) {
if (count++ >= _maxcycles) {
return TIMEOUT; // Exceeded timeout, fail.
}
}
#endif
return count;
}

92
DHT.h Normal file
View File

@@ -0,0 +1,92 @@
/*!
* @file DHT.h
*
* This is a library for DHT series of low cost temperature/humidity sensors.
*
* You must have Adafruit Unified Sensor Library library installed to use this class.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit andopen-source hardware by purchasing products
* from Adafruit!
*
* Written by Adafruit Industries.
*
* MIT license, all text above must be included in any redistribution
*/
#ifndef DHT_H
#define DHT_H
#include "Arduino.h"
/* Uncomment to enable printing out nice debug messages. */
//#define DHT_DEBUG
#define DEBUG_PRINTER Serial /**< Define where debug output will be printed. */
/* Setup debug printing macros. */
#ifdef DHT_DEBUG
#define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); }
#else
#define DEBUG_PRINT(...) {} /**< Debug Print Placeholder if Debug is disabled */
#define DEBUG_PRINTLN(...) {} /**< Debug Print Line Placeholder if Debug is disabled */
#endif
/* Define types of sensors. */
#define DHT11 11 /**< DHT TYPE 11 */
#define DHT12 12 /**< DHY TYPE 12 */
#define DHT22 22 /**< DHT TYPE 22 */
#define DHT21 21 /**< DHT TYPE 21 */
#define AM2301 21 /**< AM2301 */
/*!
* @brief Class that stores state and functions for DHT
*/
class DHT {
public:
DHT(uint8_t pin, uint8_t type, uint8_t count=6);
void begin(uint8_t usec=55);
float readTemperature(bool S=false, bool force=false);
float convertCtoF(float);
float convertFtoC(float);
float computeHeatIndex(bool isFahrenheit=true);
float computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit=true);
float readHumidity(bool force=false);
bool read(bool force=false);
private:
uint8_t data[5];
uint8_t _pin, _type;
#ifdef __AVR
// Use direct GPIO access on an 8-bit AVR so keep track of the port and bitmask
// for the digital pin connected to the DHT. Other platforms will use digitalRead.
uint8_t _bit, _port;
#endif
uint32_t _lastreadtime, _maxcycles;
bool _lastresult;
uint8_t pullTime; // Time (in usec) to pull up data line before reading
uint32_t expectPulse(bool level);
};
/*!
* @brief Class that defines Interrupt Lock Avaiability
*/
class InterruptLock {
public:
InterruptLock() {
#if !defined(ARDUINO_ARCH_NRF52)
noInterrupts();
#endif
}
~InterruptLock() {
#if !defined(ARDUINO_ARCH_NRF52)
interrupts();
#endif
}
};
#endif

103
IMG_0001.h Normal file
View File

@@ -0,0 +1,103 @@
#ifndef _GxBootExample_H_
#define _GxBootExample_H_
#if defined(ESP8266) || defined(ESP32)
#include <pgmspace.h>
#else
#include <avr/pgmspace.h>
#endif
// 180 x 64 (Boot)
const unsigned char gImage_IMG_0001[1440] PROGMEM = { /* 0X01,0X01,0XB4,0X00,0X40,0X00, */
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XF0,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XC0,0X1F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X07,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0X00,0X01,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X01,0X80,0X3F,0XFF,0XFF,
0XFF,0XFF,0XFC,0X01,0XE0,0X1F,0XFF,0XFF,0XFF,0XFF,0XF8,0X10,0XF8,0X0F,0XFF,0XFF,
0XFF,0XFF,0XF8,0X70,0XF8,0X0F,0XFF,0XFF,0XFF,0XFF,0XF0,0X70,0XF8,0X0F,0XFF,0XFF,
0XFF,0XFF,0XF0,0XF0,0XF8,0X07,0XFF,0XFF,0XFF,0XFF,0XE1,0XF0,0XFC,0X07,0XFF,0XFF,
0XFF,0XFF,0XE1,0XF0,0XFC,0X03,0XFF,0XFF,0XFF,0XFF,0XE3,0XF0,0XFC,0X01,0XFF,0XFF,
0XFF,0XFF,0XE3,0XF0,0XFC,0X21,0XFF,0XFF,0XFF,0XFF,0XC3,0XF8,0XFE,0X21,0XFF,0XFF,
0XFF,0XFF,0XC3,0XF8,0XFE,0X10,0XFF,0XFF,0XFF,0XFF,0XC7,0XF8,0XFE,0X10,0XFF,0XFF,
0XFF,0XFF,0XC7,0XF8,0XFE,0X10,0XFF,0XFF,0XFF,0XFF,0XC7,0XF8,0XFF,0X18,0XFF,0XFF,
0XFF,0XFF,0XC7,0XF8,0XFF,0X08,0XFF,0XFF,0XFF,0XFF,0XC7,0XF0,0XFF,0X00,0XFF,0XFF,
0XFF,0XFF,0XC7,0XF0,0XFF,0X80,0XFF,0XFF,0XFF,0XFF,0XC7,0XF0,0XFF,0X80,0X7F,0XFF,
0XFF,0XFF,0XC7,0XF0,0XFF,0XC0,0X3F,0XFF,0XFF,0XFF,0X87,0XF1,0XFF,0XC0,0X3F,0XFF,
0XFF,0XFF,0X07,0XF1,0XFF,0XE0,0X1F,0XFF,0XFF,0XFF,0X03,0XE1,0XFF,0XE0,0X1F,0XFF,
0XFF,0XFE,0X01,0XE1,0XFF,0XF1,0X1F,0XFF,0XFF,0XFC,0X01,0XE1,0XFF,0XF1,0X1F,0XFF,
0XFF,0XF8,0X21,0XE1,0XFF,0XF1,0X1F,0XFF,0XFF,0XE0,0X31,0XE1,0XFF,0XF1,0X1F,0XFF,
0XFF,0XE0,0XF1,0XF1,0XFF,0XF1,0X1F,0XFF,0XFF,0XC1,0XF1,0XF0,0XFF,0XF1,0X0F,0XFF,
0XFF,0X83,0XF1,0XF0,0XFF,0XF1,0X0F,0XFF,0XFF,0X87,0XF1,0XF0,0XFF,0XF1,0X0F,0XFF,
0XFF,0X07,0XF1,0XF0,0XFF,0XF0,0X8F,0XFF,0XFF,0X0F,0XF1,0XF0,0XFF,0XF0,0X8F,0XFF,
0XFE,0X0F,0XF1,0XF0,0XFF,0XF8,0X8F,0XFF,0XFE,0X1F,0XF1,0XF0,0XFF,0XF8,0X07,0XFF,
0XFC,0X1F,0XE1,0XF0,0XFF,0XF8,0X07,0XFF,0XFC,0X1F,0XE1,0XF8,0XFF,0XFC,0X03,0XFF,
0XFC,0X1F,0XE1,0XF8,0XFF,0XFC,0X03,0XFF,0XFC,0X07,0XE3,0XF8,0XFF,0XFC,0X23,0XFF,
0XF8,0X01,0XE3,0XF8,0XFF,0XFE,0X21,0XFF,0XF8,0X00,0XE3,0XF8,0XFF,0XFE,0X21,0XFF,
0XF8,0X43,0X23,0XF8,0XFF,0XFE,0X31,0XFF,0XF8,0X40,0X03,0XF8,0XFF,0XFE,0X31,0XFF,
0XF0,0X60,0X03,0XF8,0XFF,0XFE,0X31,0XFF,0XF0,0XE0,0X03,0XF8,0XFF,0XFE,0X31,0XFF,
0XE0,0XFC,0X03,0XF8,0X7F,0XFE,0X30,0XFF,0XE1,0XFF,0X83,0XF8,0X7F,0XFE,0X30,0XFF,
0XE1,0XFF,0XC3,0XFC,0X7F,0XFE,0X30,0XFF,0XE1,0XFF,0XC3,0XFC,0X7F,0XFE,0X38,0XFF,
0XE1,0XFF,0XE3,0XFC,0X3F,0XFE,0X38,0X7F,0XE1,0XFF,0XE3,0XFC,0X3F,0XFE,0X18,0X7F,
0XE1,0XFF,0XE3,0XFC,0X3F,0XFE,0X18,0X3F,0XE1,0XFF,0XE3,0XFC,0X3F,0XFE,0X1C,0X3F,
0XF1,0XFF,0XE3,0XFE,0X3F,0XFF,0X0C,0X3F,0XF1,0XFF,0XE3,0XFE,0X3F,0XFF,0X0E,0X3F,
0XE1,0XFF,0XE3,0XFE,0X1F,0XFF,0X86,0X3F,0XE1,0XFF,0XE3,0XFE,0X1F,0XFF,0X86,0X3F,
0XE1,0XFF,0XE3,0XFE,0X1F,0XFF,0X86,0X3F,0XE3,0XFF,0XE3,0XFE,0X1F,0XFF,0X86,0X3F,
0XE3,0XFF,0XE3,0XFF,0X1F,0XFF,0X86,0X3F,0XC3,0XFF,0XE3,0XFF,0X1F,0XFF,0X8E,0X3F,
0XC3,0XFF,0XE3,0XFF,0X1F,0XFF,0X8E,0X3F,0XC7,0XFF,0XC3,0XFF,0X1F,0XFF,0X8E,0X3F,
0XC7,0XFF,0XC3,0XFF,0X0F,0XFF,0X8E,0X3F,0XC3,0XFF,0XC3,0XFF,0X0F,0XFF,0X8E,0X3F,
0XC0,0X7F,0XC7,0XFF,0X0F,0XFF,0X8E,0X1F,0XC0,0X3F,0XC7,0XFF,0X0F,0XFF,0X8E,0X0F,
0XE0,0X0F,0XC7,0XFF,0X0F,0XFF,0X86,0X0F,0XE2,0X07,0XC7,0XFF,0X0F,0XFF,0X87,0X0F,
0XE3,0X07,0XC7,0XFF,0X8F,0XFF,0XC7,0X8F,0XE3,0X83,0X87,0XFF,0X8F,0XFF,0XC7,0X8F,
0XE3,0XC0,0X87,0XFF,0X8F,0XFF,0XC7,0X0F,0XE3,0XE0,0X0F,0XFF,0X8F,0XFF,0XC7,0X0F,
0XE3,0XF0,0X07,0XFF,0X87,0XFF,0XC7,0X1F,0XE3,0XF8,0X07,0XFF,0X87,0XFF,0XC7,0X1F,
0XC3,0XFC,0X07,0XFF,0X87,0XFF,0XC7,0X1F,0XC3,0XFE,0X07,0XFF,0X87,0XFF,0XC3,0X0F,
0XC3,0XFE,0X07,0XFF,0X87,0XFF,0XC3,0X0F,0XC7,0XFF,0X07,0XFF,0X87,0XFF,0XC3,0X8F,
0XC1,0XFF,0XC7,0XFF,0X87,0XFF,0XE3,0X87,0XC0,0X3F,0X87,0XFF,0X87,0XFF,0XE3,0X83,
0XC0,0X1F,0X87,0XFF,0X87,0XFF,0XE3,0X83,0XC0,0X1F,0X87,0XFF,0X87,0XFF,0XE3,0XC3,
0XE2,0X07,0X87,0XFF,0X83,0XFF,0XE3,0XC3,0XE1,0X07,0X87,0XFF,0X83,0XFF,0XE3,0XC3,
0XE1,0X81,0X87,0XFF,0X83,0XFF,0XE3,0XC3,0XE1,0XC0,0X87,0XFF,0XC3,0XFF,0XE3,0XC7,
0XE1,0XE0,0X0F,0XFF,0XC3,0XFF,0XE3,0XC7,0XE1,0XF0,0X07,0XFF,0XC3,0XFF,0XE3,0XC7,
0XE1,0XF8,0X0F,0XFF,0XC3,0XFF,0XE3,0XC7,0XE1,0XFE,0X0F,0XFF,0XC3,0XFF,0XE3,0XC7,
0XF1,0XFF,0X0F,0XFF,0XC3,0XFF,0XE3,0XC3,0XF1,0XFF,0X0F,0XFF,0XE3,0XFF,0XE3,0XC3,
0XF0,0XFF,0X0F,0XFF,0XE1,0XFF,0XE3,0XE3,0XF0,0XFF,0X8F,0XFF,0XE1,0XFF,0XE3,0XE3,
0XF8,0X7F,0X8F,0XFF,0XE1,0XFF,0XE3,0XE3,0XF8,0X3F,0X8F,0XFF,0XE1,0XFF,0XE3,0XE3,
0XFC,0X1F,0X87,0XFF,0XE1,0XFF,0XE3,0XE3,0XFE,0X0F,0X87,0XFF,0XE1,0XFF,0XE1,0XE3,
0XFF,0X0F,0X87,0XFF,0XE1,0XFF,0XE1,0XE3,0XFF,0X87,0X87,0XFF,0XE1,0XFF,0XE1,0XE3,
0XFF,0X83,0X87,0XFF,0XE1,0XFF,0XF1,0XC3,0XFF,0X81,0X87,0XFF,0XE1,0XFF,0XF1,0XC3,
0XFF,0XC0,0X87,0XFF,0XE1,0XFF,0XF1,0X83,0XFF,0XE0,0X0F,0XFF,0XF1,0XFF,0XF1,0X87,
0XFF,0XF0,0X0F,0XFF,0XF1,0XFF,0XF1,0X87,0XFF,0XFC,0X0F,0XFF,0XE0,0XFF,0XF1,0X8F,
0XFF,0XFE,0X0F,0XFF,0XE0,0XFF,0XF1,0X8F,0XFF,0XFE,0X0F,0XFF,0XE0,0XFF,0XE1,0X8F,
0XFF,0XFF,0X0F,0XFF,0XE0,0XFF,0XE1,0X8F,0XFF,0XFF,0X07,0XFF,0XF0,0XFF,0XE3,0X8F,
0XFF,0XFF,0X87,0XFF,0XF0,0XFF,0XE3,0X8F,0XFF,0XFF,0X87,0XFF,0XF0,0XFF,0XE3,0X8F,
0XFF,0XFF,0XC3,0XFF,0XF0,0XFF,0XE3,0X8F,0XFF,0XFF,0XC3,0XFF,0XF0,0XFF,0XE3,0X8F,
0XFF,0XFF,0XC3,0XFF,0XF0,0XFF,0XE3,0X8F,0XFF,0XFF,0XE3,0XFF,0XF0,0XFF,0XE3,0X8F,
0XFF,0XFF,0XE3,0XFF,0XF0,0XFF,0XE3,0X8F,0XFF,0XFF,0XE1,0XFF,0XF0,0XFF,0XE3,0X0F,
0XFF,0XFF,0XE1,0XFF,0XF0,0XFF,0XE3,0X0F,0XFF,0XFF,0XE1,0XFF,0XF0,0XFF,0XE3,0X1F,
0XFF,0XFF,0XF1,0XFF,0XF0,0XFF,0XE3,0X1F,0XFF,0XFF,0XF0,0XFF,0XF8,0XFF,0XE3,0X1F,
0XFF,0XFF,0XF0,0XFF,0XF8,0X7F,0XE3,0X1F,0XFF,0XFF,0XF0,0XFF,0XF8,0X7F,0XC2,0X1F,
0XFF,0XFF,0XF8,0X7F,0XF8,0X7F,0XC0,0X1F,0XFF,0XFF,0XF8,0X7F,0XF8,0X7F,0XC4,0X1F,
0XFF,0XFF,0XF8,0X7F,0XF8,0X7F,0XC4,0X3F,0XFF,0XFF,0XFC,0X7F,0XF8,0X7F,0XC0,0X7F,
0XFF,0XFF,0XFC,0X7F,0XF8,0X7F,0XC0,0X7F,0XFF,0XFF,0XFC,0X7F,0XF8,0X7F,0XC0,0XFF,
0XFF,0XFF,0XFC,0X7F,0XF8,0X7F,0XE0,0XFF,0XFF,0XFF,0XFC,0X7F,0XF8,0X7F,0XE0,0XFF,
0XFF,0XFF,0XFC,0X3F,0XF8,0X7F,0XE1,0XFF,0XFF,0XFF,0XFC,0X3F,0XF8,0X7F,0XE1,0XFF,
0XFF,0XFF,0XFC,0X3F,0XF8,0X7F,0XC3,0XFF,0XFF,0XFF,0XFE,0X1F,0XF8,0X7F,0XC3,0XFF,
0XFF,0XFF,0XFE,0X1F,0XF0,0X7F,0X83,0XFF,0XFF,0XFF,0XFE,0X0F,0XF0,0X7F,0X87,0XFF,
0XFF,0XFF,0XFF,0X0F,0XF0,0X7F,0X8F,0XFF,0XFF,0XFF,0XFF,0X87,0XF0,0X7F,0X0F,0XFF,
0XFF,0XFF,0XFF,0X87,0XF0,0X7E,0X0F,0XFF,0XFF,0XFF,0XFF,0XC3,0XF0,0X7E,0X0F,0XFF,
0XFF,0XFF,0XFF,0XC1,0XF0,0X7E,0X1F,0XFF,0XFF,0XFF,0XFF,0XE1,0XF0,0X7C,0X3F,0XFF,
0XFF,0XFF,0XFF,0XE0,0XF0,0X7C,0X3F,0XFF,0XFF,0XFF,0XFF,0XF0,0XF0,0X78,0X3F,0XFF,
0XFF,0XFF,0XFF,0XF8,0X70,0X70,0X7F,0XFF,0XFF,0XFF,0XFF,0XF8,0X38,0X60,0X7F,0XFF,
0XFF,0XFF,0XFF,0XFC,0X3C,0X20,0XFF,0XFF,0XFF,0XFF,0XFF,0XFC,0X1C,0X01,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFE,0X18,0X03,0XFF,0XFF,0XFF,0XFF,0XFF,0XFE,0X18,0X03,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0X18,0X07,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X08,0X07,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0X08,0X0F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X00,0X1F,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0X80,0X3F,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0X80,0X7F,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XF8,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,
};
#endif

304
NTPtimeESP.cpp Normal file
View File

@@ -0,0 +1,304 @@
/*
NTP
This routine gets the unixtime from a NTP server and adjusts it to the time zone and the
Middle European summer time if requested
Author: Andreas Spiess V1.0 2016-5-28
Based on work from John Lassen: http://www.john-lassen.de/index.php/projects/esp-8266-arduino-ide-webconfig
*/
#include <Arduino.h>
#include "NTPtimeESP.h"
#define LEAP_YEAR(Y) ( ((1970+Y)>0) && !((1970+Y)%4) && ( ((1970+Y)%100) || !((1970+Y)%400) ) )
#define SEC_TO_MS 1000
#define RECV_TIMEOUT_DEFATUL 1 // 1 second
#define SEND_INTRVL_DEFAULT 1 // 1 second
#define MAX_SEND_INTERVAL 60 // 60 seconds
#define MAC_RECV_TIMEOUT 60 // 60 seconds
const int NTP_PACKET_SIZE = 48;
byte _packetBuffer[ NTP_PACKET_SIZE];
static const uint8_t _monthDays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
float _timeZone=0.0;
String _NTPserver="";
// NTPserver is the name of the NTPserver
bool NTPtime::setSendInterval(unsigned long _sendInterval_) {
bool retVal = false;
if(_sendInterval_ <= MAX_SEND_INTERVAL) {
_sendInterval = _sendInterval_ * SEC_TO_MS;
retVal = true;
}
return retVal;
}
bool NTPtime::setRecvTimeout(unsigned long _recvTimeout_) {
bool retVal = false;
if(_recvTimeout_ <= MAC_RECV_TIMEOUT) {
_recvTimeout = _recvTimeout_ * SEC_TO_MS;
retVal = true;
}
return retVal;
}
NTPtime::NTPtime() {
_sendPhase = true;
_sentTime = 0;
_sendInterval = SEND_INTRVL_DEFAULT * SEC_TO_MS;
_recvTimeout = RECV_TIMEOUT_DEFATUL * SEC_TO_MS;
}
NTPtime::NTPtime(String NTPserver) {
_NTPserver = NTPserver;
_sendPhase = true;
_sentTime = 0;
_sendInterval = SEND_INTRVL_DEFAULT * SEC_TO_MS;
_recvTimeout = RECV_TIMEOUT_DEFATUL * SEC_TO_MS;
}
void NTPtime::setNTPPool(String NTPserver) {
_NTPserver = NTPserver;
}
void NTPtime::printDateTime(strDateTime _dateTime) {
if (_dateTime.valid) {
Serial.print(_dateTime.year);
Serial.print( "-");
Serial.print(_dateTime.month);
Serial.print( "-");
Serial.print(_dateTime.day);
Serial.print( "-");
Serial.print(_dateTime.dayofWeek);
Serial.print( " ");
Serial.print(_dateTime.hour);
Serial.print( "H ");
Serial.print(_dateTime.minute);
Serial.print( "M ");
Serial.print(_dateTime.second);
Serial.print( "S ");
Serial.println();
} else {
#ifdef DEBUG_ON
Serial.println("Invalid time !!!");
Serial.println("");
#endif
}
}
// Converts a unix time stamp to a strDateTime structure
strDateTime NTPtime::ConvertUnixTimestamp( unsigned long _tempTimeStamp) {
strDateTime _tempDateTime;
uint8_t _year, _month, _monthLength;
uint32_t _time;
unsigned long _days;
_tempDateTime.epochTime = _tempTimeStamp;
_time = (uint32_t)_tempTimeStamp;
_tempDateTime.second = _time % 60;
_time /= 60; // now it is minutes
_tempDateTime.minute = _time % 60;
_time /= 60; // now it is hours
_tempDateTime.hour = _time % 24;
_time /= 24; // now it is _days
_tempDateTime.dayofWeek = ((_time + 4) % 7) + 1; // Sunday is day 1
_year = 0;
_days = 0;
while ((unsigned)(_days += (LEAP_YEAR(_year) ? 366 : 365)) <= _time) {
_year++;
}
_tempDateTime.year = _year; // year is offset from 1970
_days -= LEAP_YEAR(_year) ? 366 : 365;
_time -= _days; // now it is days in this year, starting at 0
_days = 0;
_month = 0;
_monthLength = 0;
for (_month = 0; _month < 12; _month++) {
if (_month == 1) { // february
if (LEAP_YEAR(_year)) {
_monthLength = 29;
} else {
_monthLength = 28;
}
} else {
_monthLength = _monthDays[_month];
}
if (_time >= _monthLength) {
_time -= _monthLength;
} else {
break;
}
}
_tempDateTime.month = _month + 1; // jan is month 1
_tempDateTime.day = _time + 1; // day of month
_tempDateTime.year += 1970;
return _tempDateTime;
}
//
// Summertime calculates the daylight saving time for middle Europe. Input: Unixtime in UTC
//
boolean NTPtime::summerTime(unsigned long _timeStamp ) {
strDateTime _tempDateTime;
_tempDateTime = ConvertUnixTimestamp(_timeStamp);
// printTime("Innerhalb ", _tempDateTime);
if (_tempDateTime.month < 3 || _tempDateTime.month > 10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
if (_tempDateTime.month > 3 && _tempDateTime.month < 10) return true; // Sommerzeit in Apr, Mai, Jun, Jul, Aug, Sep
if (_tempDateTime.month == 3 && (_tempDateTime.hour + 24 * _tempDateTime.day) >= (3 + 24 * (31 - (5 * _tempDateTime.year / 4 + 4) % 7)) || _tempDateTime.month == 10 && (_tempDateTime.hour + 24 * _tempDateTime.day) < (3 + 24 * (31 - (5 * _tempDateTime.year / 4 + 1) % 7)))
return true;
else
return false;
}
boolean NTPtime::daylightSavingTime(unsigned long _timeStamp) {
strDateTime _tempDateTime;
_tempDateTime = ConvertUnixTimestamp(_timeStamp);
// here the US code
//return false;
// see http://stackoverflow.com/questions/5590429/calculating-daylight-saving-time-from-only-date
// since 2007 DST begins on second Sunday of March and ends on first Sunday of November.
// Time change occurs at 2AM locally
if (_tempDateTime.month < 3 || _tempDateTime.month > 11) return false; //January, february, and december are out.
if (_tempDateTime.month > 3 && _tempDateTime.month < 11) return true; //April to October are in
int previousSunday = _tempDateTime.day - (_tempDateTime.dayofWeek - 1); // dow Sunday input was 1,
// need it to be Sunday = 0. If 1st of month = Sunday, previousSunday=1-0=1
//int previousSunday = day - (dow-1);
// -------------------- March ---------------------------------------
//In march, we are DST if our previous Sunday was = to or after the 8th.
if (_tempDateTime.month == 3 ) { // in march, if previous Sunday is after the 8th, is DST
// unless Sunday and hour < 2am
if ( previousSunday >= 8 ) { // Sunday = 1
// return true if day > 14 or (dow == 1 and hour >= 2)
return ((_tempDateTime.day > 14) ||
((_tempDateTime.dayofWeek == 1 && _tempDateTime.hour >= 2) || _tempDateTime.dayofWeek > 1));
} // end if ( previousSunday >= 8 && _dateTime.dayofWeek > 0 )
else
{
// previousSunday has to be < 8 to get here
//return (previousSunday < 8 && (_tempDateTime.dayofWeek - 1) = 0 && _tempDateTime.hour >= 2)
return false;
} // end else
} // end if (_tempDateTime.month == 3 )
// ------------------------------- November -------------------------------
// gets here only if month = November
//In november we must be before the first Sunday to be dst.
//That means the previous Sunday must be before the 2nd.
if (previousSunday < 1)
{
// is not true for Sunday after 2am or any day after 1st Sunday any time
return ((_tempDateTime.dayofWeek == 1 && _tempDateTime.hour < 2) || (_tempDateTime.dayofWeek > 1));
//return true;
} // end if (previousSunday < 1)
else
{
// return false unless after first wk and dow = Sunday and hour < 2
return (_tempDateTime.day <8 && _tempDateTime.dayofWeek == 1 && _tempDateTime.hour < 2);
} // end else
} // end boolean NTPtime::daylightSavingTime(unsigned long _timeStamp)
unsigned long NTPtime::adjustTimeZone(unsigned long _timeStamp, float _timeZone, int _DayLightSaving) {
strDateTime _tempDateTime;
_timeStamp += (unsigned long)(_timeZone * 3600.0); // adjust timezone
if (_DayLightSaving ==1 && summerTime(_timeStamp)) _timeStamp += 3600; // European Summer time
if (_DayLightSaving ==2 && daylightSavingTime(_timeStamp)) _timeStamp += 3600; // US daylight time
return _timeStamp;
}
// time zone is the difference to UTC in hours
// if _isDayLightSaving is true, time will be adjusted accordingly
// Use returned time only after checking "ret.valid" flag
strDateTime NTPtime::getNTPtime(float _timeZone, int _DayLightSaving) {
int cb;
strDateTime _dateTime;
unsigned long _unixTime = 0;
_dateTime.valid = false;
unsigned long _currentTimeStamp;
if (_sendPhase) {
if (_sentTime && ((millis() - _sentTime) < _sendInterval)) {
return _dateTime;
}
_sendPhase = false;
UDPNTPClient.begin(1337); // Port for NTP receive
#ifdef DEBUG_ON
IPAddress _timeServerIP;
WiFi.hostByName(_NTPserver.c_str(), _timeServerIP);
Serial.println();
Serial.println(_timeServerIP);
Serial.println("Sending NTP packet (timout = "+String(_recvTimeout)+" , minInterval = "+String(_sendInterval)+" )");
#endif
memset(_packetBuffer, 0, NTP_PACKET_SIZE);
_packetBuffer[0] = 0b11100011; // LI, Version, Mode
_packetBuffer[1] = 0; // Stratum, or type of clock
_packetBuffer[2] = 6; // Polling Interval
_packetBuffer[3] = 0xEC; // Peer Clock Precision
_packetBuffer[12] = 49;
_packetBuffer[13] = 0x4E;
_packetBuffer[14] = 49;
_packetBuffer[15] = 52;
UDPNTPClient.beginPacket(_NTPserver.c_str(), 123);
UDPNTPClient.write(_packetBuffer, NTP_PACKET_SIZE);
UDPNTPClient.endPacket();
_sentTime = millis();
} else {
cb = UDPNTPClient.parsePacket();
if (cb == 0) {
#ifdef DEBUG_ON
Serial.println("NTP packet received, length=0 (OOPS!) query sent since " + String((millis() - _sentTime)) + " ms ");
#endif
if ((millis() - _sentTime) > _recvTimeout) {
_sendPhase = true;
_sentTime = 0;
}
} else {
#ifdef DEBUG_ON
Serial.print("NTP packet received, length=");
Serial.println(cb);
#endif
UDPNTPClient.read(_packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer
unsigned long highWord = word(_packetBuffer[40], _packetBuffer[41]);
unsigned long lowWord = word(_packetBuffer[42], _packetBuffer[43]);
unsigned long secsSince1900 = highWord << 16 | lowWord;
const unsigned long seventyYears = 2208988800UL;
_unixTime = secsSince1900 - seventyYears;
if (_unixTime > 0) {
_currentTimeStamp = adjustTimeZone(_unixTime, _timeZone, _DayLightSaving);
_dateTime = ConvertUnixTimestamp(_currentTimeStamp);
_dateTime.valid = true;
} else
_dateTime.valid = false;
_sendPhase = true;
}
}
return _dateTime;
}

60
NTPtimeESP.h Normal file
View File

@@ -0,0 +1,60 @@
/*
NTPtime for ESP8266/ESP32
This routine gets the unixtime from a NTP server and adjusts it to the time zone and the
Middle European summer time if requested
Author: Andreas Spiess V1.0 2016-6-28
Based on work from John Lassen: http://www.john-lassen.de/index.php/projects/esp-8266-arduino-ide-webconfig
*/
#ifndef NTPtime_h
#define NTPtime_h
// #define DEBUG_ON
#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <WiFiUdp.h>
struct strDateTime
{
byte hour;
byte minute;
byte second;
int year;
byte month;
byte day;
byte dayofWeek;
unsigned long epochTime;
boolean valid;
};
class NTPtime {
public:
NTPtime();
NTPtime(String NTPtime);
strDateTime getNTPtime(float _timeZone, int _DayLightSaving);
void setNTPPool(String NTPtime);
void printDateTime(strDateTime _dateTime);
bool setSendInterval(unsigned long _sendInterval); // in seconds
bool setRecvTimeout(unsigned long _recvTimeout); // in seconds
private:
bool _sendPhase;
unsigned long _sentTime;
unsigned long _sendInterval;
unsigned long _recvTimeout;
strDateTime ConvertUnixTimestamp( unsigned long _tempTimeStamp);
boolean summerTime(unsigned long _timeStamp );
boolean daylightSavingTime(unsigned long _timeStamp);
unsigned long adjustTimeZone(unsigned long _timeStamp, float _timeZone, int _DayLightSavingSaving);
WiFiUDP UDPNTPClient;
};
#endif

367
arduino-envirstation.ino Normal file
View File

@@ -0,0 +1,367 @@
// Arduino Environment Station for Wemos D1 Mini
// BUSY -> D0 = GPIO16
// RST -> D4 = GPIO2
// DC -> D3 = GPIO0
// CS -> D8 = GPIO15 (ADD 1Kohm pulldown resistor !!!)
// CLK -> D5 = GPIO14
// DIN -> D7 = GPIO13
// GND -> GND
// 3.3V -> 3.3V
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_BMP280.h>
#include <ESP8266WiFi.h>
#define BMP_SCK (13)
#define BMP_MISO (12)
#define BMP_MOSI (11)
#define BMP_CS (10)
#define HEAD_HEIGHT 18
#include "DHT.h"
// DHT -> D6
#define DHTPIN 12 // DHT Sensor PIN
#define DHTTYPE DHT22 // DHT Sensor Type
#include "NTPtimeESP.h"
#include <GxEPD.h>
#include <GxGDEW042T2/GxGDEW042T2.h>
#include GxEPD_BitmapExamples
// FreeFonts from Adafruit_GFX
#include <Fonts/FreeMonoBold9pt7b.h>
#include <Fonts/FreeMonoBold12pt7b.h>
#include <Fonts/FreeMonoBold18pt7b.h>
#include <Fonts/FreeMonoBold24pt7b.h>
#include <Fonts/FreeSansBold18pt7b.h>
#include <GxIO/GxIO_SPI/GxIO_SPI.h>
#include <GxIO/GxIO.h>
char *ssid = "lauIOT"; // Set you WiFi SSID
char *password = "superiot1"; // Set you WiFi password
GxIO_Class io(SPI, /*CS=D8*/ SS, /*DC=D3*/ 0, /*RST=D4*/ 2); // arbitrary selection of D3(=0), D4(=2), selected for default of GxEPD_Class
GxEPD_Class display(io, /*RST=D4*/ 2, /*BUSY=D0*/ 16); // default selection of D4(=2), D2(=4)
/*
Display config
----------------------------------
| header of 28 pixel height |
----------------------------------
| widget 0 | widget 1 | widget 2 |
| 130x90 | 130x90 | 130x90 |
| at 2,30 | at 135,30| at 138,30|
----------------------------------
| widget 3 | widget 4 | widget 5 |
| 130x90 | 130x90 | 130x90 |
| at 2,120 | at135,120| at138,120|
----------------------------------
| widget 6 | widget 7 | widget 8 |
| 130x90 | 130x90 | 130x90 |
| at 2,210 | at135,210| at138,210|
----------------------------------
TODOS
-----
- Draw Head OK
- - Draw Title OK
- Draw Widget OK
- Integrate TempS OK
- - Draw T° OK
- - Draw HR OK
- Integrate Pressure OK
- - Draw Press OK
- Draw min max OK
- Integrate Time OK
- - Draw Time OK
- Get variables private
- Publish REST API
- Show Temp & hydro graph
- Make formatting nicer :)
- Make it configurable (web interface)
- Timezone
- Wifi credentials
- reset high low
*/
DHT dht(DHTPIN, DHTTYPE); // Initialize DHT sensor for normal 16mhz Arduino
unsigned long ref_time;
Adafruit_BMP280 bmp; // I2C
NTPtime NTPch("ntp.belnet.be"); // Choose server pool as required
WiFiServer server(80);
class Environment {
public:
strDateTime dateTime;
Environment() {
this->temperature_min = 100.0;
this->temperature_max = -100.0;
this->humidity_min = 100.0;
this->humidity_max = 0.0;
this->pressure_min = 9999;
this->pressure_max = 0;
}
void setDateTime(strDateTime d) {
dateTime = d;
}
void setTemp(float t) {
this->temperature = t;
if(this->temperature < this->temperature_min ) this->temperature_min = this->temperature;
if(this->temperature > this->temperature_max ) this->temperature_max = this->temperature;
}
void setPress(unsigned int p) {
this->pressure = p;
if(this->pressure < this->pressure_min ) this->pressure_min = this->pressure;
if(this->pressure > this->pressure_max ) this->pressure_max = this->pressure;
}
void setHumid(float h) {
this->humidity = h;
if(this->humidity < this->humidity_min ) this->humidity_min = this->humidity;
if(this->humidity > this->humidity_max ) this->humidity_max = this->humidity;
}
float getTemp() { return this->temperature; }
float getTempMin() { return this->temperature_min; }
float getTempMax() { return this->temperature_max; }
unsigned int getPress() { return this->pressure; }
unsigned int getPressMin() { return this->pressure_min; }
unsigned int getPressMax() { return this->pressure_max; }
float getHumid() { return this->humidity; }
float getHumidMin() { return this->humidity_min; }
float getHumidMax() { return this->humidity_max; }
String formatDate() {
char strdatetime[32];
if(this->dateTime.valid) {
NTPch.printDateTime(this->dateTime);
sprintf(strdatetime,"%02i/%02i/%04i %02i:%02i\0",this->dateTime.day,this->dateTime.month,this->dateTime.year,this->dateTime.hour,this->dateTime.minute);
return String(strdatetime);
}
else {
return String("invalid date");
}
}
private:
float temperature;
float temperature_min;
float temperature_max;
float humidity;
float humidity_min;
float humidity_max;
unsigned int pressure;
unsigned int pressure_min;
unsigned int pressure_max;
};
Environment E;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Start setup");
/* SETUP WIFI */
Serial.println("Connecting to Wi-Fi");
WiFi.mode(WIFI_STA);
WiFi.begin (ssid, password);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println(".");
Serial.println("WiFi connected.");
// Start the server
server.begin();
Serial.println("Server started");
Serial.print("Use this URL : http://");
Serial.print(WiFi.localIP());
Serial.println("/");
/* SETUP TEMP SENSOR */
display.init(115200); // enable diagnostic output on Serial
Serial.println("setup dht");
dht.begin();
/* SETUP PRESSURE SENSOR */
Serial.println("setup pressure sensor");
if (!bmp.begin()) {
Serial.println(F("Could not find a valid BMP280 sensor, check wiring!"));
while (1);
}
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */
Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */
Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */
Adafruit_BMP280::FILTER_X16, /* Filtering. */
Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */
/* SETUP NTP */
NTPch.setSendInterval(1); // set interval to 3 seconds
NTPch.setRecvTimeout(1); // in seconds
/* INIT min/max to something that will be overwrited */
E = Environment();
Serial.println("setup done");
delay(1000);
ref_time = millis();
}
void loop()
{
WiFiClient client = server.available();
if ( (millis() - ref_time) >= 10000 ) {
// On attends depuis plus de 10 secondes.
Serial.println("Start Evt");
retreiveData(&E);
drawDisplay(&E);
ref_time = millis();
}
if (!client) {
return;
}
// Wait until the client sends some data
Serial.println("new client");
while(!client.available()) {
delay(1);
}
char request[256]; /* Path max length */
char xmlFeedback[256];
char delim[] = "/ ";
client.readStringUntil('\r').toCharArray(request,128);
char *ptr = strtok(request, delim);
String path[8]; /* MAXIMUM DEPTH OF 6 */
for(int i=0;ptr != NULL;i++) {
path[i] = ptr;
ptr = strtok(NULL, delim);
}
Serial.println(" Request with arguments : [" + (String)path[1] + "][" + (String)path[2] + "][" + (String)path[3] + "] ");
if(path[1].equals("GET")) {
if(path[2].equals("ENVIR")) {
sprintf(xmlFeedback,"<temperature>%.2f</temperature><humidity>%.2f</humidity><pressure>%u</pressure>",E.getTemp(),E.getHumid(),E.getPress());
client.println("<xml>" + (String)xmlFeedback + "</xml>");
}
}
/*
* PATH 1 = GET or SET
* PATH 2 = INSTRUCTION
* PATH 3 = PARAMETER
*/
else {
client.println("Message received !!!\n");
}
delay(1);
}
void retreiveData(Environment *E) {
/* RETREIVE DATA'S */
E->setDateTime(NTPch.getNTPtime(1.0, 1));
delay(400);
E->setTemp( dht.readTemperature() );
E->setHumid( dht.readHumidity() );
E->setPress( (int)round(bmp.readPressure()/100) );
E->setDateTime( NTPch.getNTPtime(1.0, 1));
Serial.println("temp : " + String(E->getTemp()));
Serial.println("humid : " + String(E->getHumid()));
Serial.println("pressure : " + String(E->getPress()));
}
void drawDisplay(Environment *E) {
/* DRAW DATA'S */
drawHead(E);
drawWidget(0,"temperature", &FreeSansBold18pt7b, String(E->getTemp(),1)+"°c" , String(E->getTempMin(),1)+"c", String(E->getTempMax(),1)+"c");
drawWidget(1,"hygrometry" , &FreeSansBold18pt7b, String(E->getHumid() ,1)+"%" , String(E->getHumidMin(),1)+"%" , String(E->getHumidMax(),1)+"%" );
drawWidget(2,"pressure" , &FreeSansBold18pt7b, String(E->getPress() )+"Pa" , String(E->getPressMin() )+"pa" , String(E->getPressMax() )+"pa" );
/*
drawWidget(3,"T min-max" , &FreeMonoBold12pt7b, "bbbb", String("0123"), String("1234"));
drawWidget(4,"H min-max" , &FreeMonoBold12pt7b, "cccc", String("0123"), String("1234"));
drawWidget(5,"F" , &FreeMonoBold12pt7b, "dddd", String("0123"), String("1234"));
drawWidget(6,"G" , &FreeMonoBold12pt7b, "eeee", String("0123"), String("1234"));
drawWidget(7,"H" , &FreeMonoBold12pt7b, "ffff", String("0123"), String("1234"));
drawWidget(8,"I" , &FreeMonoBold12pt7b, "gggg", String("0123"), String("1234"));
*/
display.update();
}
void drawHead(Environment *E) {
// Serial.println("Draw Head");
int16_t x1, y1;
uint16_t w, h;
String mydate(E->formatDate());
display.fillScreen(GxEPD_BLACK);
display.fillRect(0, HEAD_HEIGHT, 400, 2, GxEPD_BLACK);
display.setTextColor(GxEPD_WHITE);
display.setFont(&FreeMonoBold12pt7b);
display.getTextBounds(mydate, 0, 0, &x1, &y1, &w, &h);
display.setCursor( (int)((400-w)/2) , HEAD_HEIGHT-2 );
display.println(mydate);
}
void drawWidget(unsigned char widgetPos, String title, const GFXfont* f, String value, String vmin, String vmax) {
/* Header 20px height, Value 70px height */
int16_t x1, y1;
uint16_t w, h;
Serial.print("Draw Widget "); Serial.println(widgetPos);
uint16_t box_w = 130;
uint16_t box_h = 86;
uint16_t box_x = (int)(((widgetPos%3)*133)+2);
uint16_t box_y = (int)(((widgetPos/3)*(box_h+2))+HEAD_HEIGHT+1);
uint16_t cursor_y = box_y;
display.fillRect(box_x, box_y, box_w, box_h, GxEPD_WHITE);
//display.setCursor(box_x, box_y + 16 );
display.setFont(&FreeMonoBold9pt7b);
display.setTextColor(GxEPD_BLACK);
display.getTextBounds(title, 0, 0, &x1, &y1, &w, &h);
display.setCursor( (int)(box_x + (130-w)/2) , (int)(box_y + h + 0 ) );
display.print(title);
/* Display value */
display.setFont(f);
display.getTextBounds(value, 0, 0, &x1, &y1, &w, &h);
display.setCursor( (int)(box_x + (box_w-w)/2) , (int)(box_y + 40 + ((40-h)/2)) );
display.print(value);
/* Display min value */
display.setFont(&FreeMonoBold9pt7b);
display.getTextBounds(vmin, 0, 0, &x1, &y1, &w, &h);
display.setCursor( (int)(box_x + 6) , (int)(box_y + 62) );
display.print("min:" + vmin);
/* Display max value */
display.setFont(&FreeMonoBold9pt7b);
display.getTextBounds(vmax, 0, 0, &x1, &y1, &w, &h);
display.setCursor( (int)(box_x + 6) , (int)(box_y + 76) );
display.print("max:" + vmax);
//vmin
// display.updateWindow(box_x, box_y, box_w, box_h, true);
}