Viewable With Any Browser

STATS

Todays date:
Tuesday 14th of May 2024 03:45:08 PM

You are visitor

29623


Your IP address is 3.144.134.107


Page last updated
17 April 2019

The Greenfinger Project

TFT    First off, You will need to connect the TFT screen to the Wemos D1 Mini.
Instructions for this can be found at:


www.so-now.com/tft.php

When your TFT and Wemos are up and running, we need to connect the DHT 11.



DHT 11 Sensor

DHT 11    As we mentioned earlier, we have a spare DHT 11 temperature and humidity sensor for this project.

It needs to be connected to the Wemos D1 Mini in the following way:

(pins are numbered 1 to 4, left to right).

DHT 11 Pin DHT Pin Wemos D1
Number Function Pin Name
1 VCC 3.3v
2 Data D4
3 NC Not Connected
4 GND Circuit Ground


When that is all connected up, you will need to use the library manager in the Arduin0 IDE to make sure you have the DHT libraries installed.

Then, it's all down to the code.....

Time to code

Arduino     OK. Example code below.

Click here to download

Note this is the code we use for testing. We have a MQTTT server running. You may want to remove the MQTT/Wifi parts.

Use the serial monitor for some debugging info.



 /*
 greenhouse sensor/control.
 Target: Wemos D1 mini.
 Support: 320 X 240 tft screen.
 
 So-now.com v1.0, 19-04-2019
 
 Updated by Bodmer for variable meter size
 */

// Define meter size as 1 for tft.rotation(0) or 1.3333 for tft.rotation(1)
//#define M_SIZE 1.3333
#define M_SIZE 1

#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>>
#include <DHTesp.h>>
#include <ESP8266WiFi.h>>
#include <PubSubClient.h>>

#ifdef ESP32
#pragma message(THIS EXAMPLE IS FOR ESP8266 ONLY!)
#error Select ESP8266 board.
#endif

DHTesp dht;

TFT_eSPI tft = TFT_eSPI();       // Invoke custom library

WiFiClient espClient;

PubSubClient client(espClient);

#define TFT_GREY 0x5AEB

uint8_t gTemperature = 10;

float ltx = 0;    // Saved x coord of bottom of needle
uint16_t osx = M_SIZE*120, osy = M_SIZE*120; // Saved x & y coords
uint32_t updateScreenTime = 0;       // time for next update
uint32_t updateMQTTTime = 0;       // time for next update

int old_analog =  -999; // Value last displayed

uint8_t old humidity -999;
uint8_t old temperature = 0;

uint8_t giSW1 = 0b00000001;
uint8_t giSW2 = 0b00000010;

//SSID of your network
const char* ssid = "looking"; //SSID of your Wi-Fi router
const char* pass = "sexy"; //Password of your Wi-Fi router

const char* MQTTserver = "192.168.0.51";
const char* MQTTClientName = "greenhouse";
const char* MQTTuid = "imtoosexy";
const char* MQTTpwd = "formyboots";

char charBuffer[128];
uint8_t iBufferCount = 0;


void setup(void) {
  tft.init();
  tft.setRotation(1);
  Serial.begin(9600); // For debug
  tft.fillScreen(TFT_BLACK);

  drawHumidityMeter(); // Draw analogue meter
  drawThermometer();
  
  updateScreenTime = millis(); // Next update time
  updateMQTTTime = millis(); // Next update time

  dht.setup(D4, DHTesp::DHT11);

  //set up wifi connection
  // Connect to Wi-Fi network
  Serial.println();
  Serial.println();
  Serial.print("Connecting to...");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA); //We don't want the ESP to act as an AP
  WiFi.begin(ssid, pass);
  uint8_t trycount = 0;
  
  while (WiFi.status() != WL_CONNECTED)
    {
    delay(500);
    Serial.print(".");
    trycount ++;
    if(trycount > 9)
      {
      trycount = 0;
      Serial.println("");
      }
    }
    
  Serial.println("");
  Serial.println("Wi-Fi connected.");

  Serial.print("ip_address : ");
  Serial.println(WiFi.localIP());
  Serial.print("MQTT Client Name : ");
  Serial.println(MQTTClientName);

  //connect to MQTT server
  client.setServer(MQTTserver, 1883);

  //attempt initial connection
  mqtt_connect();
 
}


void loop() {
  uint8_t humidity;
  uint8_t temperature;

  if (!client.connected())
    {
    Serial.println("[Disconnected]");
    mqtt_connect();
    }
    
  client.loop();

  if (updateScreenTime <= millis())
    {
    updateScreenTime = millis() + 10000; // Update screen values every 10 seconds
 
    humidity = dht.getHumidity();
    temperature = dht.getTemperature();

    plotHumidity((int)humidity, 0); // It takes between 2 and 12ms to replot the needle with zero delay

    plotTemperature(temperature);
    }

  if (updateMQTTTime <= millis())
    {
    updateMQTTTime = millis() + 600000; // Update MQTT values every 10 minutes

    humidity = dht.getHumidity();
    temperature = dht.getTemperature();

    String line = "{\"iUID\":77, ";
    line = line + "\"fTemp\":";
    line = line + temperature + ", \"fHum\":";
    line = line + humidity + ", \"SW1\":";
    line = line + giSW1 + ", \"SW2\":";
    line = line + giSW2 + "}";
    
    client.publish("response", (char*)line.c_str());
    Serial.println((char*)line.c_str());

    }

delay(2000);
}


// #########################################################################
//  Draw the Humidity meter
// #########################################################################
void drawHumidityMeter()
  {
  // Meter outline
  tft.fillRect(0, 0, M_SIZE*239, M_SIZE*126, TFT_GREY);
  tft.fillRect(5, 3, M_SIZE*230, M_SIZE*119, TFT_WHITE);

  tft.setTextColor(TFT_BLACK);  // Text colour

  // Draw ticks every 5 degrees from -50 to +50 degrees (100 deg. FSD swing)
  for (int i = -50; i < 51; i += 5) {
    // Long scale tick length
    int tl = 15;

    // Coodinates of tick to draw
    float sx = cos((i - 90) * 0.0174532925);
    float sy = sin((i - 90) * 0.0174532925);
    uint16_t x0 = sx * (M_SIZE*100 + tl) + M_SIZE*120;
    uint16_t y0 = sy * (M_SIZE*100 + tl) + M_SIZE*140;
    uint16_t x1 = sx * M_SIZE*100 + M_SIZE*120;
    uint16_t y1 = sy * M_SIZE*100 + M_SIZE*140;

    // Coordinates of next tick for zone fill
    float sx2 = cos((i + 5 - 90) * 0.0174532925);
    float sy2 = sin((i + 5 - 90) * 0.0174532925);
    int x2 = sx2 * (M_SIZE*100 + tl) + M_SIZE*120;
    int y2 = sy2 * (M_SIZE*100 + tl) + M_SIZE*140;
    int x3 = sx2 * M_SIZE*100 + M_SIZE*120;
    int y3 = sy2 * M_SIZE*100 + M_SIZE*140;

    // Cold zone limits
    if (i >= -50 && i < -5) {
      tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_CYAN);
      tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_CYAN);
    }

    // warning zone limits
    if (i >= -5 && i < 5) {
      tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_ORANGE);
      tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_ORANGE);
    }

    // Green zone limits
    if (i >= 5 && i < 15) {
      tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_GREEN);
      tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_GREEN);
    }

    // warning zone limits
    if (i >= 15 && i < 25) {
      tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_ORANGE);
      tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_ORANGE);
    }

    // Hot zone limits
    if (i >= 25 && i < 50) {
      tft.fillTriangle(x0, y0, x1, y1, x2, y2, TFT_RED);
      tft.fillTriangle(x1, y1, x2, y2, x3, y3, TFT_RED);
    }

    // Short scale tick length
    if (i % 25 != 0) tl = 8;

    // Recalculate coords incase tick length changed
    x0 = sx * (M_SIZE*100 + tl) + M_SIZE*120;
    y0 = sy * (M_SIZE*100 + tl) + M_SIZE*140;
    x1 = sx * M_SIZE*100 + M_SIZE*120;
    y1 = sy * M_SIZE*100 + M_SIZE*140;

    // Draw tick
    tft.drawLine(x0, y0, x1, y1, TFT_BLACK);

    // Check if labels should be drawn, with position tweaks
    if (i % 25 == 0) {
      // Calculate label positions
      x0 = sx * (M_SIZE*100 + tl + 10) + M_SIZE*120;
      y0 = sy * (M_SIZE*100 + tl + 10) + M_SIZE*140;
      switch (i / 25) {
        case -2: tft.drawCentreString("0", x0, y0 - 12, 2); break;
        case -1: tft.drawCentreString("25", x0, y0 - 9, 2); break;
        case 0: tft.drawCentreString("50", x0, y0 - 7, 2); break;
        case 1: tft.drawCentreString("75", x0, y0 - 9, 2); break;
        case 2: tft.drawCentreString("100", x0, y0 - 12, 2); break;
      }
    }

    // Now draw the arc of the scale
    sx = cos((i + 5 - 90) * 0.0174532925);
    sy = sin((i + 5 - 90) * 0.0174532925);
    x0 = sx * M_SIZE*100 + M_SIZE*120;
    y0 = sy * M_SIZE*100 + M_SIZE*140;
    // Draw scale arc, don't draw the last part
    if (i < 50) tft.drawLine(x0, y0, x1, y1, TFT_BLACK);
  }

  tft.drawString("%RH", M_SIZE*(5 + 230 - 40), M_SIZE*(119 - 20), 2); // Units at bottom right
  tft.drawCentreString("%RH", M_SIZE*120, M_SIZE*70, 4); // Comment out to avoid font 4
  tft.drawRect(5, 3, M_SIZE*230, M_SIZE*119, TFT_BLACK); // Draw bezel line

  plotHumidity(0, 0); // Put meter needle at 0
}

// #########################################################################
// Update needle position
// This function is blocking while needle moves, time depends on ms_delay
// 10ms minimises needle flicker if text is drawn within needle sweep area
// Smaller values OK if text not in sweep area, zero for instant movement but
// does not look realistic... (note: 100 increments for full scale deflection)
// #########################################################################
void plotHumidity(int value, byte ms_delay)
{
  tft.setTextColor(TFT_BLACK, TFT_WHITE);
  char buf[8]; dtostrf(value, 4, 0, buf);
  tft.drawRightString(buf, M_SIZE*40, M_SIZE*(119 - 20), 2);

  if (value < -10) value = -10; // Limit value to emulate needle end stops
  if (value > 110) value = 110;

  // Move the needle until new value reached
  while (!(value == old_analog)) {
    if (old_analog < value) old_analog++;
    else old_analog--;

    if (ms_delay == 0) old_analog = value; // Update immediately if delay is 0

    float sdeg = map(old_analog, -10, 110, -150, -30); // Map value to angle
    // Calcualte tip of needle coords
    float sx = cos(sdeg * 0.0174532925);
    float sy = sin(sdeg * 0.0174532925);

    // Calculate x delta of needle start (does not start at pivot point)
    float tx = tan((sdeg + 90) * 0.0174532925);

    // Erase old needle image
    tft.drawLine(M_SIZE*(120 + 20 * ltx - 1), M_SIZE*(140 - 20), osx - 1, osy, TFT_WHITE);
    tft.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_WHITE);
    tft.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_WHITE);

    // Re-plot text under needle
    tft.setTextColor(TFT_BLACK);
    tft.drawCentreString("%RH", M_SIZE*120, M_SIZE*70, 4); // // Comment out to avoid font 4

    // Store new needle end coords for next erase
    ltx = tx;
    osx = M_SIZE*(sx * 98 + 120);
    osy = M_SIZE*(sy * 98 + 140);

    // Draw the needle in the new postion, magenta makes needle a bit bolder
    // draws 3 lines to thicken needle
    tft.drawLine(M_SIZE*(120 + 20 * ltx - 1), M_SIZE*(140 - 20), osx - 1, osy, TFT_RED);
    tft.drawLine(M_SIZE*(120 + 20 * ltx), M_SIZE*(140 - 20), osx, osy, TFT_MAGENTA);
    tft.drawLine(M_SIZE*(120 + 20 * ltx + 1), M_SIZE*(140 - 20), osx + 1, osy, TFT_RED);

    // Slow needle down slightly as it approaches new postion
    if (abs(old_analog - value) < 10) ms_delay += ms_delay / 5;

    // Wait before next update
    delay(ms_delay);
  }
}


//void drawThermometer(int xPos, int yPos)
void drawThermometer()
{
  //force position for testing
  int xPos = 240;
  int yPos = 0;
  
  // Thermometer outline
  tft.fillRect(xPos, yPos, 80, 240, TFT_GREY);
  tft.fillRect(xPos + 5, yPos + 3, 70, 232, TFT_WHITE);

  //colour scale
  tft.fillRect(xPos + 10, yPos + 30, 35, 40, TFT_RED);
  tft.fillRect(xPos + 10, yPos + 70, 35, 10, TFT_ORANGE);
  tft.fillRect(xPos + 10, yPos + 80, 35, 30, TFT_GREEN);
  tft.fillRect(xPos + 10, yPos + 110, 35, 10, TFT_ORANGE);
  tft.fillRect(xPos + 10, yPos + 120, 35, 30, TFT_CYAN);

  // Thermometer body
  tft.fillCircle(xPos + 28, yPos + 20, 8, TFT_BLACK);      //top dome outline
  tft.fillRect(xPos + 20, yPos + 20, 17, 140, TFT_BLACK);   //neck outline
  tft.fillCircle(xPos + 28, yPos + 170, 18, TFT_BLACK);     //bottom bulb outline
  tft.fillRect(xPos + 20, yPos + 20, 17, 140, TFT_BLACK);   //neck outline
  
  
  //Thermometer scale
  tft.drawLine(xPos + 10, yPos + 30, xPos + 45, yPos + 30, TFT_BLACK);        //
  tft.drawLine(xPos + 30, yPos + 40, xPos + 50, yPos + 40, TFT_BLACK);        // 50
  tft.drawLine(xPos + 30, yPos + 50, xPos + 45, yPos + 50, TFT_BLACK);        // 
  tft.drawLine(xPos + 30, yPos + 60, xPos + 50, yPos + 60, TFT_BLACK);        // 40
  tft.drawLine(xPos + 30, yPos + 70, xPos + 45, yPos + 70, TFT_BLACK);        // 
  tft.drawLine(xPos + 10, yPos + 80, xPos + 50, yPos + 80, TFT_BLACK);        // 30
  tft.drawLine(xPos + 30, yPos + 90, xPos + 45, yPos + 90, TFT_BLACK);        // 
  tft.drawLine(xPos + 30, yPos + 100, xPos + 50, yPos + 100, TFT_BLACK);      // 20
  tft.drawLine(xPos + 10, yPos + 110, xPos + 45, yPos + 110, TFT_BLACK);      // 
  tft.drawLine(xPos + 10, yPos + 120, xPos + 50, yPos + 120, TFT_BLACK);      // 10
  tft.drawLine(xPos + 30, yPos + 130, xPos + 45, yPos + 130, TFT_BLACK);      // 
  tft.drawLine(xPos + 30, yPos + 140, xPos + 50, yPos + 140, TFT_BLACK);      // 0
  tft.drawLine(xPos + 10, yPos + 150, xPos + 45, yPos + 150, TFT_BLACK);      //

  //draw graticule text
  tft.drawCentreString("50", xPos + 60, yPos + 35, 2);
  tft.drawCentreString("40", xPos + 60, yPos + 55, 2);
  tft.drawCentreString("30", xPos + 60, yPos + 75, 2);
  tft.drawCentreString("20", xPos + 60, yPos + 95, 2);
  tft.drawCentreString("10", xPos + 60, yPos + 115, 2);
  tft.drawCentreString("0", xPos + 60, yPos + 135, 2);

  tft.fillCircle(xPos + 28, yPos + 20, 6, TFT_WHITE);       //hollow top dome
  tft.fillRect(xPos + 22, yPos + 20, 13, 150, TFT_WHITE);   //hollow neck
  tft.fillCircle(xPos + 28, 170, 16, TFT_WHITE);             //hollow bulb
  tft.fillCircle(xPos + 28, 170, 14, TFT_BLUE);             //full bulb
//  tft.fillRect(xPos + 25, yPos + 140, 7, 30, TFT_BLUE);     //semi filled

  tft.setTextColor(TFT_BLACK);
  tft.drawCircle(xPos + 30, 210, 4, TFT_BLACK);              //degree symbol
  tft.drawCircle(xPos + 30, 210, 3, TFT_BLACK);               //degree symbol
  tft.drawCentreString("C", xPos + 50, yPos + 205, 4); // // Comment out to avoid font 4
  
}


void plotTemperature(int value)
{
  //screen position
  int xPos = 240;
  int yPos = 0;
  int iNewValue = value;

  iNewValue = (value * 2);

  tft.fillRect(xPos + 25, yPos + 20, 7, yPos + 120 - iNewValue, TFT_WHITE);
  tft.fillRect(xPos + 25, yPos + 140 - iNewValue, 7, iNewValue + 30, TFT_BLUE);

  
  tft.setTextColor(TFT_WHITE, TFT_BLACK);  // Text colour
  
  char buf[8]; dtostrf(value, 4, 0, buf);
  tft.drawCentreString(buf,120,180,4);
}


void mqtt_connect()
{
// Loop until we're reconnected
while (!client.connected())
  {
  // Attempt to connect
  if(client.connect(MQTTClientName, MQTTuid, MQTTpwd))
    {
    Serial.println("[Connected]");
    }
  else
    {
    Serial.print("[failed, rc=");
    Serial.print(client.state());
    Serial.println("]");
//    // Wait 5 seconds before retrying
    delay(5000);
    }
  }
}
                   
                    

Enjoy