ThingPulse / esp8266-weather-station-color

ESP8266 Weather Station in Color using ILI9341 TFT 240x320 display
https://thingpulse.com/product/esp8266-wifi-color-display-kit-2-4/
MIT License
569 stars 222 forks source link

Screen brightness #24

Closed vadpol closed 4 years ago

vadpol commented 7 years ago

Hi,

I experienced some problem with screen brightness appeared due to direct connection of the display LED pin to the GPIO of ESP8266. Obviously the current of the GPIO is not enough to make a screen bright enough especially in the natural light environment. Moreover the particular GPIO15 (D8 at D1 Mini) might be overloaded and killed as a result with an excessive current consumption. Therefore I propose a simple schematics to avoid this situation and to make a screen much brighter. The only thing is that relevant code should be changed a little as now this port works in reverse logic:

// The LED pin needs to set LOW // Use this pin to save energy // Turn on the background LED pinMode(TFT_LED, OUTPUT); digitalWrite(TFT_LED, LOW);

led pin

Also in case of energy saving requirement it might be good to use an ADC (A0) pin at ESP to connect an LDR (light dependent resistor) to adjust the screen brightness in such a way that it goes brighter with natural light presence and dims out in the twilight or darkness. A calibration of LDR is needed to provide the necessary voltage readings at ADC pin and set up of the corresponding brightness levels of the screen.

squix78 commented 7 years ago

Hi Vadpol

Many thanks for your constructive feedback. Especially the LDR is certainly a nice idea to adjust screen brightness. I was under the assumption, that the display board's LED pin is just an enable pin. If I understand you correctly this is more like a power supply pin? Or did I misunderstood you?

Kind regards, Daniel

vadpol commented 7 years ago

Hi Daniel,

Thanks for being interested in my proposals! The LED pin on display is connected just to backlight LEDs and could be connected to +3,3V source via 100 Ohm series resistor just to limit the current. An ILI9341 chip has an internal LED driver but it seems that it is not used in this display. I wouldn't recommend direct connection of LED pin to power source as onboard +3,3V regulator on D1 Mini will be overloaded and overheated then. If we use a PWM signal via transistor switch instead then brightness of these LEDs might be adjusted I believe.

Best regards, Vadim

vadpol commented 7 years ago

Hi Daniel,

Sorry for being silent for a while, however I did some work on the project in the meantime, hopefully these improvements have increased the functionality of the device. Here you are:

led ldr

An additional BOM includes a few very cheap components, namely:

  1. NPN switch transistor 2N2222, 2N3904 or similar - 1 pce
  2. 100 Ohm resistor 0,25 - 1 pce
  3. 1K resistor 0,25 - 1 pce
  4. 100K resistor 0,25 - 1 pce
  5. LDR sensor (I used this one http://arduino-ua.com/docs/GL55Series.pdf) - 1 pce

As for LDR sensor the other types will also do, however some calibration of the voltages at ADC (A0) pin will be needed. As soon as D1 Mini module is used it has a voltage divider at ADC pin already, so the recommended range of the voltages at this pin is 0-3,2V (note that at bare ESP-12... module the voltage at A0 pin should be within 0-1V range!). Some experiments are needed here for any particular case, the result of mine is given above and values are in the code below. The PWM signal from D8 pin controls the transistor in such a way that it opens more frequent to make a darker screen (more 'ground' level presents at LED pin then) and closes to make a brighter screen (more +5V level presents at LED pin).

This schematics update also requires some code upgrade.

  #define TFT_LED D8 //output PWM pin for LED display brightness control 
  #define LDR_PIN A0 //analog input for LDR illuminance sensor 
  int LDRReading; // ldr data 
....
//ADC_MODE(ADC_VCC); // - comment this line as ADC pin will be externally connected
....
 void ldr(); // ambient illuminance measurement routine
....
void setup() {
....
//these lines should be commented 
//Serial.println(TFT_LED);
//pinMode(TFT_LED, OUTPUT);
//digitalWrite(TFT_LED, HIGH);    // HIGH to Turn on;

void loop() {
  if (touchController.isTouched(500)) {
    TS_Point p = touchController.getPoint();
    if (p.y < 80) {
      IS_STYLE_12HR = !IS_STYLE_12HR;
    } else {
      screen = (screen + 1) % screenCount;
    }
  } // the above is an existing piece of code
  ldr(); // LED display brightness adjustment routine depending on the ambient illuminance
  Serial.println(LDRReading); // see the measurement result on monitor 

  gfx.fillBuffer(MINI_BLACK); // existing line
....
void drawAbout() {
  gfx.fillBuffer(MINI_BLACK); // existing line
....
//drawLabelValue(11, "VCC: ", String(ESP.getVcc() / 1024.0) +"V"); // comment this line
drawLabelValue(11, "LDR value: ", String(LDRReading)); //supply voltage value indication changed to LDR measured value at A0 pin
.... 
// ambient illuminance measurement routine
void ldr() {
    LDRReading = analogRead(LDR_PIN);

    if (LDRReading < 100) {
    analogWrite(TFT_LED, 850); // the most dark screen

  } else if (LDRReading < 250) {
    analogWrite(TFT_LED, 700);

  } else if (LDRReading < 500) {
    analogWrite(TFT_LED, 500);

  } else if (LDRReading < 750) {
    analogWrite(TFT_LED, 250);

  } else if (LDRReading < 950) {
    analogWrite(TFT_LED, 100);

  } else {
    analogWrite(TFT_LED, 0); // the most bright screen
  }
}

Hope that it is clear what changes I've made. Now it is also possible to see the illuminance measurement result on 'About' screen instead of 'VCC:' line, it is changed to 'LDR value:'.

about screen with changes and ldr

//#include <ESP8266WiFi.h> // comment this line
#include <ESP8266WiFiMulti.h> //library for multi WiFi connection instead of ESP8266WiFi library 
ESP8266WiFiMulti wifiMulti; //the above WiFi library initialization
....
void setup() {
....
//adding of different WiFi access points, could be a few, the strongest one will be selected for automatic connection
  wifiMulti.addAP("your SSID1", "your PSWD1"); 
  wifiMulti.addAP("your SSID2", "your PSWD2");
  wifiMulti.addAP("your SSID3", "your PSWD3");

//waiting for connection with the strongest AP
  while (wifiMulti.run() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");  
}
....
void drawAbout() {
....
 //drawLabelValue(10, "Chip ID:", String(ESP.getChipId())); // comment this line
drawLabelValue(10, "WiFi SSID:", String(WiFi.SSID())); // shows the name of current AP connected

This works perfectly well!

the 6th screen

Hope that you enjoyed the new features of your nice project!

Best regards, Vadim

vadpol commented 7 years ago

Well, it's time to continue with indoor climate part. In order to measure all the parameters the best solution is to use a BME280 all-in-one sensor which measures:

  1. Ambient temperature
  2. Relative humidity
  3. Air pressure

As soon as display in the device is connected to D1 Mini via SPI bus we need to use a BME280 sensor with the same bus. Usually it is a violet color pcb widely present at Internet shops, here is a picture example;

image

There are many manufacturers of this kind of pcb, just be sure that it has an SPI interface, some could be with I2C only or both.

Then you need to connect the sensor to D1 Mini and power. The power pin Vcc of this board should be connected to +3,3V pin at D1 Mini, a schematic diagram is given below:

bme280 connection

Actually all the existing pins of SPI interface of the screen connection are used with only one unique pin of D0. It wasn't used in before and now we assign it to CSB signal of the sensor's pcb.

This is all you need to do with hardware, it's quite easy I believe. Here is the picture how it looks in my construction, I put the sensor into battery bay of the box I have and did two holes in the bay's cover just to provide an ambient air access to the sensor.

rear holes

sensors bay

Now we go for a software part as new hardware requires some updates of it. This will be a topic of my next post.

vadpol commented 7 years ago

Here is the software part which needs to be added/changed to make our sensor workable. As metric system is used in my country I followed this in below code. The exception is an air pressure which is shown in mm Hg, however it is easy to make it in mbars as well, just change the formula in relevant line.

//include two Adafruit libs which could be found at Github
#include <Adafruit_Sensor.h> //Adafruit sensor library
#include <Adafruit_BME280.h> //Adafruit library for BME280 sensor
...
#define BME_CS D0 //define D0 pin for BME280 sensor CSB pin connection
Adafruit_BME280 bme(BME_CS); //initiate BME280 sensor
...
float humidity = 0.; //variable to keep measured indoor humidity
float temperature = 0.; //variable to keep measured indoor temperature
...
//declare routine to draw indoor data screen
void drawIndoorData();
....
//increase the number of info screens to 6 iso original 5
int screenCount = 6; // change 5 to 6 in this line
...
void setup() {
....
bme.begin(); //start BME sensor
....
}
void loop() {
....
//existing code
  drawCurrentWeather();
    drawAstronomy();
  } else if (screen == 1) {
    drawCurrentWeatherDetail();
  } else if (screen == 2) {
    drawForecastTable(0);
  } else if (screen == 3) {
    drawForecastTable(6);
  } else if (screen == 4) {
    drawAbout();
//add the below two lines here
  } else if (screen == 5) { //indoor data screen added
    drawIndoorData();
//existing code below
  }
  gfx.commit();
....
}
....
// additional screen draws current indoor conditions
void drawIndoorData() {
  humidity = bme.readHumidity();
  temperature = bme.readTemperature()-2.0;//here you may add or deduct the temperature calibration factor, it is 2.0 in my case 
  gfx.setFont(ArialRoundedMTBold_14);
  gfx.setTextAlignment(TEXT_ALIGN_CENTER);
  gfx.setColor(MINI_WHITE);
  gfx.drawString(120, 2, "Indoor Conditions");
  gfx.setTextAlignment(TEXT_ALIGN_LEFT);
  gfx.drawString(0, 24, "Temperature");
  gfx.setFont(ArialRoundedMTBold_36);
  gfx.setColor(MINI_YELLOW);
  gfx.setTextAlignment(TEXT_ALIGN_CENTER);
  gfx.drawString(120, 46, String(temperature) + "°C"); //value in Celsius degrees
  gfx.setFont(ArialRoundedMTBold_14);
  gfx.setTextAlignment(TEXT_ALIGN_LEFT);
  gfx.setColor(MINI_WHITE);
  gfx.drawString(0, 99, "Humidity");
  gfx.setFont(ArialRoundedMTBold_36);
  gfx.setColor(MINI_BLUE);
  gfx.setTextAlignment(TEXT_ALIGN_CENTER);
  gfx.drawString(120, 121, String(humidity) + "%");
  gfx.setFont(ArialRoundedMTBold_14);
  gfx.setTextAlignment(TEXT_ALIGN_LEFT);
  gfx.setColor(MINI_WHITE);
  gfx.drawString(0, 174, "Air pressure");
  gfx.setFont(ArialRoundedMTBold_36);
  gfx.setColor(MINI_WHITE);
  gfx.setTextAlignment(TEXT_ALIGN_CENTER);
  gfx.drawString(120, 196, String(bme.readPressure()*0.007501) + " mm");//remove the factor if value in mbars is needed
  gfx.setFont(ArialRoundedMTBold_14);
  gfx.setTextAlignment(TEXT_ALIGN_LEFT);
  gfx.setColor(MINI_WHITE);
  gfx.drawString(0, 249, "Approximate altitude");
  gfx.setFont(ArialRoundedMTBold_36);
  gfx.setColor(MINI_YELLOW);
  gfx.setTextAlignment(TEXT_ALIGN_CENTER);
  gfx.drawString(120, 271, String(bme.readAltitude(1013.25)) + " m"); //change the factor in brackets depending on sea level elevation of your place, normally available in Internet
}

Actually this is all, the appearance of the new screen is shown in my previous posts, hope that weather station is more flexible and functional now!

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.