ラズパイで天気情報を電光表示板に表示する

![IMG_3091.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/b663678d-40e9-c511-847d-1d7e68565a53.jpeg)

[前回](https://qiita.com/yuppejp/items/5485599131a549722131)の続きでOLEDモジュールを二つ使って、バスの接近情報に加えて、現在の天気情報も表示してみます。[SO1602AWWB-UC-WB](http://akizukidenshi.com/catalog/g/gP-08277/)は二つまで同時に接続することができます。

#完成例
左側が天気情報で、右側が前回作成したバスの接近情報情報です。どちらもリアルタイムに現在の情報が常に表示されているので、身支度をしながら確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/c01d5f9f-1821-a6ee-2879-4b09d8581956.png)

表示幅が狭いため、天気は先頭の2文字だけ表示しています。
- 晴れ： Fair (Fa)
- くもり： Cloudy (Cl)
- 雨: Rain (Ra)

#配線図
二つのOLEDモジュールの配線は、4ピンのSAのみ異なります。SAのHigh/LowでIOアドレスが変わります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/77444/50455f1d-6e66-04c4-1598-ddde25f66d3d.png)

|Raspberry Pi|SO1602(1個目）           |SO1602(2個目）       |
|------------|-----------------------|-------------------|
|1(3.3V)     |2(VDD)                 |2(VDD), <b>4(SA0)</b>     |
|3(SDA)      |8(SDAin), 9(SDAout)    |8(SDAin), 9(SDAout)|
|5(SCL)      |7(SLC)                 |7(SLC)             |
|6(GND)      |1(VSS), 3(/CS), <b>4(SA0)</b> |1(VSS), 3(/CS)     |

#天気情報の取得
最寄り地域の現在の天気と気温はweathernews社のサイトから取得しました。使用したOLEDモジュールは漢字が表示できないため、lang=enを指定して英語で取得します。
予想最高気温と最低気温はYahoo天気を使用しました。

```Python:weather.py
import urllib.request
import cchardet
import re
import so1602
from datetime import datetime
from bs4 import BeautifulSoup

def padding(text):
    pattern = r'[0-9]*'
    result = re.search(pattern, text)
    num = result.group(0)
    if len(num) == 1:
        text = ' ' + text
    return text

def fixlen(text, length):
    return text.ljust(length)[:length]

def getTemp(url):
    highs = []
    lows = []

    with urllib.request.urlopen(url) as res:
        byte = res.read()
        html = byte.decode(cchardet.detect(byte)['encoding'])
        soup = BeautifulSoup(html, 'html.parser')

        for block in soup.find_all('li', {'class':{'high'}}):
            items = block.text.split()
            high = items[0]
            high = high.replace('℃', 'c')
            high = high.replace('[', ' ')
            high = high.replace(']', '')
            high = padding(high)
            highs.append(high)

        for block in soup.find_all('li', {'class':{'low'}}):
            items = block.text.split()
            low = items[0]
            low = low.replace('℃', 'c')
            low = low.replace('[', ' ')
            low = low.replace(']', '')
            low = padding(low)
            lows.append(low)
   
    return lows, highs

def getNowTemp(url):
    lows, highs = getTemp(url)

    now = datetime.now()
    if now.hour < 17:
        high = 'H:' + highs[0]
        low = 'L:' + lows[0]
    else:
        high = 'h:' + highs[1]
        low = 'l:' + lows[1]
    
    return low, high

def getNowWeather(url):
    with urllib.request.urlopen(url) as res:
        byte = res.read()
        html = byte.decode(cchardet.detect(byte)['encoding'])
        soup = BeautifulSoup(html, 'html.parser')
        #print('[soup]:', soup, '\n')

        title = soup.head.title
        #print('[title]:', title.text, '\n')


        #for block in soup.find_all('div', {'class':{'text_box'}}):
        for block in soup.find_all('div', {'class':{'weather-now__cont'}}):
            items = block.text.split()
            #['10:20,', 'Fair', '16.8℃', 'RH', ':', '45', '%', 'Pres.', ':', '1010', 'hPa', 'Wind', ':', 'S', '5', 'm/s', 'Sunrise', ':', '05:12', 'Sunset', ':', '18:14']
            print(items)

    time = items[0]
    weather = items[1].replace('Weather', '')
    temp = items[2].replace('Temp.', '').replace('℃', 'c')
    humid = items[3].replace('RH', '')
    wind = items[6] + ' ' + items[7].replace('/', '')

    return time, weather, temp, humid, wind

def getWeather(weather_url, temp_url):
    time, weather, temp, humid, wind = getNowWeather(weather_url)
    low, high = getNowTemp(temp_url)

    line1 = time + weather
    line2 = temp
    line1 = fixlen(line1, 7) + ' ' + high
    line2 = fixlen(line2, 7) + ' ' + low

    return line1, line2

def display(addr, line1, line2):
    so1602.setaddr(addr)

    # LCD初期化
    so1602.command(0x0c)
    so1602.command(0x01)

    # LCD表示
    # 1行目
    so1602.command(0x80)
    so1602.write(line1)

    # 2行目
    so1602.command(0xa0)
    so1602.write(line2)

if __name__ == '__main__':
    urls = (
        'https://weathernews.jp/onebox/35.409038/139.596662/temp=c&q=%E4%B8%8A%E5%A4%A7%E5%B2%A1%EF%BC%88%E7%A5%9E%E5%A5%88%E5%B7%9D%E7%9C%8C%EF%BC%89&v=fd701b496541c0fcbfd59939ef829941202fdf32e6fd63783109fb3aabeba244&lang=en',
        'https://weather.yahoo.co.jp/weather/jp/14/4610.html')
    
    line1, line2 = getWeather(*urls)
    print('1234567890123456')
    print(line1)
    print(line2)
    display(0x3c, line1, line2)
```

#実行してみる
```bash
$ python3 weather.py
```

うまく表示できたら、cronにセットします。

```
*/1 * * * * python3 /home/pi/programs/bus.py
*/1 * * * * python3 /home/pi/programs/weather.py
```

#さいごに
OLEDモジュールは視認性が良く、常時、何か情報を表示しておくのに最適です。アイデア次第でいろいろと活用できそうです。面白い使い方がありましたら、ぜひシェアしてください。

###参考
- [ラズパイで作る「気温・湿度・気圧センサー」　有機ELディスプレイを取り付け](https://www.itmedia.co.jp/news/articles/1902/22/news025.html)
- [ラズパイでバスの接近情報を電光表示板に表示する](https://qiita.com/yuppejp/items/5485599131a549722131)