Electronic
20 Juin 2024
[Cristal] How to display live weather on a I2C screen ?
Introduction
Together we will see how to display live weather based on GPS coordinates on an I2C screen. To obtain the information, we will use the open-meteo API system.
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.
#ifndef METEO_H_
#define METEO_H_
#include <Arduino.h>
String init_http(void);
float get_temp(void);
int get_WMO(void);
int get_day_night(void);
#endif
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <open-meteo.h>
String url = "https://api.open-meteo.com/v1/forecast?latitude=<your-latitude>&longitude=<your-longitude>¤t=temperature_2m,is_day,weather_code&forecast_days=1";
String init_http(void){
// Utilisation de la bibliothèque HTTPClient pour effectuer une requête GET
HTTPClient http;
http.begin(url); // 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";
}
}
float get_temp(void){
String req_rep = init_http();
DynamicJsonDocument doc(1024); // Taille du document JSON
// Désérialiser le JSON
DeserializationError error = deserializeJson(doc, req_rep);
// Vérifier s'il y a une erreur lors de la désérialisation
if (!error) {
// Extraire la valeur de "temperature_2m"
float temperature = doc["current"]["temperature_2m"];
return temperature;
} else {
Serial.println("Erreur lors de la désérialisation du JSON !");
}
}
int get_WMO(void){
String req_rep = init_http();
DynamicJsonDocument doc(1024); // Taille du document JSON
// Désérialiser le JSON
DeserializationError error = deserializeJson(doc, req_rep);
// Vérifier s'il y a une erreur lors de la désérialisation
if (!error) {
// Extraire la valeur de "weather_code"
int wmo = doc["current"]["weather_code"];
return wmo;
} else {
Serial.println("Erreur lors de la désérialisation du JSON !");
}
}
int get_day_night(void){
String req_rep = init_http();
DynamicJsonDocument doc(1024); // Taille du document JSON
// Désérialiser le JSON
DeserializationError error = deserializeJson(doc, req_rep);
// Vérifier s'il y a une erreur lors de la désérialisation
if (!error) {
// Extraire la valeur de "is_day"
int dn = doc["current"]["is_day"];
return dn;
} else {
Serial.println("Erreur lors de la désérialisation du JSON !");
}
}
We can now use these functions to display the weather interactively on the 128 x 64 screen.
#include <Arduino.h>
#include <U8g2lib.h>
#include <stdio.h>
#include <Wire.h>
#include <open-meteo.h>
#include <WiFi.h>
#define I2C_SDA 27
#define I2C_SCL 22
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE);
// 'soleil', 32x32px
const unsigned char epd_bitmap_soleil [] PROGMEM = {
0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00,
0xf0, 0xc0, 0x03, 0x0f, 0xf0, 0xc1, 0x83, 0x0f, 0xf0, 0x01, 0x80, 0x0f, 0xf0, 0x03, 0xc0, 0x0f,
0xe0, 0xf3, 0xcf, 0x07, 0x80, 0xfc, 0x3f, 0x01, 0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc,
0x3f, 0xff, 0xff, 0xfc, 0x3f, 0xff, 0xff, 0xfc, 0x00, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00,
0x00, 0xfe, 0x7f, 0x00, 0x00, 0xfe, 0x7f, 0x00, 0x80, 0xfd, 0xbf, 0x01, 0xe0, 0xf3, 0xcf, 0x07,
0xf0, 0x03, 0xc0, 0x0f, 0xf0, 0x01, 0x80, 0x0f, 0xf0, 0xc1, 0x83, 0x0f, 0xf0, 0xc0, 0x03, 0x0f,
0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00
};
// 'ciel-clair', 32x32px
const unsigned char epd_bitmap_ciel_clair [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x7f, 0x00, 0xfc, 0xff, 0xff, 0x03, 0xfe, 0xff, 0xff, 0x07,
0xff, 0xff, 0xff, 0x07, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0x0f,
0xff, 0xff, 0xff, 0x0f, 0xfe, 0xff, 0xff, 0x07, 0xfc, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x73,
0xf0, 0xff, 0xff, 0x79, 0xf0, 0xff, 0xff, 0x19, 0xf0, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0x03,
0xe0, 0xff, 0xff, 0x03, 0xc0, 0xff, 0xff, 0xf7, 0x00, 0xf0, 0xff, 0xf3, 0x00, 0xf0, 0xff, 0x03,
0x00, 0xf0, 0xff, 0x03, 0x00, 0xe0, 0xff, 0x03, 0x00, 0xee, 0xff, 0x39, 0x80, 0xcf, 0xff, 0x78,
0x80, 0x03, 0x7f, 0x70, 0x00, 0x60, 0x80, 0x01, 0x00, 0x60, 0x80, 0x03, 0x00, 0x70, 0x8c, 0x03,
0x00, 0x30, 0x0c, 0x03, 0x00, 0x30, 0x0c, 0x02, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'nuage', 32x32px
const unsigned char epd_bitmap_nuage [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xff, 0x7f,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff,
0xf8, 0xff, 0xff, 0x7f, 0xf8, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x1f, 0xf0, 0xff, 0xff, 0x07,
0xe0, 0xff, 0xff, 0x07, 0x80, 0xff, 0xff, 0x07, 0x00, 0xf8, 0xff, 0x03, 0x00, 0xf0, 0xff, 0x03,
0x00, 0xf0, 0xff, 0x01, 0x00, 0xe0, 0xff, 0x00, 0x00, 0x80, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'brumeux', 32x32px
const unsigned char epd_bitmap_brumeux [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x78, 0xfe, 0xff, 0x00, 0xf8, 0xfe, 0xff, 0x00, 0x78, 0xfe, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00,
0xf8, 0xff, 0xff, 0x07, 0xf8, 0xff, 0xff, 0x07, 0xf8, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00,
0x80, 0xff, 0xff, 0xf1, 0xe0, 0xff, 0xff, 0xf7, 0xf0, 0xff, 0xff, 0xef, 0xf8, 0xff, 0xff, 0x1f,
0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xf8, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x1f,
0xf0, 0xff, 0xff, 0x0f, 0xe0, 0xff, 0xff, 0x07, 0x00, 0xf0, 0xff, 0x01, 0x00, 0xf8, 0xff, 0x01,
0x00, 0xf8, 0xff, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'pluie-abondante', 32x32px
const unsigned char epd_bitmap_pluie_abondante [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0xc7, 0x01, 0x00, 0x1c, 0xc7, 0x01, 0x00, 0x1c, 0xc7, 0x01,
0x00, 0x1c, 0xc7, 0x01, 0xc0, 0x71, 0x1c, 0x07, 0xc0, 0x71, 0x1c, 0x07, 0xc0, 0x71, 0x1c, 0x07,
0xc0, 0x71, 0x1c, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x0f,
0xf8, 0xff, 0xff, 0x1f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f,
0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x7f, 0xfe, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x1f,
0xfc, 0xff, 0xff, 0x0f, 0xf8, 0xff, 0xff, 0x07, 0xe0, 0xff, 0xff, 0x07, 0x00, 0xfc, 0xff, 0x03,
0x00, 0xf8, 0xff, 0x01, 0x00, 0xf0, 0xff, 0x00, 0x00, 0xc0, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'flocon-de-neige', 32x32px
const unsigned char epd_bitmap_flocon_de_neige [] PROGMEM = {
0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xdc, 0x3b, 0x00, 0x00, 0xfc, 0x3f, 0x00,
0xc0, 0xfd, 0xbf, 0x03, 0xc0, 0xf9, 0x9f, 0x03, 0xc0, 0xe1, 0x87, 0x03, 0xdc, 0xc1, 0x83, 0x3b,
0xfc, 0xc3, 0xc3, 0x3f, 0xfc, 0xc3, 0xc3, 0x3f, 0xf8, 0xc3, 0xc3, 0x1f, 0xf8, 0xcf, 0xf3, 0x1f,
0xfe, 0xff, 0xff, 0x7f, 0x7e, 0xff, 0xff, 0x7e, 0x1e, 0xfc, 0x3f, 0x78, 0x00, 0xf0, 0x0f, 0x00,
0x00, 0xf0, 0x0f, 0x00, 0x1e, 0xfc, 0x3f, 0x78, 0x7e, 0xff, 0xff, 0x7e, 0xfe, 0xff, 0xff, 0x7f,
0xf8, 0xcf, 0xf3, 0x1f, 0xf8, 0xc3, 0xc3, 0x1f, 0xfc, 0xc3, 0xc3, 0x3f, 0xfc, 0xc3, 0xc3, 0x3f,
0xdc, 0xc1, 0x83, 0x3b, 0xc0, 0xe1, 0x87, 0x03, 0xc0, 0xf9, 0x9f, 0x03, 0xc0, 0xfd, 0xbf, 0x03,
0x00, 0xfc, 0x3f, 0x00, 0x00, 0xdc, 0x3b, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0xc0, 0x03, 0x00
};
// 'orage', 32x32px
const unsigned char epd_bitmap_orage [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x07, 0x00,
0x00, 0xc0, 0x07, 0x00, 0x00, 0xc0, 0x07, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0xf0, 0x1f, 0x00,
0x00, 0xf8, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0xc0, 0xff, 0xff, 0x07, 0xf0, 0xff, 0xff, 0x1f,
0xf8, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f, 0xfc, 0xff, 0xff, 0x3f,
0xfc, 0xff, 0xff, 0x1f, 0xf8, 0xff, 0xff, 0x07, 0xf8, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x03,
0xe0, 0xff, 0xff, 0x03, 0xe0, 0xff, 0xff, 0x01, 0xe0, 0xff, 0xff, 0x00, 0xc0, 0xff, 0x39, 0x00,
0x80, 0xff, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// 'lunes', 32x32px
const unsigned char epd_bitmap_lune [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0xff, 0x3f, 0x00,
0x80, 0xff, 0xff, 0x00, 0xe0, 0xff, 0xff, 0x01, 0xf0, 0xff, 0xff, 0x03, 0xf8, 0xff, 0xff, 0x07,
0xf8, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0xff, 0x1f,
0x1c, 0xf0, 0xff, 0x1f, 0x00, 0xc0, 0xff, 0x3f, 0x00, 0x00, 0xff, 0x3f, 0x00, 0x00, 0xfe, 0x3f,
0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0xf8, 0x3f, 0x00, 0x00, 0xf8, 0x3f,
0x00, 0x00, 0xf0, 0x3f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0x00, 0xf0, 0x1f,
0x00, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf0, 0x07, 0x00, 0x00, 0xf8, 0x03,
0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
class Meteo_aff {
public :
int wmo_code, dn_cond;
float temp;
mutable const char* location;
void print_4user(){
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_helvB18_te);
u8g2.setFontDirection(2);
u8g2.enableUTF8Print();
char buffer_te[8];
snprintf(buffer_te, sizeof(buffer_te), "%.1f°C", temp);
u8g2.drawUTF8(70,5,buffer_te);
u8g2.setFont(u8g2_font_helvB14_te);
u8g2.drawUTF8(125,40,location);
u8g2.setBitmapMode(1);
if (wmo_code == 0 && dn_cond == 1){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_soleil);
}
else if ((wmo_code == 0 || wmo_code == 1 || wmo_code == 2) && dn_cond == 0){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_lune);
}
else if ((wmo_code == 1 || wmo_code == 2) && dn_cond == 1){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_ciel_clair);
}
else if (wmo_code == 3){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_nuage);
}
else if (wmo_code == 45 || wmo_code == 48 || wmo_code == 51 || wmo_code == 53 || wmo_code == 55 || wmo_code == 56 || wmo_code == 57){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_brumeux);
}
else if (wmo_code == 61 || wmo_code == 63 || wmo_code == 65 || wmo_code == 66 || wmo_code == 67 || wmo_code == 80 || wmo_code == 81 || wmo_code == 82){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_pluie_abondante);
}
else if (wmo_code == 71 || wmo_code == 73 || wmo_code == 75 || wmo_code == 77 || wmo_code == 85 || wmo_code == 86){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_flocon_de_neige);
}
else if (wmo_code == 95 || wmo_code == 96 || wmo_code == 99){
u8g2.drawXBM(85, 2, 32, 32, epd_bitmap_orage);
}
u8g2.sendBuffer();
}
void setLocation(const char* newLocation) const {
location = newLocation;
}
};
Meteo_aff m1;
m1.temp = get_temp();
m1.dn_cond = get_day_night();
m1.wmo_code = get_WMO();
m1.setLocation("Brest");
m1.print_4user();
delay(10000);
Attribution - Pas d'Utilisation Commerciale - Pas de Modification 3.0 France (CC BY-NC-ND 3.0 FR)
Auteur : Romain MELLAZA
Date de publication : 20 Juin 2024