Supla z MQTT i LCD ILI9341

Adamo28
Posts: 150
Joined: Sun Nov 08, 2020 2:54 pm

Post

Połączyłem się z brokerem MQTT Supli poprzez bibliotekę PubSubClient, do obsługi wyświetlacza użyłem TFT_eSPI która obsługuje również dotyk. Na początku należy włączyć MQTT w integracjach na swoim koncie, zapisać dane, zwłaszcza hasło. Do podglądu skorzystałem z MQTT-Explorer, bardzo ułatwia kopiowanie wybranych topików. Wyświetlacz identyczny jak ten https://forum.arduino.cc/t/wiring-2-8-tft-spi/646151 i standardowo Wemos D1 mini.

W bibliotece TFT_eSPI należy prze edytować plik User_Setup.h w którym definiujemy jaki mamy wyświetlacz i z jakich GPIO skorzystaliśmy. U mnie wygląda to tak:

Code: Select all

#define ILI9341_DRIVER       // Generic driver for common displays

// ###### EDIT THE PIN NUMBERS IN THE LINES FOLLOWING TO SUIT YOUR ESP8266 SETUP ######

// For NodeMCU - use pin numbers in the form PIN_Dx where Dx is the NodeMCU pin designation
#define TFT_MISO  PIN_D6  // Automatically assigned with ESP8266 if not defined
#define TFT_MOSI  PIN_D7  // Automatically assigned with ESP8266 if not defined
#define TFT_SCLK  PIN_D5  // Automatically assigned with ESP8266 if not defined
#define TFT_CS    PIN_D2  // Chip select control pin D8 bylo d2
#define TFT_DC    PIN_D4  // Data Command control pin
#define TFT_RST   PIN_D0  // Reset pin (could connect to NodeMCU RST, see next line)
//#define TFT_RST  -1     // Set TFT_RST to -1 if the display RESET is connected to NodeMCU RST or 3.3V

//Piny miso, mosi i sclk równolegle - mostki z wyświetlaczem, tylko CS na osobnym GPIO
#define TOUCH_CS PIN_D3     // Chip select pin (T_CS) of touch screen

//Zakomentowałem część czcionek aby zaoszczędzić pamięci
//#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
//#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
//#define SMOOTH_FONT

//to było domyślnie
#define SPI_FREQUENCY  27000000
#define SPI_TOUCH_FREQUENCY  2500000
Sam kod wgrany do ESP:

Code: Select all

#include <LittleFS.h>
#include <TFT_eSPI.h>        
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <WiFiClientSecure.h>
#include "grafika.h"    

#define CALIBRATION_FILE "/TouchCalData1"
#define REPEAT_CAL false

TFT_eSPI tft = TFT_eSPI();   // Invoke library

char in_message[100];

// Wi-Fi settings
const char* ssid = "wifi";
const char* password = "wifi pass";

// MQTT broker settings
const char* mqttServer = "mqtt41.supla.org";
const int mqttPort = 8883;  // MQTT over SSL/TLS default port

// MQTT authentication
const char* mqttUsername = "jusernejm z mqtt supli";
const char* mqttPassword = "pasłord z mqtt supli";

// Tematy MQTT z supli
String top1="supla/91----------------------------fd/devices/54x2/channels/11587/state/temperature";//Temperatura dom 
String top2="supla/91----------------------------fd/devices/51x4/channels/10770/state/depth";//Poziom peletu
String top3="supla/91----------------------------fd/devices/51x4/channels/10765/state/temperature";//Temperatura kotla
String top4="supla/91----------------------------fd/devices/52x8/channels/11081/state/phases/1/power_active";//Moc kotła
String top5="supla/91----------------------------fd/devices/53x2/channels/11388/state/phases/1/voltage";//Napiecie sieci
String top6="supla/91----------------------------fd/devices/53x2/channels/11388/state/total_cost";//złotówki za kwh 

// Create an instance of WiFiClientSecure
WiFiClientSecure wifiClient;

// Create an instance of PubSubClient
PubSubClient mqttClient(wifiClient);

//różne zmienne do kombinowania
unsigned long PrevMillis=0;
unsigned long PrevTouchTime=0;
bool fstRun=true;
volatile float r;
int his=0;
int Scr=0;

String tempDom; 
String poziomPeletu, tmpPoziomPeletu;
String tempKotla;
String mocKotla;
String napiecie, napiecieTmp;
String koszty;

void setup()
{
  Serial.begin(115200);
 
  tft.begin();               // Initialise the display
  tft.fillScreen(0x068a); // Screen fill
  tft.setRotation(1);  // landscape
  tft.setSwapBytes(true);
  
  // Calibrate the touch screen and retrieve the scaling factors
  //touch_calibrate(); //przy pierwszym uruchomieniu
  uint16_t calData[5] = { 361, 3521, 152, 3691, 7 }; //rotation 1
  tft.setTouch(calData);
  
  tft.pushImage(77, 77, supla2w, supla2h, supla2); //zielone logo na środku
  tft.setTextColor(TFT_BLACK);  
  tft.setTextSize(1);
  tft.drawString("Connecting ...", 230, 220, 2);

  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi!");
 
  // Configure MQTT server and set SSL/TLS options
  mqttClient.setServer(mqttServer, mqttPort);
  mqttClient.setCallback(callback);
  
  // Ustawnia niezabezpieczone połączenie
  wifiClient.setInsecure();
  
  // Connect to MQTT broker
  connectToMqtt();

  delay (1000);
}

void loop()
{

 if (!mqttClient.connected()) {
    // If MQTT connection is lost, try to reconnect
    reconnect();
  }
  
  mqttClient.loop();

  uint16_t x = 0, y = 0; // To store the touch coordinates

  // Pressed will be set true is there is a valid touch on the screen
  bool pressed = tft.getTouch(&x, &y);

  // Draw a white spot at the detected coordinates
  if (pressed and (millis()-PrevTouchTime>250)) {
    Serial.print("Touch x,y = ");
    Serial.print(x);
    Serial.print(",");
    Serial.print(y);
    Serial.println("");

      //wyznacza 80pix strefy dotyku
      if (((x > 240) && (y > 1)) && ((x < 320) && (y < 240))) {
        tft.fillCircle(x, y, 20, TFT_BROWN);
        fstRun=true;// zeruje zmienną ustawijącą ekran
        Scr++;
        if (Scr>3)Scr=0;
      }

      if (((x > 1) && (y > 1)) && ((x < 80) && (y < 240))) {
        tft.fillCircle(x, y, 20, TFT_BROWN);
        fstRun=true;// zeruje zmienną ustawijącą ekran
        Scr--;
        if (Scr<0)Scr=3;
      }
  }//koniec pressed
  
  //opóżnienie aby przy dotyku zbyt szybko nie przełączało ekranów
  if (pressed){PrevTouchTime=millis();}
  
if(millis()-PrevMillis > 500){    
  PrevMillis=millis();  

  switch(Scr) {
   case 0:
    ScrZbiorczy1();
    break;
  case 1:
   ScrPoziom();
    break;
  case 2:
   ScrPiec();
    break;
  case 3:
   ScrTxt();
    break;
  default:
   ScrZbiorczy1();
  }//koniec switch 

}//koniec millis  
}//koniec loop


//--------------------------------------------------------------
// E K R A N Y
//--------------------------------------------------------------

void ScrTxt(){

if (fstRun==true){
  tft.fillScreen(0x068a); // Wyczyść ekran
  tft.pushImage(250, 5, logow, logoh, logo); 
  tft.setTextColor(TFT_BLACK,0x068a);  
  fstRun=false;
}
    tft.setTextSize(1);
    tft.drawString("Moc piec: ", 10, 90, 4);   
    tft.drawString(moc()+" W  ", 195, 90, 4);//dodatkowe spacje na końcu wymazują pozostałości przy dużej zmianie wartości...

    tft.drawString("Napięcie sieci: ", 10, 130, 4);   
    tft.drawString(napiecieCnv()+" V  ", 195, 130, 4);

    tft.drawString("Koszty energii: ", 10, 170, 4);   
    tft.drawString(koszty+"zl  ", 195, 170, 4);
}

//--------------------------------------------------------------
void ScrPiec (){
  
if (fstRun==true){
  tft.fillScreen(TFT_WHITE); 
  tft.pushImage(32, 48, piecw, piech, piec); 
  fstRun=false;
}
    tft.setTextSize(1);
    tft.setTextColor(TFT_BLACK);
    tft.drawString("Poziom pelletu % ", 10, 10, 4);   
    tft.setTextColor(TFT_RED,0xce79);//dla esp8266 sprait zjada za dużo RAMu
    tft.drawString(poziom(), 195, 150, 7);    
}
//--------------------------------------------------------------
void ScrPoziom(){
  
if (fstRun==true){
  tft.fillScreen(TFT_BLACK); 
  tft.setTextColor(TFT_RED, TFT_BLACK);
  tft.pushImage(250, 5, logow, logoh, logo, 0x068a); 
  fstRun=false;
}
  tft.setTextSize(1);
  tft.setTextColor(TFT_YELLOW);
  tft.drawString("Poziom pelletu % ", 10, 10, 4);
  tft.setTextColor(TFT_RED, TFT_BLACK);
  tft.setTextSize(2);
  tft.drawString(poziom(), 90, 80, 7);
}
//--------------------------------------------------------------
void ScrZbiorczy1(){

if (fstRun==true){
  tft.fillScreen(0x068a); // Wyczyść ekran
  tft.pushImage(250, 5, logow, logoh, logo);
  tft.setTextColor(TFT_BLACK);  
  tft.setTextSize(1);
  tft.drawString("Temperatury:", 10, 50, 4);
   tft.drawLine(200, 90, 200, 152, TFT_WHITE);
  tft.drawString("Dom:", 10, 90, 4);
   tft.drawLine(5, 118, tft.width() - 5, 118, TFT_WHITE);
  tft.drawString("Piec:", 10, 125, 4);
   tft.drawLine(5, 152, tft.width() - 5, 152, TFT_WHITE);
  fstRun=false;
}

tft.setTextColor(TFT_BLACK, 0x068a);

r=atof(tempDom.c_str());
r=round(r*10)/10;
tempDom=String(r);
tempDom.remove(tempDom.length()-1);
tft.drawString(tempDom+"`C", 230, 90, 4);

r=atof(tempKotla.c_str());
r=round(r*10)/10;
tempKotla=String(r);
tempKotla.remove(tempKotla.length()-1);
tft.drawString(tempKotla+"`C", 230, 125, 4);

}
//--------------------------------------------------------------

String poziom(){
  r=poziomPeletu.toFloat();
  r=r*100;
  //map(value, fromLow, fromHigh, toLow, toHigh)
  int l= map(r, 10 , 110, 99, 0);//dwie liczby max
  if (l >= 99) l=99;
  tmpPoziomPeletu=String(l);
  return tmpPoziomPeletu;
}
//--------------------------------------------------------------
String moc(){
r=atof(mocKotla.c_str());
mocKotla=String(r);
mocKotla.remove(mocKotla.length()-1);
return mocKotla;
}
//--------------------------------------------------------------
String napiecieCnv(){
napiecieTmp=napiecie;
napiecieTmp.remove(napiecieTmp.length()-3);
return napiecieTmp;
}
//--------------------------------------------------------------
void connectToMqtt() {
  // Loop until connected to MQTT broker
  while (!mqttClient.connected()) {
    Serial.println("Connecting to MQTT server...");
    if (mqttClient.connect("RaNd0Mbi", mqttUsername, mqttPassword)) {// !!!RaNd0Mbit -losowy ciąg 8 znakow 
      Serial.println("Connected to MQTT server!");

    //subskrybuje tematy z mqtt
     mqttClient.subscribe(top1.c_str());// Temperatura dom
     mqttClient.subscribe(top2.c_str());// Poziom pelletu
     mqttClient.subscribe(top3.c_str());// Temperatura kotła
     mqttClient.subscribe(top4.c_str());// Moc kotła
     mqttClient.subscribe(top5.c_str());// Napięcie
     mqttClient.subscribe(top6.c_str());// Koszty
    
    } else {
      Serial.print("Failed to connect to MQTT server. Retrying in 5 seconds...");
      delay(5000);
    }
  }
}
//--------------------------------------------------------------
void reconnect() {
  // Disconnect if already connected
  if (mqttClient.connected()) {
    mqttClient.disconnect();
  }
  // Attempt to reconnect
  connectToMqtt();
}
//--------------------------------------------------------------
void callback(char* topic, byte* payload, unsigned int length) {
  // Handle MQTT subscription messages, if needed
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("]\n ");

 if (strcmp(topic,top1.c_str())==0){
    payload[length] = '\0';
    tempDom=String((char*)payload);
  }
  if (strcmp(topic,top2.c_str())==0){
    payload[length] = '\0';
    poziomPeletu=String((char*)payload);
  }
  if (strcmp(topic,top3.c_str())==0){
    payload[length] = '\0';
    tempKotla=String((char*)payload);
  }
   if (strcmp(topic,top4.c_str())==0){
    payload[length] = '\0';
    mocKotla=String((char*)payload);
  }
   if (strcmp(topic,top5.c_str())==0){
    payload[length] = '\0';
    napiecie=String((char*)payload);
  }
  if (strcmp(topic,top6.c_str())==0){
    payload[length] = '\0';
    koszty=String((char*)payload);
  }
}//koniec callback


void touch_calibrate()
{
  uint16_t calData[5];
  uint8_t calDataOK = 0;

  // check file system exists
  if (!LittleFS.begin()) {
    Serial.println("Formating file system");
    LittleFS.format();
    LittleFS.begin();
  }

  // check if calibration file exists and size is correct
  if (LittleFS.exists(CALIBRATION_FILE)) {
    if (REPEAT_CAL)
    {
      // Delete if we want to re-calibrate
      LittleFS.remove(CALIBRATION_FILE);
    }
    else
    {
      File f = LittleFS.open(CALIBRATION_FILE, "r");
      if (f) {
        if (f.readBytes((char *)calData, 14) == 14)
          calDataOK = 1;
        f.close();
      }
    }
  }

  if (calDataOK && !REPEAT_CAL) {
    // calibration data valid
    tft.setTouch(calData);
  } else {
    // data not valid so recalibrate
    tft.fillScreen(TFT_BLACK);
    tft.setCursor(20, 0);
    tft.setTextFont(2);
    tft.setTextSize(1);
    tft.setTextColor(TFT_WHITE, TFT_BLACK);
    tft.println("Touch corners as indicated");
    tft.setTextFont(1);
    tft.println();

    if (REPEAT_CAL) {
      tft.setTextColor(TFT_RED, TFT_BLACK);
      tft.println("Set REPEAT_CAL to false to stop this running again!");
    }
    
    tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
  
    Serial.println(); Serial.println();
    Serial.println("// Use this calibration code in setup():");
    Serial.print("  uint16_t calData[5] = ");
    Serial.print("{ ");

    for (uint8_t i = 0; i < 5; i++)
    {
      Serial.print(calData[i]);
      if (i < 4) Serial.print(", ");
    }
    Serial.println(" };");
    Serial.print("  tft.setTouch(calData);");
    Serial.println(); Serial.println();

    tft.setTextColor(TFT_GREEN, TFT_BLACK);
    tft.println("Calibration complete!");

    // store data
    File f = LittleFS.open(CALIBRATION_FILE, "w");
    if (f) {
      f.write((const unsigned char *)calData, 14);
      f.close();
    }
  }
}//koniec calibracja dotyku

Jest jeszcze dodatkowy plik grafika.h https://drive.google.com/file/d/1GQ6_Fw ... sp=sharing z obrazkami, konwersję robiłem tą stroną: https://notisrac.github.io/FileToCArray/
Jednak należy mieć na uwadzę że pamięć ESP8266 jest mało pojemna i nie można poszaleć. Samo połaczenie z MQTT zjada dużo zasobów i nie można poszaleć z sprite-ami...

Zdaje sobię sprawę że powyższe pozostawia wiele do życzenia ale może posłużyć jak baza to dalszej zabawy, zwłaszcza że MQTT daje dostęp do każdej zmiennej jaką widzimy w apce i można sobie to dowolnie układać na ekranie, obrabiać ico tam fantazja podpowie i RAM pozwoli. Mi najbardziej zależało na wyświetleniu poziomu pelletu w zasobniku, czujnik vl53l0x z innego użądzenia w supli pokazuje tylko odległość a tak mam ładną wizualizację która sobie pewnie jeszcze jakoś ubajeruję jak tylko coś fajnego mi wpadnie na myśl :lol:

Link do filmiu z działania, kolor na żywo są fajniejsze https://drive.google.com/file/d/1Fhr0Nv ... sp=sharing Wszytskie wyświetlone wartości zmieniają się dokładnie tak jak w apce choć na krótkim filmie tego może tak nie widać...
You do not have the required permissions to view the files attached to this post.
lukasz06
Posts: 848
Joined: Sun Jul 17, 2022 6:53 pm

Post

Fajne 👍
A może z esp32, jak pamięci ma mało. Da radę?
Adamo28
Posts: 150
Joined: Sun Nov 08, 2020 2:54 pm

Post

Cześć, tak na esp32 można dużo więcej, i nie ma problemu z tym że jeden obrazek 100x100p zjada całe zasoby. Finalnie tak to wyszło, jak na Wemos D1 mini jestem całkiem zadowolony, dodałem jeszcze ikonkę lampy którą załączam oświetlenie przed domem po mqtt (zmienia stan po załączeniu) Moim zdaniem jest to dużo lepsza opcja niż linki bezpośrednie i warta uwagi, choć by przez to że responsywność jest taka sama jak aplikacji na telefonie.
You do not have the required permissions to view the files attached to this post.
Leszekbialy
Posts: 114
Joined: Fri Apr 06, 2018 9:29 pm

Post

Bardzo fajny i ciekawy projekt z potencjałem.
lukasz06
Posts: 848
Joined: Sun Jul 17, 2022 6:53 pm

Post

Elegancko, gratulacje :)
nowtech
Posts: 3
Joined: Mon May 06, 2024 4:54 pm

Post

hej, fajny projekt ale mam problemy mam wersje tego 240x320 a ty masz ta wiekszą, wiesz moze jak mam zkalibrowac albo edytowac te ustawiania bo ucina mi w połowie obrazki, i nie włacza mi sei kalibracja dotyku
Adamo28
Posts: 150
Joined: Sun Nov 08, 2020 2:54 pm

Post

Hej, zobacz tft.setRotation(1); z różnymi parametrami (1 do 3), zakładam że tam jest problem, dopóki wyświetlacz jest 320x240 powinno się zmieścić. Mam jeszcze jeden z mniejszą przekątną i ma dużo fajniejsze, bardziej nasycone kolory pomimo tej samej rozdzielczości. Co do kalibracji dotyku od komentuj funkcję

Code: Select all

// Calibrate the touch screen and retrieve the scaling factors
  touch_calibrate(); //przy pierwszym uruchomieniu
  //uint16_t calData[5] = { 361, 3521, 152, 3691, 7 }; //rotation 1
  //tft.setTouch(calData);
i jak skalibrujesz skopiuj dane z terminala, i za komentuj na nwoo aby nie wywoływać jej ponownie, choć dopóki nie wymażesz esp całkowicie, dane z pierwszej kalibracji powinny się automatycznie zachować w pamięci.
nowtech
Posts: 3
Joined: Mon May 06, 2024 4:54 pm

Post

a moge dosatc ten kod drugi ?
Adamo28
Posts: 150
Joined: Sun Nov 08, 2020 2:54 pm

Post

Hej, nie mam innego, wgrywałem to skutecznie na trzy wyświetlacze 3.2', 2.8' i i jeden mniejszy 2.4' albo coś koło tego. Wszystkie na ILI9341 i wszystkie z rozdzielczością 320x240 więc nic nie zmieniałem w układzie grafiki. Tylko przy wgraniu na esp32 trzeba piny na nowo zdefiniować i chyba odpowiednio pamięć ustawić. Podlinkuj co masz i jaki dokładnie masz problem, może z jakimś zdjęciem.

Return to “Projekty użytkowników”