commit f72662c8d3ffa363ccfc4cc97bb53c6d2250c0da Author: Laurent Deleers Date: Fri Apr 10 10:47:07 2020 +0200 envirstation first commit diff --git a/DHT.cpp b/DHT.cpp new file mode 100644 index 0000000..14e1d85 --- /dev/null +++ b/DHT.cpp @@ -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; +} diff --git a/DHT.h b/DHT.h new file mode 100644 index 0000000..7e3fc34 --- /dev/null +++ b/DHT.h @@ -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 diff --git a/IMG_0001.h b/IMG_0001.h new file mode 100644 index 0000000..ea87c49 --- /dev/null +++ b/IMG_0001.h @@ -0,0 +1,103 @@ +#ifndef _GxBootExample_H_ +#define _GxBootExample_H_ + +#if defined(ESP8266) || defined(ESP32) +#include +#else +#include +#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 diff --git a/NTPtimeESP.cpp b/NTPtimeESP.cpp new file mode 100644 index 0000000..4fe9b0c --- /dev/null +++ b/NTPtimeESP.cpp @@ -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 +#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; +} diff --git a/NTPtimeESP.h b/NTPtimeESP.h new file mode 100644 index 0000000..3b85e24 --- /dev/null +++ b/NTPtimeESP.h @@ -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 +#ifdef ESP32 +#include +#else +#include +#endif +#include + +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 diff --git a/arduino-envirstation.ino b/arduino-envirstation.ino new file mode 100644 index 0000000..5c7b766 --- /dev/null +++ b/arduino-envirstation.ino @@ -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 +#include +#include +#include + +#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 +#include + +#include GxEPD_BitmapExamples + +// FreeFonts from Adafruit_GFX +#include +#include +#include +#include +#include + +#include +#include + + + +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,"%.2f%.2f%u",E.getTemp(),E.getHumid(),E.getPress()); + client.println("" + (String)xmlFeedback + ""); + } + } + /* + * 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); + } +