1754 views|7 replies

155

Posts

1

Resources
The OP
 

【Beetle ESP32-C3】8. OLED clock and weather assistant (Arduino) [Copy link]

This post was last edited by sonicfirr on 2022-9-5 07:45

The previous two reviews, this case is based on these two:

Beetle ESP32-C3】VI. OLED, AHT10 and TCP (Arduino)

【Beetle ESP32-C3】VII. Network timing and weather request (Arduino)


On Sunday, I integrated the first two evaluation cases and made a "big job". The functions are as follows:

1) OLED can display two screens (called PAGE in the code), "clock + AHT10 temperature and humidity" and "weather icon + temperature".

2) Button (connected to IO7) is used to control the OLED screen change.

This article first gives the complete code, and then plans to write a review description. Code logic - I have been working on it for a day, and I really don’t have the energy to explain the logic.

#include <Arduino.h>
#include <WiFi.h>
#include <WiFiMulti.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <Adafruit_AHTX0.h>

//-----SSID & password
const char *ssid = "yourssid";        //WIFI AP ssid
const char *password = "yourpsw";     //WIFI AP password

//-----NTP server & timezone offset
const char *ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 14400;     //3600*4 for UTC+8
const int  daylightOffset_sec = 14400;
struct tm  t;                         //time struct
void printLocalTime(void);

//-----timer HW per second
hw_timer_t *timer = NULL;             //timer variable
volatile SemaphoreHandle_t timersem;  //timer fire sem
void     IRAM_ATTR onTimer(void);     //callback func
void     initTimer(void);

//-----weather server URL & instance for json parsing
DynamicJsonDocument doc(1024);        //json doc instance
const char *url = "https://api.thinkpage.cn/v3/weather/now.json?key=your_apikey&location=tianjin&language=en&unit=c";
void getWeather(void);                //request now weather func
int code = 0;                         //weather code
int degree = 0;                       //weather temperature

//-----u8g2 instance & functions
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
void drawLocalTimePage(void);
void drawNowWeatherPage(int code, int temp);

//-----input key
#define KEY             7

//-----show page enum
typedef enum {
  TIMEPAGE = 0,
  WEATHERPAGE,
} AITA_PAGE_INDEX;
//-----global variable of page No
int pagestate = TIMEPAGE;

//-----AHT10 instance & sensor variables
Adafruit_AHTX0 aht;                   //aht instance
sensors_event_t aht_humi, aht_temp;   //sensor variables
void getAHT10(void);                  //read aht10 sensor

void setup() {
//-----initialize BSP
  Serial.begin(115200);
  pinMode(KEY, INPUT_PULLUP);
//-----initialize u8g2
  u8g2.begin();
  u8g2.setFontPosTop();
  u8g2.enableUTF8Print();
//-----initialize AHT10
  if(!aht.begin()) {
    Serial.println("Could not find AHT");
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_osb18_tf);
    u8g2.drawStr(5,10,"no AHT");
    u8g2.sendBuffer();
    while(1) delay(10);
  }
  Serial.println("AHT10 or AHT20 found");
  getAHT10();
//-----connect AP 
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
//-----print IP address
  Serial.println(" CONNECTED");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
//-----initialize and get the time then initialize timer(per sec)
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  if(!getLocalTime(&t)){
    Serial.println("Failed to obtain time");
    return;
  } else {
    Serial.println(&t, "%A, %B %d %Y %H:%M:%S");
    initTimer();
    getWeather();
  }
}

void loop() {
//-----update time state per second
  if(xSemaphoreTake(timersem, 0) == pdTRUE) {
    getLocalTime(&t);
  }
//-----refresh screen 
  if(pagestate == TIMEPAGE)
    drawLocalTimePage();    
  else if(pagestate == WEATHERPAGE) 
    drawNowWeatherPage(code, degree);  
//-----update weather info per 5 minutes
  if(t.tm_min%5==0 && t.tm_sec==0) {
    getAHT10();
    if(WiFi.status() == WL_CONNECTED) {
      getWeather();
    }
  }
//-----read KEY
  if(digitalRead(KEY) == 0) {
    delay(30);
    if(digitalRead(KEY) == 0) {
      if(pagestate == WEATHERPAGE) pagestate = TIMEPAGE;
      else                         pagestate++;
    }
  }
}

//-----second timer callback function
void IRAM_ATTR onTimer() {
  xSemaphoreGiveFromISR(timersem, NULL);
}
//-----intialize timer function
void initTimer() {
  timersem = xSemaphoreCreateBinary();
  //ESP32 sysclk is 80MHz.
  //frequency division factor to 80,
  //then timer clock is 1MHz.
  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 1000000, true); //1000000us timer
  timerAlarmEnable(timer);
}

//-----print local time function
void printLocalTime(void) {
  if(!getLocalTime(&t)) {
    Serial.println("Failed to obtain time");
    return;
  }
  Serial.println(&t, "%F %T %A");
}
//-----read AHT10 sensor function
void getAHT10(void) {
  aht.getEvent(&aht_humi, &aht_temp); 
}
//-----draw local time function
void drawLocalTimePage(void) {
  char str[6] = {0};
  u8g2.clearBuffer();
  //line1. set time & weekday
  u8g2.setFont(u8g2_font_ncenB14_tr);
  u8g2.setCursor(0, 0);
  u8g2.print(&t, "%H:%M:%S  %a");
  u8g2.setCursor(24, 18);
  //line2. set date
  u8g2.setFont(u8g2_font_8x13_mf);
  u8g2.print(&t, "%Y-%m-%d");
  //line3. set aht10 humidity
  u8g2.drawStr(0, 32, "Humi: ");
  memset(str, 0, 6);
  dtostrf(aht_humi.relative_humidity, 6, 2, str);
  u8g2.drawStr(48, 32, str);
  u8g2.drawStr(96,32, "% rH");
  //line4. set aht10 temperature
  u8g2.drawStr(0, 48, "Temp: ");
  memset(str, 0, 6);
  dtostrf(aht_temp.temperature, 6, 2, str);
  u8g2.drawStr(48, 48, str);
  u8g2.setCursor(96, 48);
  u8g2.print("°  C");
  //draw screen
  u8g2.sendBuffer();
}

//-----set weather icon function
void drawWeatherSymbol(u8g2_uint_t x, u8g2_uint_t y, uint8_t symbol) {
  if(symbol>=0 && symbol<4) {         //Sun
    u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
    u8g2.drawGlyph(x, y, 69);
  } else if(symbol>=4 && symbol<9) {  //Cloudy
    u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
    u8g2.drawGlyph(x, y, 65); 
  } else if(symbol==9) {              //Overcast
    u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
    u8g2.drawGlyph(x, y, 64);
  } else if(symbol>=10 && symbol<13) {//Thunder
    u8g2.setFont(u8g2_font_open_iconic_embedded_6x_t);
    u8g2.drawGlyph(x, y, 67);
  } else if(symbol>=13 && symbol<21) {//Rain
    u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
    u8g2.drawGlyph(x, y, 67);
  } else {                            //Others show star
    u8g2.setFont(u8g2_font_open_iconic_weather_6x_t);
    u8g2.drawGlyph(x, y, 68);
  }
}
//-----set weather temperature degree function
void drawWeatherDegree(uint8_t symbol, int degree) {
  drawWeatherSymbol(0, 0, symbol);
  u8g2.setFont(u8g2_font_logisoso32_tf);
  u8g2.setCursor(48+6, 10);
  u8g2.print(degree);
  u8g2.print("°C"); //requires enableUTF8Print()
}
//-----draw now weather function
void drawNowWeatherPage(int code, int temp) {
  u8g2.clearBuffer();
  drawWeatherDegree(code, temp);
  u8g2.setCursor(32, 48);
  u8g2.setFont(u8g2_font_8x13_mf);
  u8g2.print("Tianjin");
  u8g2.sendBuffer();
}

//-----request now weather function
void getWeather() {
  if((WiFi.status() == WL_CONNECTED)) {
    HTTPClient http;           //create HTTPClient instance
    http.begin(url);           //begin HTTP request
    int httpCode = http.GET(); //get response code - normal:200
    if(httpCode > 0) {
      Serial.printf("[HTTP] GET... code: %d\n", httpCode);
      if(httpCode == HTTP_CODE_OK) {
        String payload = http.getString();       
        Serial.println(payload);
        //parse response string  to DynamicJsonDocument instance
        deserializeJson(doc, payload);
        //get top level Json-Object
        JsonObject obj = doc.as<JsonObject>();
        //get "results" property then parse the value to Json-Array
        JsonVariant resultsvar = obj["results"];
        JsonArray resultsarr = resultsvar.as<JsonArray>();
        //get array index 0 which is now weather info
        JsonVariant resultselementvar = resultsarr[0];
        JsonObject resultselementobj = resultselementvar.as<JsonObject>();
        /* get values of city, temp, code, update */
        //get city
        JsonVariant namevar = resultselementobj["location"]["name"];
        String namestr = namevar.as<String>();
        Serial.println(namestr);
        //get temperature
        JsonVariant temperaturevar = resultselementobj["now"]["temperature"];
        String temperaturestr = temperaturevar.as<String>();
        degree = temperaturevar.as<int>();
        Serial.println(temperaturestr);
        //get weather code
        JsonVariant codevar = resultselementobj["now"]["code"];
        code = codevar.as<int>();
        Serial.println(code);
        //get last_update time
        JsonVariant last_updatevar = resultselementobj["last_update"];
        String last_updatestr = last_updatevar.as<String>();
        Serial.println(last_updatestr);
      }
    } else {
      Serial.printf("[HTTP] GET... failed, error: %s\n", 
      http.errorToString(httpCode).c_str());
    }
    http.end(); //end http connectiong
  }
}

Figure 8-1 Example OLED display effect

This post is from RF/Wirelessly

Latest reply

Thanks for sharing!   Details Published on 2022-9-6 09:07
 

2865

Posts

4

Resources
2
 

Is the original poster's OLD SSD1306 an SPI port or an I2C interface?

This post is from RF/Wirelessly

Comments

I2C interface, save IO  Details Published on 2022-9-5 09:58
I2C interface, save IO  Details Published on 2022-9-5 09:50
 
 

6742

Posts

2

Resources
3
 

The effect seems to be good. I also developed a function to get the time two days ago~

This post is from RF/Wirelessly
 
 
 

155

Posts

1

Resources
4
 
bigbat posted on 2022-9-5 09:26 Is the original poster's OLD SSD1306 an spi port or an I2C interface

I2C interface, save IO

This post is from RF/Wirelessly

Comments

The SPI interface of SSD1306 can also have 2 lines, one of which can be unused.  Details Published on 2022-9-5 13:30
 
 
 

6818

Posts

11

Resources
5
 
bigbat posted on 2022-9-5 09:26 Is the original poster's OLD SSD1306 an spi port or an I2C interface

After looking at the picture, it is a four-wire device, so it should be an IIC interface.

This post is from RF/Wirelessly
 
 
 

2865

Posts

4

Resources
6
 
sonicfirr posted on 2022-9-5 09:50 I2C interface, save IO

The SPI interface of SSD1306 can also have 2 lines, one of which can be unused.

This post is from RF/Wirelessly

Comments

That's right.  Details Published on 2022-9-5 14:41
 
 
 

155

Posts

1

Resources
7
 
bigbat posted on 2022-9-5 13:30 The SPI interface of SSD1306 can also be 2 lines, one of which can be unused.

That's right.

This post is from RF/Wirelessly
 
 
 

6062

Posts

4

Resources
8
 

Thanks for sharing!

This post is from RF/Wirelessly
 
 
 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

快速回复 返回顶部 Return list