yahoo!天気rssデータと天気マーク追加で電光掲示板天気予報表示PGリプレース

2020年10月6日

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

天気予報の配信が次々と止まり、その度ごとに手を入れるのは面倒くさくてしようがないんですが使用がありません。

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

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

是非、内容をご覧ください。

スポンサーリンク

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

さて、電光掲示板天気予報プログラムの訂正箇所ですが次の通りです。

  1. データ取出し部分
  2. お天気マーク追加
  3. お天気マーク検索処理
  4. title訂正
  5. その他の対応

それぞれの訂正箇所について細かく解説します。

データ取出し部分

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爺は、お天気マーク検索後、出力ファイルに書き出すようにしました。

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

## 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')

また、判定以外のデータが来たときは、404.jpg(上記お天気マークの先頭にある波のマークです)を表示するようにしました。

おそらく、プログラミングミス以外はありえないはずですが‥。

title 設定

title については、先のプログラムリプレースでも述べましたが、livedoorのようになっていないためリテラルで対応しました。

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

その他の対応

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

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

sudo pip3 install beautifulsoup4

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

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

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

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

天気予報表示の手順

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

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

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

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

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

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

  1. ファイル作成プログラム変更
  2. txt→gif 変換
  3. gif 連結

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

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

そのため、今日の最高気温、最低気温を出力ファイル(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

スポンサーリンク

ソースコード

最後に、訂正終了後のシェルとファイル作成プログラムを掲載します。

シェル 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

ファイル作成プログラム

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

#!/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()

最後に

Livedoorの天気予報データ配信が終了したことで、電光掲示板天気予報表示の訂正を余儀なくされました。

そのため、yahoo!天気rssデータと天気マークを追加することで電光掲示板天気予報表示プログラムのリプレースを行いました。

今回、そこで実施した内容を掲載しています。

これで、ようやく、電光掲示板の天気予報表示が正しくなりました。

※気づけば電光掲示板の記事も増えてきました

スポンサーリンク
この記事を書いた人

60爺

60路を越え、RaspberryPi と出会い、その関係でブログ開設(2017/2~)となりました。始めてみると、コツコツやるのが性に合ってしまい、漢字の記事から家の補修・将棋・windows10関係・別名・言い方などジャンルを拡大して今に至ってます。まだまだ、元気なので新たな話題を見つけて皆様に提供できればと思っています。「プロフィールはこちら

電光掲示板

Posted by 60爺