Skip to content

Instantly share code, notes, and snippets.

@877dev
Last active March 24, 2021 00:23
Show Gist options
  • Save 877dev/ab7ed069d8b4cd4e2d8da4fc912b4698 to your computer and use it in GitHub Desktop.
Save 877dev/ab7ed069d8b4cd4e2d8da4fc912b4698 to your computer and use it in GitHub Desktop.
TFT weather station with BME280

Hardware

Wemos D1 Mini ESP8266
https://www.wemos.cc/en/latest/d1/d1_mini.html

TFT 2.4 inch
https://www.wemos.cc/en/latest/d1_mini_shield/tft_2_4.html

GY-BME280 sensor
https://www.14core.com/wiring-the-bme280-environmental-sensor-using-i2cspi-interface-with-microcontroller/

3D printed case
https://www.thingiverse.com/thing:4706517

3D Printer used
https://creality3d.shop/collections/ender-series-3d-printer/products/creality3d-ender-3-pro-high-precision-3d-printer

Wiring

Wemos --- Cable --- BME280
3.3V ------- RED ------ VCC
GND ---- GREEN ------ GND
D1 ----- ORANGE ----- SCL
D2 ----- YELLOW ------ SDA

https://hacksterio.s3.amazonaws.com/uploads/attachments/898003/04_fritzing_PDxsBrHoAC.png

Software

Arduino IDE
https://www.arduino.cc/en/software

Adding ESP8266 support to Arduino IDE
https://randomnerdtutorials.com/how-to-install-esp8266-board-arduino-ide/

Code used
https://gist.github.com/877dev/ab7ed069d8b4cd4e2d8da4fc912b4698#file-v003_bme280_tft_sketch-ino

How the Code Works

Start of code

Include any libraries required to enable support for all hardware
Define WiFi credentials and other variables
Define TFT screen connection pins
Configure a timer for calling the functions at regular intervals
Configure a timezone to be defined later

Setup function

Start serial monitor output, if enabled. This can be viewed via USB and plugging into PC running Arduino IDE, and opening serial monitor.
Call a function to draw the TFT start screen (when finished the program returns to the same place and continues on..) Call a function to connect to WiFi
Run code to connect to the internet NTP server, and get the current time/date for your timezone
Connect to the BME280 temperature sensor via I2C protocol, and send status to serial monitor
Setup timer to update the date/time, called every 1000ms (1second)
Setup timer to update the temp/humidity, called every 5000ms (5 seconds)

drawInitialScreen function

Start the screen, set rotation and text wrap off
Fill screen with black colour

setupWiFi function

Connect to WiFi and update TFT screen
More info via serial monitor

loop function

This function runs in a continuous loop, many times per second
timer.run() keeps track of the timers, i.e. whether to update time or sensor readings
event() keeps track of synchronising the time with the internet NTP server, default every 30mins

printTime function

This function is called every 1000ms
It prints the date across the top line, then the actual time in the middle of the screen

readSensors function

This function is called every 5000ms
First the sensor readings are read and stored into variables temp, hum and pres
The text colour is set to green
The temp and humidity are printed to the TFT screen
More info including pressure can be seen via serial monitor

Troubleshooting / info

Screen stuck on "Connect to WiFi ..."

Check in strong WiFi area
Unplug / plug back in to try again

Screen stuck on "Fetching time..."

This means it cannot connect to the online time server, possibly it is down for a short time
Check in strong WiFi area
Unplug / plug back in to try again

Stuck on "Finding sensor..."

The sensor inside cannot be found, try power cycling first
If it persists, possibly a wire has come loose inside, pull the front cover off and check
If needed unscrew the sensor compartment lid and check for loose connection
Otherwise it's likely the sensor at fault, return to son-in-law for warranty repair!

Sensor giving wrong value

The BME280 sensor produces a small amount of heat, this can affect the sensor reading
This has been corrected in code, by applying an offset
It should take around 30mins to settle down to a reasonably accurate value

/*
Written by 877dev Jan 2021
--------------------------
**** IMPORTANT: Scroll down to enter your wifi and any required offsets before flashing ****
Hardware
---------------------
Wemos D1 mini
Wemos 2.4 TFT 320×240 pixels
BME280 - I2C device found at address 0x76 !
***NOTE: make sure to change BMP280 I2C address in .h library!!
TFT info:
-----------
Lolin TFT 2.4 is 320 x 240 pixels
size 1 = 5x8, size 2 is 10x16 (double), size 3 is 20x32 (double again), and so on..
Help on drawing https://learn.adafruit.com/adafruit-gfx-graphics-library/graphics-primitives
EZTime info:
------------
https://github.com/ropg/ezTime
DEBUG_PRINTLN(myTZ.dateTime()); //gives "Friday, 31-Jul-2020 10:05:40 BST"
DEBUG_PRINT(UTC.dateTime("l, d-M-y H:i:s.v T")); //gives "Saturday, 25-Aug-18 14:32:53.282 UTC"
*/
//Debugging serial prints
#define DEBUG // <--------------Enable disable debug serial prints - comment out this line only (saves memory)
#ifdef DEBUG
#define DEBUG_PRINT(x) Serial.print (x)
#define DEBUG_PRINTLN(x) Serial.println (x)
#define DEBUG_PRINTLNHEX(x) Serial.println (x, HEX)
#else
#define DEBUG_PRINT(x)
#define DEBUG_PRINTLN(x)
#define DEBUG_PRINTLNHEX(x)
#endif
//
//Include libraries
#include <Adafruit_GFX.h> //for TFT Lolin 2.4
#include <Adafruit_ILI9341.h> //for TFT Lolin 2.4
#include <SimpleTimer.h> //for calling of function, instead of millis
#include <BME280I2C.h> //for BME280 temp sensor
#include <ezTime.h> //Online time library https://github.com/ropg/ezTime
#include <Wire.h> //for I2C communication - seems to be included in another library..
#include <ESP8266WiFi.h> // connection to WiFi and reconnect
// USER DETAILS GO IN THIS SECTION ******************************************************************
//Enter your details here, or link to your secret credentials file
#define mySSID "SSID_HERE"
#define myPASSWORD "PASSWORD_HERE"
//Setup sensors (set offsets to 0 if not sure)
BME280I2C bme; // Default : forced mode, standby time = 1000 ms. Oversampling = pressure ×1, temperature ×1, humidity ×1, filter off,
int temp_offset = -3.8; // temperature offset to allow for sensor being inside case
int hum_offset = 12; // Humidity offset to allow for sensor being inside case
int pres_offset = 18; // Pressure offset based on local pressure readings (Birmingham airport) https://www.youtube.com/watch?v=Wq-Kb7D8eQ4
//*****************************************************************************************************
//Setup TFT
#define ILI9341_CS D0 //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
#define ILI9341_DC D8 //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
#define ILI9341_RST -1 //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
#define TS_CS D3 //for D1 mini or TFT I2C Connector Shield (V1.1.0 or later)
Adafruit_ILI9341 tft = Adafruit_ILI9341(ILI9341_CS, ILI9341_DC, ILI9341_RST); //initialize display
//Setup other variables
SimpleTimer timer; //configure timer
Timezone myTZ; //EZtime timezone variable
//WiFi credentials
char ssid[] = mySSID; //Enter your WIFI Name
char pass[] = myPASSWORD; //Enter your WIFI Password
void setup() {
#ifdef DEBUG
Serial.begin(115200);
while (!Serial) {} // Wait
#endif
drawInitialScreen(); // called once to draw TFT first screen
setupWifi(); //connect to wifi
//EZTIME STUFF:
DEBUG_PRINTLN("Fetching time...");
tft.setTextSize(3);
tft.setCursor(5, 85);
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft.print("Fetching time... ");
setServer("time.cloudflare.com"); // Set NTP server (default is pool.ntp.org)
waitForSync(); // Wait for ezTime to get its time synchronized
//Set timezone
myTZ.setLocation(F("Europe/London")); // Set timezone https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
//Print current time and date
DEBUG_PRINT(F("Europe/London: "));
DEBUG_PRINTLN(myTZ.dateTime());
//
//Confirm to user time set ok
tft.setCursor(5, 120);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("Time set ok ");
delay(2000);
//Clear screen
tft.fillScreen(ILI9341_BLACK);
//
//OPTIONAL
setDebug(INFO); // Enable/disable for debug info
//setInterval (60); // Disabled defaults to 30mins, or can set to custom. Set NTP polling interval to 60 seconds. Way too often, but good for demonstration purposes.
//Start the BME280 sensor
Wire.begin(); // check needed and library needed
while (!bme.begin())
{
DEBUG_PRINTLN("Could not find BME280 sensor!");
tft.setCursor(5, 15);
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft.print("Finding sensor... ");
delay(1000);
}
// bme.chipID(); // Deprecated. See chipModel().
switch (bme.chipModel())
{
case BME280::ChipModel_BME280:
DEBUG_PRINTLN("Found BME280 sensor! Success.");
break;
case BME280::ChipModel_BMP280:
DEBUG_PRINTLN("Found BMP280 sensor! No Humidity available.");
break;
default:
DEBUG_PRINTLN("Found UNKNOWN sensor! Error!");
}
//Setup timers which call the functions
timer.setInterval(1000L, printTime); //timer to print time
delay(500); //one time delay to stagger the timers, to ease cpu processing
timer.setInterval(5000L, readSensors); //timer to read sensors
}
unsigned long drawInitialScreen() // intitial screen overlay
{
tft.begin();
tft.setRotation(3);
tft.setTextWrap(false); // added to prevent flickering of lines being wrapped and overwritten quickly = default is true
tft.fillScreen(ILI9341_BLACK);
}
void setupWifi()
{
// Attempt to connect to Wifi network:
DEBUG_PRINT("Connecting Wifi: ");
DEBUG_PRINTLN(ssid);
// Update TFT
tft.setTextSize(3);
tft.setCursor(5, 15);
tft.print("Connect to WiFi.... ");
// Set WiFi to station mode and disconnect from an AP if it was Previously
// connected
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
DEBUG_PRINT(".");
delay(500);
}
// Update TFT
tft.setCursor(5, 50);
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
tft.print("WiFi connected ");
DEBUG_PRINTLN("");
DEBUG_PRINTLN("WiFi connected");
DEBUG_PRINT("IP address: ");
DEBUG_PRINTLN(WiFi.localIP());
}
void loop()
{
timer.run(); // run SimpleTimer(s)
events(); // needed to process eztime NTP updates etc..
}
void printTime()
{
//Print Day DD-MM-YY to top line
tft.setTextSize(3);
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
tft.setCursor(5, 15);
tft.println(myTZ.dateTime(" D d-M-y "));
//Print time in large front across middle of screen
tft.setCursor(25, 80);
tft.setTextSize(9);
tft.println(myTZ.dateTime("H:i "));
}
void readSensors()
{
//Read latest sensor values
float temp = bme.temp() + temp_offset; //offset defined in main sketch
int hum = bme.hum() + hum_offset; //offset defined in main sketch
int pres = bme.pres() / 100 + pres_offset; //offset based on local pressure readings
//Set colour to green on black
tft.setTextColor(ILI9341_GREEN, ILI9341_BLACK);
//Print temperature
tft.setTextSize(5);
tft.setCursor(10, 190);
tft.print(temp,1);
tft.print("c ");
//Print humidity
tft.print(hum);
tft.print("% ");
//Optional serial prints
DEBUG_PRINTLN(myTZ.dateTime());
DEBUG_PRINTLN();
DEBUG_PRINT("BME280 sensor ");
DEBUG_PRINT("Temp: ");
DEBUG_PRINT(temp);
DEBUG_PRINT(" C, Humidity: ");
DEBUG_PRINT(hum);
DEBUG_PRINT(" %, Pressure:");
DEBUG_PRINT(pres);
DEBUG_PRINT(" bar ");
DEBUG_PRINTLN();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment