Web radio - mise à jour écran décallée

Bonjour à tous,

J'ai modifié un sketch de Webradio de michelep afin d'y adjoindre deux encodeur rotatifs et un écran TFT1.8 SPI 128x160.

Afin de ne pas avoir l'écran qui se mets à jour toutes les secondes avec la boucle Millis dans la Loop et éviter le scintillement de l'écran, je souhaite Mettre à jour l'écran que quand je change de station, je modifie le volume ou, plus tard, le titre de l'air diffusé change.

Ca fonctionne parfaitement lorsque je modifie le volume mais lorsque je change de station, l'affichage de la sation ne change pas immédiatement. Il faut que je modifie le volume pour que la nouvelle station s'affiche.

A chaque modification de station par l'encodeur rotatif, le flux radio change mais l'affichage a une station de retard.

Je cherche depuis plusieurs jours!
j'ai ajouté des updateDisplay() un peu partout mais rien ne change!

Peut-être pourrez vous m'aider ?

Merci.

Ci dessous le programme modifié :

// ESP32 WebRadio
//
// Released under GNU General Public License v3.0
//
// Compile with DOIT ESP32 WebKit v1 and burn /data directory into SPIFFS (1M)

//https://github.com/michelep/ESP32_WebRadio
//
//
//  Display 160x128
//  +-------------------------------------------+ _yHeader=0
//  | Header                                    |       _hHeader=20px
//  +-------------------------------------------+ _yName=20
//  |                                           |
//  | Logo                   StationName        |       _hName=44px
//  |                                           |
//  +-------------------------------------------+ _yTitle=68
//  |                                           |
//  |              StreamTitle                  |       _hTitle=44px
//  |                                           |
//  +-------------------------------------------+ _yFooter=108
//  | Footer                                    |       _hFooter=20px
//  +-------------------------------------------+ 128
//                                             160

#include <ESP32Encoder.h>
ESP32Encoder encoder;
ESP32Encoder encoder2;

int32_t countVol = encoder.getCount();
int32_t oldCountVol;
int32_t countStreams = encoder2.getCount();
int32_t oldCountStreams;

#define __DEBUG__

// Firmware data
const char BUILD[] = __DATE__ " " __TIME__;
#define FW_NAME         "esp32-webradio"
#define FW_VERSION      "0.0.6"

#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiClient.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include "time.h"

// Audio to PCM5102 DAC
// "https://github.com/schreibfaul1/ESP32-audioI2S"
#include "Audio.h"

#define I2S_DOUT      26
#define I2S_BCLK      27
#define I2S_LRC       25

#define MAX_VOLUME 21
#define MIN_VOLUME 0

String streamTitle;
String oldStreamTitle;

Audio audio;

// Control buttons
#define BUTTONS_NUM 3
const int BUTTONS_PINS[BUTTONS_NUM] = {34, 35, 32};

// Icons
#define audio_icon_width 5
#define audio_icon_height 10
static const uint8_t PROGMEM audio_icon_bits[] = {
  0x10, 0x18, 0x1c, 0x1f, 0x1f, 0x1f, 0x1f, 0x1c, 0x18, 0x10
};

#define wifi_icon_width 8
#define wifi_icon_height 8
static const uint8_t PROGMEM wifi_icon_bits[] = {
  0x00, 0x1f, 0x20, 0x4e, 0x50, 0x56, 0x56, 0x40
};


// LCD
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <Fonts/Org_01.h>

#define TFT_DC         2
#define TFT_RST        4 // Or set to -1 and connect to Arduino RESET pin  
#define TFT_CS        15

// Color definitions for the TFT screen (if used)
// TFT has bits 6 bits (0..5) for RED, 6 bits (6..11) for GREEN and 4 bits (12..15) for BLUE.
#define BLACK   ST7735_BLACK
#define BLUE    ST7735_BLUE
#define RED     ST7735_RED
#define GREEN   ST7735_GREEN
#define CYAN    GREEN | BLUE
#define MAGENTA RED | BLUE
#define YELLOW  RED | GREEN
#define WHITE   RED | BLUE | GREEN


//#define DISPLAY_BL 27
//#define DISPLAY_BL_DEFAULT 100 // Backlight LEDs PWM duty-cycle

// Serial clock out (SCLK), Serial data out (DIN), Data/Command select (D/C), LCD chip select (CS), LCD reset (RST)
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

// WebServer
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>

AsyncWebServer server(80);

// ArduinoJson
// https://arduinojson.org/
#include <ArduinoJson.h>

// File System
#include <FS.h>
#include "SPIFFS.h"

// Format SPIFFS if mount failed
#define FORMAT_SPIFFS_IF_FAILED 1

#include "soc/soc.h" //disable brownour problems
#include "soc/rtc_cntl_reg.h" //disable brownour problems

// Config
struct Config {
  // WiFi config
  char wifi_essid[24];
  //  char wifi_password[16];
  char wifi_password[24];
  // NTP Config
  char ntp_server[16];
  int8_t ntp_timezone;
  // Host config
  char hostname[16];
  bool ota_enable;
  char ota_password[8];
  // Radio podcast
  int8_t stream_id;
  int8_t stream_count;
  char stream_url[64];
  int8_t volume;
  // Display config
  int8_t contrast;
};

#define CONFIG_FILE "/config.json"
File configFile;
Config config; // Global config object

// JSON file contains an array of streams URL
#define DB_FILE "/streams.json"

static int last; // millis counter
bool streamIsValid = false;
bool streamChanged = true;
bool streamIsPaused = false;
bool streamIsPlaying = false;
bool deviceIsOTA = false;

DynamicJsonDocument env(256);

/*
   Esternal procedures definition
*/
bool loadConfigFile();
void initWebServer();
void printStreamsDB();
bool getStreamURL(uint8_t);

// ************************************
// DEBUG_PRINT() and DEBUG_PRINTLN()
//
// send message to Serial
// ************************************
void DEBUG_PRINT(String message) {
#ifdef __DEBUG__
  Serial.print(message);
#endif
}

void DEBUG_PRINTLN(String message) {
#ifdef __DEBUG__
  Serial.println(message);
#endif
}

// ************************************
// connectToWifi()
//
// connect to configured WiFi network
// ************************************
bool connectToWifi() {
  uint8_t timeout = 0;

  if (strlen(config.wifi_essid) > 0) {
    DEBUG_PRINT("[INIT] Connecting to " + String(config.wifi_essid) + "...");

    WiFi.begin(config.wifi_essid, config.wifi_password);

    while ((WiFi.status() != WL_CONNECTED) && (timeout < 10)) {
      delay(250);
      timeout++;
    }
    if (WiFi.status() == WL_CONNECTED) {
      DEBUG_PRINTLN("CONNECTED. IP:" + WiFi.localIP().toString() + " GW:" + WiFi.gatewayIP().toString());

      env["ip"] = WiFi.localIP().toString();
      if (MDNS.begin(config.hostname)) {
        DEBUG_PRINTLN("[INIT] MDNS responder started: " + String(config.hostname));
        // Add service to MDNS-SD
        MDNS.addService("http", "tcp", 80);
      }

      configTime(config.ntp_timezone * 3600, config.ntp_timezone * 3600, config.ntp_server);

      return true;
    } else {
      DEBUG_PRINTLN("[ERROR] Failed to connect to WiFi");
      return false;
    }
  } else {
    DEBUG_PRINTLN("[ERROR] Please configure Wifi");
    return false;
  }
}

//
// high priority audioTask on CORE0
//
void audioTask(void *pvParameters) {
  while (1) {
    if (!streamIsPaused) {
      if (streamChanged) {
        playStream(config.stream_id);
        streamChanged = false;
        updateDisplay();
      }
      audio.loop();
      streamIsPlaying = audio.isRunning();
    }
  }
}

//
// SETUP()
//
void setup() {
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();
  Serial.println();
  Serial.println();
  Serial.print("ESP32 SDK: ");
  Serial.println(ESP.getSdkVersion());
  Serial.println();
  Serial.print(FW_NAME);
  Serial.print(" ");
  Serial.print(FW_VERSION);
  Serial.print(" ");
  Serial.println(BUILD);
  delay(1000);

  ESP32Encoder::useInternalWeakPullResistors = UP;
  encoder.attachSingleEdge (35, 34);
  encoder2.attachSingleEdge (17, 16);
  encoder.setCount(2);
  encoder2.setCount(0);
  oldCountStreams = -1;

  // Initialize SPIFFS
  DEBUG_PRINT("[INIT] Initializing SPIFFS...");
  if (!SPIFFS.begin()) {
    DEBUG_PRINTLN("[ERROR] SPIFFS mount failed. Try formatting...");
    if (SPIFFS.format()) {
      DEBUG_PRINTLN("[INIT] SPIFFS initialized successfully");
    } else {
      DEBUG_PRINTLN("[FATAL] SPIFFS fatal error");
      ESP.restart();
    }
  } else {
    DEBUG_PRINTLN("OK");
  }

  // Initialize buttons control board
  for (int i = 0; i < BUTTONS_NUM; i++) {
    pinMode(BUTTONS_PINS[i], INPUT);
  }

  // Load configuration
  loadConfigFile();

  // Initialize DISPLAY
  DEBUG_PRINT("[INIT] Initialize display...");

  tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab
  Serial.println("ST7735 initialised");

  // Connect to WiFi network
  connectToWifi();

  // Initialize Web Server
  initWebServer();

  // Initialize OTA
  if (config.ota_enable) {
    DEBUG_PRINT("[INIT] Initialize OTA...");
    // ArduinoOTA.setPort(3232);
    ArduinoOTA.setHostname(config.hostname);

    ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";
      Serial.println("Start updating " + type);
      deviceIsOTA = true;
      streamIsPaused = true;
    })
    .onEnd([]() {
      Serial.println("\nEnd");
      deviceIsOTA = false;
      streamIsPaused = false;
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
      tft.setCursor(8, 24);
      tft.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
      deviceIsOTA = false;
    });
    ArduinoOTA.begin();
    DEBUG_PRINTLN("OK");
  }
  //
  DEBUG_PRINT("[INIT] Initialize audio...");

  env["volume"] = config.volume;

  audio.setPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);
  audio.setVolume(env["volume"].as<int>());
  DEBUG_PRINTLN("OK");

  //
  printStreamsDB();

  // let's fly!
  DEBUG_PRINTLN("[INIT] Ready: let's fly!");
  env["status"] = "Ready";

  // Launch audioTask on CORE0 with high priority
  disableCore0WDT(); // Disable watchdog on CORE0
  xTaskCreatePinnedToCore(
    audioTask,   /* Function to implement the task */
    "audioTask", /* Name of the task */
    10000,      /* Stack size in words */
    NULL,       /* Task input parameter */
    15,          /* Priority of the task */
    NULL,       /* Task handle. */
    0);  /* Core where the task should run */
    
    updateDisplay();
}

String zeroPadding(int digit) {
  if (digit < 10) {
    return String("0" + String(digit));
  }
  return String(digit);
}

void updateDisplay() {

  uint16_t rotation = 1;
  tft.setRotation(rotation);
  // Graphic display of 128x160 pixels
  tft.fillScreen(ST7735_BLACK);
  tft.setTextSize(3);

  // If there's an OTA running...
  if (deviceIsOTA) {
    tft.setCursor(2, 16);
    tft.print("Updating.Please wait!");
    //display.display();
    return;
  }

  tft.setTextSize(1);
  // Top red BAR with WiFi signal power
  tft.drawXBitmap(0, 0, wifi_icon_bits, wifi_icon_width, wifi_icon_height, 0xff);
  tft.fillRect(10, 0, 84, 8, RED);
  tft.setTextColor(WHITE, BLACK);
  tft.setCursor(100, 0);
  tft.println(String(WiFi.RSSI()) + "dB");

  if (streamIsPlaying) {

    tft.setTextColor(YELLOW);
    tft.setCursor(4, 20);
    tft.println("Station :");

    tft.setTextColor (CYAN);
    tft.setCursor(4, 35);
    tft.println(env["stream_station"].as<String>());

    tft.setTextColor(YELLOW);
    tft.setCursor(4, 55);
    tft.println("Titre :");

    tft.setTextColor (CYAN);
    tft.setCursor(4, 70);
    tft.println(env["stream_title"].as<String>());

  } else {
    tft.setCursor(4, 80);
    if (streamIsPaused) {
      tft.println("*** PAUSE ***");
    } else {
      tft.println("Loading...");
    }
  }
  // Draw volume bar
  tft.drawXBitmap(2, 115, audio_icon_bits, audio_icon_width, audio_icon_height, 0xff);
  uint8_t volume = map(config.volume, 0, 22, 0, 72);
  tft.drawRect(10, 115, 72, 10, RED);
  tft.fillRect(10, 115, volume, 10, RED);
}

bool playStream(uint8_t stream_id) {
  if (getStreamURL(stream_id)) {
    streamIsPlaying = audio.connecttohost(config.stream_url);
    return true;
  }
  DEBUG_PRINTLN("[AUDIO] No STREAM URL defined!");
  env["status"] = "No stream url defined!";
  return false;
}

void audio_info(const char *info) {
  Serial.print("info        "); Serial.println(info);
}
void audio_showstation(const char *station) {
  Serial.print("station     "); Serial.println(station);
  String streamStation = String(station);
  env["stream_station"] = streamStation.substring(0, 25); // First 16 chars only (max)
}

void audio_showstreamtitle(const char *title) {
  Serial.print("streamtitle "); Serial.println(title);
  String streamTitle = String(title);
  env["stream_title"] = streamTitle.substring(0, 25); // Take only the first 16 chars (max)
}

void audio_bitrate(const char *bitrate) {
  Serial.print("bitrate     "); Serial.println(bitrate);
  String bitRate = String(bitrate);
  env["stream_bitrate"] = bitRate.substring(0).toInt();
}

// Stream actions
void nextStream() {
  //config.stream_id++;
  config.stream_id = countStreams;
  if (config.stream_id >= config.stream_count) {
    config.stream_id = 0;
  }
  streamChanged = true;
}
void nextStreamWeb() {
  config.stream_id++;
  if (config.stream_id >= config.stream_count) {
    config.stream_id = 0;
  }
  streamChanged = true;
}

void togglePlay() {
  streamIsPlaying = audio.pauseResume();
  DEBUG_PRINT("[AUDIO] pauseResume(): ");
  if (streamIsPlaying) {
    DEBUG_PRINTLN("PLAY");
    streamIsPaused = false;
    env["status"] = "Playing " + config.stream_id;
    updateDisplay();
  } else {
    DEBUG_PRINTLN("PAUSE");
    streamIsPaused = true;
    env["status"] = "Pause";
    updateDisplay();
  }
}

uint8_t tickCounter = 0;

void loop() {
  if (config.ota_enable) {
    ArduinoOTA.handle();
  }

  if ((millis() - last) > 1100) {

    streamsControl();

    if (WiFi.status() != WL_CONNECTED) {
      // Not connected? RETRY!
      connectToWifi();
    }

    audio.setVolume(config.volume);
    env["volume"] = config.volume;

    tickCounter++;
    if ((tickCounter % 10) == 0) {
      if (!streamIsPlaying) {
        playStream(config.stream_id);
        updateDisplay();
      }
    }
    volumeControl();

    if (streamTitle != oldStreamTitle) {
      updateDisplay();
      oldStreamTitle = streamTitle;
    }

    last = millis();
  }
}
void volumeControl() {

  countVol = (encoder.getCount());
  if (countVol < 1) {
    countVol = 1;
    encoder.setCount(countVol);
  }
  if (countVol > 21) {
    countVol = 21;
    encoder.setCount(countVol);
  }
  if (countVol != oldCountVol) {
    config.volume = countVol;
    oldCountVol = countVol;
    updateDisplay();
  }
}

void streamsControl() {
  countStreams = (encoder2.getCount());
  if (countStreams < 0) {
    countStreams = 0;
    encoder2.setCount(countStreams);
  }
  if (countStreams > 6) {
    countStreams = 6;
    encoder2.setCount(countStreams);
  }
  if (countStreams != oldCountStreams) {
    nextStream();
    updateDisplay();
    oldCountStreams = countStreams;
  }
}