rssデータ受信と天気マーク追加。電光掲示板表示天気予報Pythonプログラムリプレース

livedoor の天気予報データ配信のサービスが7月31日に終了したことで、天気予報読み上げが出来なくなり、かつ、電光掲示板への天気予報データ表示が、ずっと7月31日のものになった件は、先の記事でお知らせしました。

この際、天気予報読み上げのPythonプログラムを訂正し、天気予報については無事喋ってくれるようになりました。

続けて、電光掲示板への天気予報データ表示についての訂正を実施します。

1.電光掲示板天気予報PGリプレース

(1) 訂正箇所

① データ取出し部分

rss形式のデータを取り出す部分ですが、こちらは、前回記事と同様に、参考資料②の内容を丸々コピーすることで可能です。

天気予報読み上げと全く同じコードです。

【訂正前】

    json_url = 'https://weather.livedoor.com/forecast/webservice/json/v1' #API URL

        r =  urllib.request.urlopen('%s?city=%s' % (json_url, city) )
        obj = json.loads( r.read().decode('utf-8') )

【訂正後】

## Parser : 天気情報WebページのHTMLタグから天気情報を抽出してパースするメソッド ####################
def Parser(rssurl):
   with urllib.request.urlopen(rssurl) as res:
      xml = res.read()
      soup = BeautifulSoup(xml, "html.parser")
      for item in soup.find_all("item"):
         title = item.find("title").string
         description = item.find("description").string
         if title.find("[ PR ]") == -1:
            tenki.append(title)
            detail.append(description)

### Execute
# 抽出対象のRSS(神奈川県横浜市)
rssurl = "https://rss-weather.yahoo.co.jp/rss/days/4610.xml"

② お天気マークの追加

以前のプログラムでは、json形式の中にあるお天気マークを取り込むことが出来たのですが、Yahoo!天気の rss形式のデータには、お天気マークがないため、取り込むことができません。

そのため、自分でお天気マークを準備する必要があります。

60爺は、以下のようなお天気マークを作成しました。

準備が出来たら、お天気マーク用のフォルダを用意し格納します。

③ お天気マーク検索処理

次に、参考資料②のプログラムの一部を借用し、今日の天気、明日の天気から該当するお天気マークを検索する処理を作成します。

60爺は、お天気マーク検索後、出力ファイルに書き出すようにしました。

検索処理は次のようになりました(天気に該当しない文言が来た際、何故か「暴風雨」マークが出るので、確認したところ、「暴風雨」と「暴風雪」の判定条件に誤りがありましたので訂正しました)。

また、判定以外のデータが来たときは、404.jpg(上記お天気マークの先頭にある波のマークです)を表示するようにしました。おそらく、プログラミングミス以外はありえないはずですが‥。

## ck_Weather : 取得した天気情報とそれに応じたアイコンを出力するメソッド ################################
def ck_Weather(i, detail):

   if (detail[i].find("晴")) != -1 and (detail[i].find("曇")) == -1 and (detail[i].find("雨")) == -1 and (detail[i].find("雪")) == -1:
       files = icon_path + "Sun.jpg"

   elif (detail[i].find("晴一時曇")) != -1 or (detail[i].find("晴のち曇")) != -1 or (detail[i].find("晴時々曇")) != -1:
       files = icon_path + "SunToCloud.jpg"

   elif (detail[i].find("晴一時雨")) != -1 or (detail[i].find("晴のち雨")) != -1 or (detail[i].find("晴時々雨")) != -1:
       files = icon_path + "SunToRain.jpg"

   elif (detail[i].find("晴一時雪")) != -1 or (detail[i].find("晴のち雪")) != -1 or (detail[i].find("晴時々雪")) != -1:
       files = icon_path + "SunToSnow.jpg"

   elif (detail[i].find("曇")) != -1 and (detail[i].find("晴")) == -1 and (detail[i].find("雨")) == -1 and (detail[i].find("雪")) == -1:
       files = icon_path + "Cloud.jpg"

   elif (detail[i].find("曇一時晴")) != -1 or (detail[i].find("曇のち晴")) != -1 or (detail[i].find("曇時々晴")) != -1:
       files = icon_path + "CloudToSun.jpg"

   elif (detail[i].find("曇一時雨")) != -1 or (detail[i].find("曇のち雨")) != -1 or (detail[i].find("曇時々雨")) != -1:
       files = icon_path + "CloudToRain.jpg"

   elif (detail[i].find("曇一時雪")) != -1 or (detail[i].find("曇のち雪")) != -1 or (detail[i].find("曇時々雪")) != -1:
       files = icon_path + "CloudToSnow.jpg"

   elif (detail[i].find("雨")) != -1 and (detail[i].find("晴")) == -1 and (detail[i].find("曇")) == -1 and (detail[i].find("雪")) == -1:
       files = icon_path + "Rain.jpg"

   elif (detail[i].find("雨一時晴")) != -1 or (detail[i].find("雨のち晴")) != -1 or (detail[i].find("雨時々晴")) != -1:
       files = icon_path + "RainToSun.jpg"

   elif (detail[i].find("雨一時曇")) != -1 or (detail[i].find("雨のち曇")) != -1 or (detail[i].find("雨時々曇")) != -1:
       files = icon_path + "RainToCloud.jpg"

   elif (detail[i].find("雨一時雪")) != -1 or (detail[i].find("雨のち雪")) != -1 or (detail[i].find("雨時々雪")) != -1:
       files = icon_path + "RainToSnow.jpg"

   elif (detail[i].find("雪")) != -1 and (detail[i].find("晴")) == -1 and (detail[i].find("雨")) == -1 and (detail[i].find("曇")) == -1:
       files = icon_path + "Snow.jpg"

   elif (detail[i].find("雪一時晴")) != -1 or (detail[i].find("雪のち晴")) != -1 or (detail[i].find("雪時々晴")) != -1:
       files = icon_path + "SnowToSun.jpg"

   elif (detail[i].find("雪一時曇")) != -1 or (detail[i].find("雪のち曇")) != -1 or (detail[i].find("雪時々曇")) != -1:
       files = icon_path + "SnowToCloud.jpg"

   elif (detail[i].find("雪一時雨")) != -1 or (detail[i].find("雪のち雨")) != -1 or (detail[i].find("雪時々雨")) != -1:
       files = icon_path + "SnowToRain.jpg"

   elif (detail[i].find("暴風雨")) != -1:
       files = icon_path + "Typhon.jpg"

   elif (detail[i].find("暴風雪")) != -1:
       files = icon_path + "HeavySnow.jpg"

   else:
       files = icon_path + "404.jpg"


   print('icon=',files)
   if i == 0:
       cmd = "convert %s /home/pi/work/file3.jpg" % files
       res = subprocess.call( cmd.strip().split(" ") )
       print('file3.gif')
   else:
       cmd = "convert %s /home/pi/work/file5.jpg" % files
       res = subprocess.call( cmd.strip().split(" ") )
       print('file5.gif')

④ title 設定

title については、livedoorのようになっておらず、以下のような総合データが出てしまうので、リテラルで対応しました。

    title = u'神奈川県横浜の天気'

(2) その他の対応

① BeautifulSoup インストール

電光掲示板の表示を行っているラズパイは、天気予報読み上げのラズパイと違うものを使用しています。

このため、天気予報読み上げで実施した BeautifulSoup のインストールを実施しました。

sudo pip3 install beautifulsoup4

2.今日の最高気温、最低気温追加表示

天気予報読み上げで行ったように、今日の最高気温、最低気温追加表示を追加しようと思います。

そのため、天気予報表示用のシェルを見直したんですが、ちょっと面倒くさいことがわかりました。

その理由を述べていきます。

(1) 天気予報表示の手順

天気予報を電光掲示板に表示する手順は以下の通りです。

これらはシェルとして登録され、定時になると起動されます。

  • ファイル作成:10個のファイルを作成します。
  • txt→gif 変換:6個の txt ファイルを gif ファイルにコンバート
  • border 追加:見出しのファイルに枠を追加します
  • size change:border追加ファイル、今日、明日のお天気マークのサイズ変換
  • gif 連結:出来上がったファイル10個を連結して表示用ファイル作成
  • 天気予報表示:表示用ファイルを電光掲示板に流す
  • LED PANEL RESET:電光掲示板リセット

1.で述べたプログラムは、手順の一番頭にあるファイル作成です。上述したように10個のファイルを作成しています。

ここで出来たファイルを、gif変換、枠付けやサイズ変更を行い、最後に連結して電光掲示板表示用のファイルを作成しているわけです。

(2) 表示内容の追加による変更箇所

今日の最高気温、最低気温の2項目を追加するには次の変更が必要です。

① ファイル作成プログラム変更

今日の最高気温、最低気温は、明日の最高気温、最低気温と同じように気温により、文字色を変える必要があります。

そのため、今日の最高気温、最低気温を出力ファイル(gif)として追加します。

そして、これら2つの気温を表示するため、テキスト内容に変更が発生するので、ファイル出力(訂正)が必要です。

以下、出力ファイルの一覧にまとめます。結局、ファイル出力は 10 ⇒ 14 となり、4つのファイル追加になりました。

テキストファイル訂正は、ひとつで済みました。

file1.txt”8月20日、17時0分20秒 神奈川県横浜の天気”
file2.txt”今日の天気は”
file3.jpg今日の天気の天気マーク
file4.txt”です。今日の予想最高気温”訂正
file4_1.gif今日の最高気温(色付き)追加
file4_2.txt”、予想最低気温”追加
file4_3.gif今日の最低気温(色付き)追加
file4_4.txt”です。明日の天気は”追加
file5.jpg明日の天気の天気マーク
file6.txt”です。明日の予想最高気温”
file7.gif明日の最高気温(色付き)
file8.txt”、予想最低気温”
file9.gif明日の最低気温(色付き)
file10.txt”です。”

② シェル変更

・ txt→gif 変換

上記一覧で追加となった file4_2.txt 及び file4_4.txt の gif 変換を追加します。

・ gif 連結

追加したファイルを連結するので訂正が発生します。

ファイルの連結純は次の通りです。これらを連結した結果が、電光掲示板表示用ファイル tenki.gif となります。

file1_border1.gif + file2.gif + file3_2.jpg +
file4.gif + file4_1.gif + file4_2.gif +
4_3.gif + file4_4.gif + file5_2.jpg + file6.gif +
file7.gif + file8.gif + file9.gif + file10.gif

3.ソースコード

(1) シェル tenki_new.sh

訂正の終了したシェルのソースです。

# file product
python3 /home/pi/python-pg/tenki_file.py

# text --> gif
convert -background black -fill green -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file1.txt /home/pi/work/file1.gif

convert -background black -fill yellow -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file2.txt /home/pi/work/file2.gif

convert -background black -fill yellow -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file4.txt /home/pi/work/file4.gif

convert -background black -fill yellow -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file4_2.txt /home/pi/work/file4_2.gif

convert -background black -fill yellow -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file4_4.txt /home/pi/work/file4_4.gif

convert -background black -fill yellow -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file6.txt /home/pi/work/file6.gif

convert -background black -fill yellow -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file8.txt /home/pi/work/file8.gif

convert -background black -fill yellow -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:@/home/pi/work/file10.txt /home/pi/work/file10.gif
echo "convert end"
# gif1 add border
convert   -border 1x1 -bordercolor red /home/pi/work/file1.gif /home/pi/work/file1_border.gif

echo "add border end"

# gif --> size change
convert /home/pi/work/file1_border.gif -resize x16 /home/pi/work/file1_border1.gif

convert /home/pi/work/file3.jpg -resize x16 /home/pi/work/file3_2.jpg

convert /home/pi/work/file5.jpg -resize x16 /home/pi/work/file5_2.jpg

echo "size change end"
# file add
convert +append /home/pi/work/file1_border1.gif /home/pi/work/file2.gif /home/pi/work/file3_2.jpg /home/pi/work/file4.gif /home/pi/work/file4_1.gif /home/pi/work/file4_2.gif /home/pi/work/file4_3.gif /home/pi/work/file4_4.gif /home/pi/work/file5_2.jpg /home/pi/work/file6.gif /home/pi/work/file7.gif /home/pi/work/file8.gif /home/pi/work/file9.gif /home/pi/work/file10.gif /home/pi/work/tenki.gif

# imagescroller
sudo timeout 60 sudo python3 /home/pi/rpi-rgb-led-matrix/bindings/python/samples/image-scroller.py -r 16 --led-no-hardware-pulse yes -c 2  -i /home/pi/work/tenki.gif

#demo run for LED PANEL reset
sudo /home/pi/rpi-rgb-led-matrix/examples-api-use/demo -D 1 -t 1 /home/pi/rpi-rgb-led-matrix/examples-api-use/runtext16.ppm --led-rows=16 --led-no-hardware-pulse --led-chain=2

(2) ファイル作成プログラム

訂正の終わったファイル作成プログラムです。

#!/usr/bin/env python3
# -*- coding:utf-8 -*-

from datetime import datetime

import  urllib.request
from bs4 import BeautifulSoup

import shlex
import subprocess

def main():
    print ('start')
    txt_weather()
    return

def file_out(name,naiyo):

    f = open(name,'w')
    f.write(naiyo)
    f.close()

    return

def img_file_out(color, ondo, file):

    print(color,ondo,file)

    cmd = "convert -background black -fill %s -font /usr/share/fonts/truetype/fonts-japanese-gothic.ttf -pointsize 16 label:%s℃ /home/pi/work/%s.gif" % (color, ondo , file)

    try:
        res = subprocess.call( cmd.strip().split(" ") )
    except:
        print("Error. test")

    return

def txt_weather():

    weather_text = u'%sの天気は'
    temperature_text = u'です。%sの予想最高気温、%s℃、予想最低気温、%s℃です。'
    file4_01text = 'です。今日の予想最高気温 '
    file6_text = 'です。明日の予想最高気温 '
    file8_text = '、予想最低気温 '
    file10_text = 'です。'

    Parser(rssurl) # 天気予報サイトのHTMLタグから天気情報を抽出

    for i in range(0,2):
        detail2 = detail[i].split()
        print("dtail -= ",detail2)
        if i == 0:
    # TODAY
             kyo_tenki = detail2[i]
             temp = detail2[2].split('/')
             kyo_max = temp[0].split('℃')
             kyo_min = temp[1].split('℃')
             ck_Weather(i, detail)
             file4_13_out(kyo_max[0],kyo_min[0])
        else:
    # TOMMOROW
             asu_tenki = detail2[i]
             temp = detail2[2].split('/')
             temp_num_max = temp[0].split('℃')
             temp_num_min = temp[1].split('℃')
             ck_Weather(i, detail)
             file7_9_out(temp_num_max[0],temp_num_min[0])

    title = u'神奈川県横浜の天気'

    d = datetime.now()
    text_day = '%s月%s日、%s時%s分%s秒' % (d.month, d.day, d.hour, d.minute, d.second)

    today_w_txt = weather_text % '今日'
    tommorow_w_txt = weather_text % '明日'
    # text_file set & out
    file1_text = text_day + ' ' + title + ' '
    file2_text = today_w_txt + ' '
    file4_text = file4_01text + ' '
    file4_4text = file10_text + tommorow_w_txt + ' '

    file_out("/home/pi/work/file1.txt",file1_text)
    file_out("/home/pi/work/file2.txt",file2_text)
    file_out("/home/pi/work/file4.txt",file4_text)
    file_out("/home/pi/work/file4_2.txt",file8_text)
    file_out("/home/pi/work/file4_4.txt",file4_4text)
    file_out("/home/pi/work/file6.txt",file6_text)
    file_out("/home/pi/work/file8.txt",file8_text)
    file_out("/home/pi/work/file10.txt",file10_text)

    return

## ck_Weather : 取得した天気情報とそれに応じたアイコンを出力するメソッド ################################
def ck_Weather(i, detail):

   if (detail[i].find("晴")) != -1 and (detail[i].find("曇")) == -1 and (detail[i].find("雨")) == -1 and (detail[i].find("雪")) == -1:
       files = icon_path + "Sun.jpg"

   elif (detail[i].find("晴一時曇")) != -1 or (detail[i].find("晴のち曇")) != -1 or (detail[i].find("晴時々曇")) != -1:
       files = icon_path + "SunToCloud.jpg"

   elif (detail[i].find("晴一時雨")) != -1 or (detail[i].find("晴のち雨")) != -1 or (detail[i].find("晴時々雨")) != -1:
       files = icon_path + "SunToRain.jpg"

   elif (detail[i].find("晴一時雪")) != -1 or (detail[i].find("晴のち雪")) != -1 or (detail[i].find("晴時々雪")) != -1:
       files = icon_path + "SunToSnow.jpg"

   elif (detail[i].find("曇")) != -1 and (detail[i].find("晴")) == -1 and (detail[i].find("雨")) == -1 and (detail[i].find("雪")) == -1:
       files = icon_path + "Cloud.jpg"

   elif (detail[i].find("曇一時晴")) != -1 or (detail[i].find("曇のち晴")) != -1 or (detail[i].find("曇時々晴")) != -1:
       files = icon_path + "CloudToSun.jpg"

   elif (detail[i].find("曇一時雨")) != -1 or (detail[i].find("曇のち雨")) != -1 or (detail[i].find("曇時々雨")) != -1:
       files = icon_path + "CloudToRain.jpg"

   elif (detail[i].find("曇一時雪")) != -1 or (detail[i].find("曇のち雪")) != -1 or (detail[i].find("曇時々雪")) != -1:
       files = icon_path + "CloudToSnow.jpg"

   elif (detail[i].find("雨")) != -1 and (detail[i].find("晴")) == -1 and (detail[i].find("曇")) == -1 and (detail[i].find("雪")) == -1:
       files = icon_path + "Rain.jpg"

   elif (detail[i].find("雨一時晴")) != -1 or (detail[i].find("雨のち晴")) != -1 or (detail[i].find("雨時々晴")) != -1:
       files = icon_path + "RainToSun.jpg"

   elif (detail[i].find("雨一時曇")) != -1 or (detail[i].find("雨のち曇")) != -1 or (detail[i].find("雨時々曇")) != -1:
       files = icon_path + "RainToCloud.jpg"

   elif (detail[i].find("雨一時雪")) != -1 or (detail[i].find("雨のち雪")) != -1 or (detail[i].find("雨時々雪")) != -1:
       files = icon_path + "RainToSnow.jpg"

   elif (detail[i].find("雪")) != -1 and (detail[i].find("晴")) == -1 and (detail[i].find("雨")) == -1 and (detail[i].find("曇")) == -1:
       files = icon_path + "Snow.jpg"

   elif (detail[i].find("雪一時晴")) != -1 or (detail[i].find("雪のち晴")) != -1 or (detail[i].find("雪時々晴")) != -1:
       files = icon_path + "SnowToSun.jpg"

   elif (detail[i].find("雪一時曇")) != -1 or (detail[i].find("雪のち曇")) != -1 or (detail[i].find("雪時々曇")) != -1:
       files = icon_path + "SnowToCloud.jpg"

   elif (detail[i].find("雪一時雨")) != -1 or (detail[i].find("雪のち雨")) != -1 or (detail[i].find("雪時々雨")) != -1:
       files = icon_path + "SnowToRain.jpg"

   elif (detail[i].find("暴風雨")) != -1:
       files = icon_path + "Typhon.jpg"

   elif (detail[i].find("暴風雪")) != -1:
       files = icon_path + "HeavySnow.jpg"

   else:
       files = icon_path + "404.jpg"


   print('icon=',files)
   if i == 0:
       cmd = "convert %s /home/pi/work/file3.jpg" % files
       res = subprocess.call( cmd.strip().split(" ") )
       print('file3.gif')
   else:
       cmd = "convert %s /home/pi/work/file5.jpg" % files
       res = subprocess.call( cmd.strip().split(" ") )
       print('file5.gif')

def file4_13_out(temp_max,temp_min):
# max temp  file7
    if int(temp_max) >= 25:
        img_file_out("red", temp_max, "file4_1")
    elif int(temp_max) >= 20:
        img_file_out("orange", temp_max, "file4_1")
    else:
        img_file_out("yellow", temp_max, "file4_1")

    # mix temp  file9
    if int(temp_min) < 5:
        img_file_out("white", temp_min, "file4_3")
    elif int(temp_min) < 10:
        img_file_out("blue", temp_min, "file4_3")
    else:
        img_file_out("yellow", temp_min, "file4_3")

def file7_9_out(temp_max,temp_min):
# max temp  file7
    if int(temp_max) >= 25:
        img_file_out("red", temp_max, "file7")
    elif int(temp_max) >= 20:
        img_file_out("orange", temp_max, "file7")
    else:
        img_file_out("yellow", temp_max, "file7")

    # mix temp  file9
    if int(temp_min) < 5:
        img_file_out("white", temp_min, "file9")
    elif int(temp_min) < 10:
        img_file_out("blue", temp_min, "file9")
    else:
        img_file_out("yellow", temp_min, "file9")

## Parser : 天気情報WebページのHTMLタグから天気情報を抽出してパースするメソッド ####################
def Parser(rssurl):
   with urllib.request.urlopen(rssurl) as res:
      xml = res.read()
      soup = BeautifulSoup(xml, "html.parser")
      for item in soup.find_all("item"):
         title = item.find("title").string
         description = item.find("description").string
         if title.find("[ PR ]") == -1:
            tenki.append(title)
            detail.append(description)

### Execute

icon_path ="/home/pi/work/tenki_mark/"

# 抽出対象のRSS(神奈川県横浜市)
rssurl = "https://rss-weather.yahoo.co.jp/rss/days/4610.xml"

tenki = []
detail = []
detail2 = []
temp = []
temp_num_max = []
temp_num_min = []
kyo_max = []
kyo_min = []

if __name__ == "__main__":
    main()