[Cristal] How to display daily news on a I2C screen ?
Introduction
Together we will see how to display daily news on an I2C screen. To obtain the information, we will use the News API. You will have to create a free account on their site to obtain your personal API key. Don’t hesitate to go read the API documentation, we can make super interesting HTTP requests! Unfortunately the information displayed will not be full live, there is a 24 hour delay, but it allows you to get the most popular information for each country.
Programming
We will use the module ArduinoJson
, so you need to install it on your project whether you are using the Arduino IDE or PlatformIO.
We therefore code a simple library allowing us to make the HTTP request allowing us to provide the JSON payload to the API, knowing that the payload is basically quite long with more than twenty different articles returned, so I chose to keep only the 5 most popular french articles of the day (But you can do absolutely whatever you want based on my example) :
open-news-api.h
:
#ifndef NEWS_H_
#define NEWS_H_
String init_http_news(void);
String* get_five_top_news(void);
#endif
open-news-api.cpp
:
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <open-news-api.h>
#include <get_secret_values.h>
#define MAX_TITLES 5
String url_news = "https://newsapi.org/v2/top-headlines?country=fr&sortBy=popularity&apiKey=";
String init_http_news(void){
String apiKey = get_secret(5);
// Remove any trailing newline characters
apiKey.trim();
// Append the API key to the URL
url_news += apiKey;
// Utilisation de la bibliothèque HTTPClient pour effectuer une requête GET
HTTPClient http;
http.begin(url_news); // Début de la requête HTTP
int code = http.GET(); // Effectuer la requête GET
if (code > 0) { // Vérifier si la requête a réussi
// Obtenir le contenu de la réponse
String payload = http.getString();
http.end();
return payload;
} else {
Serial.println("Erreur lors de la requête HTTP !");
http.end();
return "error";
}
http.end();
}
String* get_five_top_news(void) {
// Créer un tableau pour stocker les titres
static String titles[MAX_TITLES];
for (int i = 0; i < MAX_TITLES; i++) {
titles[i] = ""; // Initialiser le tableau
}
String req_rep = init_http_news();
if (req_rep == "") {
Serial.println("Aucune réponse reçue !");
return titles;
}
DynamicJsonDocument doc(2048); // Taille du document JSON, ajustez si nécessaire
// Désérialiser le JSON
DeserializationError error = deserializeJson(doc, req_rep);
if (error) {
Serial.println("Erreur lors de la désérialisation du JSON !");
return titles;
}
// Accéder à la liste des articles
JsonArray articles = doc["articles"].as<JsonArray>();
// Extraire les titres des 5 premiers articles
int count = 0;
for (JsonObject article : articles) {
if (count >= MAX_TITLES) break; // Limiter à 5 titres
const char* title = article["title"];
if (title) {
titles[count] = String(title);
count++;
}
}
// Vérifier s'il y a des titres trouvés
if (count == 0) {
titles[0] = "Aucun titre trouvé !";
}
return titles;
}
If you are wondering what the personal library “get_secret_values” is then head here.
Display on screen
#include <Arduino.h>
#include <U8g2lib.h>
#include <stdio.h>
#include <Wire.h>
#include <open-news-api.h>
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE);
void display_titles() {
// Obtenir le tableau de titres
if (titles_news == nullptr){
titles_news = get_five_top_news();
}
u8g2.clearBuffer();
u8g2.setFlipMode(1); // Activer le mode de retournement pour inverser l'affichage
u8g2.setFontDirection(0);
u8g2.enableUTF8Print();
u8g2.setFont(u8g2_font_ncenB08_tf);
// Constante pour la largeur de l'écran en pixels
const int screenWidth = 128; // Largeur de l'écran OLED
for (int i = 0; i < MAX_TITLES; i++) {
u8g2.clearBuffer(); // Effacer le tampon de l'écran
u8g2.setCursor(0, 10); // Position du curseur pour le texte
// Préparer le titre avec le préfixe "Titre X: "
String fullTitle = "Titre " + String(i + 1) + ": " + titles_news[i];
// Variables pour gérer les lignes et l'espacement vertical
int lineHeight = 10; // Hauteur de ligne (ajustez selon la taille de police)
int yPosition = 10; // Position initiale en Y
// Variable pour stocker la largeur courante du texte
int currentWidth = 0;
// Diviser le texte en mots pour gérer le retour à la ligne
char *token = strtok((char *)fullTitle.c_str(), " ");
while (token != nullptr) {
String word = String(token) + " ";
int wordWidth = u8g2.getStrWidth(word.c_str());
if (currentWidth + wordWidth > screenWidth) {
// Si le mot ne tient pas sur la ligne actuelle, aller à la ligne suivante
yPosition += lineHeight;
u8g2.setCursor(0, yPosition);
currentWidth = 0;
}
// Imprimer le mot courant et mettre à jour la largeur actuelle
u8g2.print(word);
currentWidth += wordWidth;
// Passer au mot suivant
token = strtok(nullptr, " ");
}
u8g2.sendBuffer(); // Envoyer le tampon à l'écran
delay(DISPLAY_TIME); // Attendre avant d'afficher le titre suivant
}7
u8g2.setFlipMode(0);
}
You can safely remove u8g2.setFlipMode()
if your screen is in the opposite direction to mine, it just depends on its orientation in your project.
Auteur : Romain MELLAZA
Date de publication : 30 Juin 2024