2024年10月14日 星期一

MicroPython 學習筆記 : 用 SSD1306 顯示氣象資訊 (三)

在前一篇測試中我們已經掌握如何利用 MicroPython 內建的 framebuf 模組將圖片的 bytearray 資料存入顯示緩衝器後顯示於 SSD1306 OLED 螢幕上, 本篇則是要從 OpenWeatherMap 每 60 秒抓取一次氣象資料, 然後以圖片方式顯示於 SSD1306 上. 氣象爬蟲做法參考 :



4. 以圖片方式顯示 OpenWeatherMap 氣象資訊 : 

在 "MicroPython 學習筆記 : 用 SSD1306 顯示氣象資訊 (一)" 這篇測試中我們已將 OpenWeatherMap 氣象資料爬蟲寫成如下之 get_weather() 函式 : 

def get_weather(country, city, api_key):
    url=f'https://api.openweathermap.org/data/2.5/weather?q={city},{country}&units=metric&lang=zh_tw&appid={api_key}'
    try:
        res=urequests.get(url)
        data=ujson.loads(res.text)
        if data['cod']==200:    # 注意是數值
            ret={'geocode': data['id'],
                 'icon': data['weather'][0]['icon'],
                 'temperature': data['main']['temp'],
                 'pressure': data['main']['pressure'],
                 'humidity': data['main']['humidity']}
            return ret
        else:
            return None
    except Exception as e:
        return None

首先將 SSID 與密碼以及 OpenWeatherMap API key 寫在 config.py 中, 匯入要用到的模組 : 

>>> import config  
>>> import xtools   
>>> import urequests  
>>> import ujson  
>>> import ssd1306   
>>> import big_symbol   

連上網路 : 

>>> ip=xtools.connect_wifi(config.SSID, config.PASSWORD)     
Connecting to network...
network config: ('192.168.192.189', '255.255.255.0', '192.168.192.92', '192.168.192.92')

設定 get_weather() 需要的參數後呼叫它就會傳回現在的溫濕度與氣壓等資料 :

>>> weather_api_key=config.WEATHER_API_KEY   
>>> city='Kaohsiung'      
>>> country='TW'    
>>> data=get_weather(country, city, weather_api_key)    
>>> data   
{'icon': '03d', 'temperature': 27.88, 'geocode': 1673820, 'pressure': 1014, 'humidity': 88}   

接下來就可以用 big_symbol 模組的 Symbol 物件將這些氣象資料以較大尺寸的圖片顯示至 SSD1306 上. 先建立 SSD1306_I2C 物件 oled :

>>> i2c=I2C(0, scl=Pin(22), sda=Pin(21))     # 建立 I2C 物件 (ESP32)
>>> oled=ssd1306.SSD1306_I2C(128, 64, i2c)     # 建立 SSD1306_I2C 物件 
>>> sb=big_symbol.Symbol(oled)     # 建立 Symbol 物件

先清除螢幕 :

>>> sb.clear()    

呼叫 Symbol 物件的 temp() 方法顯示溫度像素圖 :

>>> sb.temp(0, 0)   
>>> oled.show()      

顯示 get_weather() 傳回的溫度於溫度像素圖後面 :

>>> sb.text(f"{data['temperature']}c", 32, 0)   
>>> oled.show()   

接下來呼叫 Symbol 物件的 temp() 方法顯示濕度像素圖 :

>>> sb.humid(0, 16)    
>>> oled.show()   

顯示 get_weather() 傳回的溼度於濕度像素圖後面 :

>>> sb.text(f"{data['humidity']}%", 32, 16)    
>>> oled.show()   

然後是顯示氣壓 : 

>>> sb.press(0, 32)   
>>> sb.text(f"{data['pressure']}hPa", 32, 32)   
>>> oled.show()    

最後可用 ASCII 文字在座標 (0, 48) 位置顯示目前時間以及在座標 (0, 56) 顯示地點 : 

>>> now=xtools.tw_now()    
Querying NTP server and set RTC time ... OK.
>>> now    
'2024-10-14 22:15:09'
>>> oled.text(now, 0, 48, 1)    
>>> oled.text(city, 0, 56, 1)    
>>> oled.show()     

這樣就會在 OLED 上顯示氣象資料了 :




完整程式碼如下 :

import config  
import xtools   
import urequests  
import ujson  
from machine import I2C, Pin
import ssd1306   
import big_symbol 

def get_weather(country, city, api_key):
    url=f'https://api.openweathermap.org/data/2.5/weather?q={city},{country}&units=metric&lang=zh_tw&appid={api_key}'
    try:
        res=urequests.get(url)
        data=ujson.loads(res.text)
        if data['cod']==200:    # 注意是數值
            ret={'geocode': data['id'],
                 'icon': data['weather'][0]['icon'],
                 'temperature': data['main']['temp'],
                 'pressure': data['main']['pressure'],
                 'humidity': data['main']['humidity']}
            return ret
        else:
            return None
    except Exception as e:
        return None

ip=xtools.connect_wifi(config.SSID, config.PASSWORD)
weather_api_key=config.WEATHER_API_KEY
city='Kaohsiung'   
country='TW'
data=get_weather(country, city, weather_api_key) 
i2c=I2C(0, scl=Pin(22), sda=Pin(21)) 
oled=ssd1306.SSD1306_I2C(128, 64, i2c)
sb=big_symbol.Symbol(oled) 
sb.clear()
sb.temp(0, 0) 
sb.text(f"{data['temperature']}c", 32, 0)  
sb.humid(0, 16)  
sb.text(f"{data['humidity']}%", 32, 16)   
sb.press(0, 32)   
sb.text(f"{data['pressure']}hPa", 32, 32) 
oled.text(city, 0, 56, 1)   
now=xtools.tw_now()    
oled.text(now, 0, 48, 1)    
oled.show() 

但上面的測試只是取得並顯示一筆資料而已, 我們的目標是要每分鐘更新最新氣象資料, 所以要用無窮迴圈來做, 程式碼如下 :

import config  
import xtools   
import urequests  
import ujson
from machine import I2C, Pin
import ssd1306   
import big_symbol
import time

def get_weather(country, city, api_key):
    url=f'https://api.openweathermap.org/data/2.5/weather?q={city},{country}&units=metric&lang=zh_tw&appid={api_key}'
    try:
        res=urequests.get(url)
        data=ujson.loads(res.text)
        if data['cod']==200:    # 注意是數值
            ret={'geocode': data['id'],
                 'icon': data['weather'][0]['icon'],
                 'temperature': data['main']['temp'],
                 'pressure': data['main']['pressure'],
                 'humidity': data['main']['humidity']}
            return ret
        else:
            return None
    except Exception as e:
        return None

ip=xtools.connect_wifi(config.SSID, config.PASSWORD)
if ip:
    # 設定氣象爬蟲參數
    weather_api_key=config.WEATHER_API_KEY
    city='Kaohsiung'   
    country='TW'
    # 建立 I2C 與 SSD1306_I2C 物件
    i2c=I2C(0, scl=Pin(22), sda=Pin(21)) # ESP32 I2C
    oled=ssd1306.SSD1306_I2C(128, 64, i2c)
    sb=big_symbol.Symbol(oled)
    while True:  # 每分鐘抓一次更新 OLED 顯示器
        data=get_weather(country, city, weather_api_key)
        sb.clear()
        sb.temp(0, 0)       
        sb.text(f"{data['temperature']}c", 32, 0)
        sb.humid(0, 16) 
        sb.text(f"{data['humidity']}%", 32, 16)
        sb.press(0, 32)
        sb.text(f"{data['pressure']}hPa", 32, 32)
        oled.text(xtools.tw_now(), 0, 48, 1)
        oled.text(city, 0, 56, 1)
        oled.show()
        time.sleep(60)
else:
    print('無法連線 WiFi')

這樣每分鐘就會刷新螢幕顯示最新的氣象資料了. 

沒有留言 :