I have a 2-year-old child, so I watch E-Tele every morning, but the weather doesn't come out on E-Tele. I'm switching channels back and forth to news programs just to see the weather, so I'm going to make a simple app that gets the weather from the weather API and pushes it to LINE. It's a year-end killing time Of course within the free range
I've never used GitHub Actions, so I'm trying it out However, since I only use the cron function, I think that the GAS trigger function is easier and better if this is all.
Created from here https://developers.line.biz/ja/services/messaging-api
Also, since there is a QR code of the application registered on the management screen of LINE Developer, register it as a friend.
Let me use the OpenWeatherMap API
Create an account here https://home.openweathermap.org/users/sign_up
import os
import json
import pandas as pd
from dotenv import load_dotenv
from urllib.request import urlopen
from datetime import datetime
from pytz import timezone
from linebot import LineBotApi
from linebot.models import TextSendMessage
def get_weather_icon(icon_str):
if icon_str == "01d" or icon_str == "01n":
return "☀️"
elif (
icon_str == "02d"
or icon_str == "02n"
or icon_str == "03d"
or icon_str == "03n"
or icon_str == "04d"
or icon_str == "04n"
):
return "☁️"
elif (
icon_str == "09d" or icon_str == "09n" or icon_str == "10d" or icon_str == "10n"
):
return "☂️"
elif icon_str == "11d" or icon_str == "11n":
return "⚡️"
elif icon_str == "13d" or icon_str == "13n":
return "☃️"
else:
return ""
def send_to_line(df):
texts = []
for k, v in df:
texts.append(f"【{k}】")
for _, d in v.iterrows():
texts.append(
f"{d['time']}Time{get_weather_icon(d['icon'])} {d['temp']}(℃) {d['rain']}(mm/3h)"
)
texts.append("")
line_bot = LineBotApi(os.getenv("LINE_ACCESS_TOKEN"))
line_bot.push_message(
os.getenv("LINE_USER_ID"), TextSendMessage(text="\n".join(texts))
)
def main():
url = "http://api.openweathermap.org/data/2.5/forecast"
id = os.getenv("OWM_PLACE_ID")
api_key = os.getenv("OWM_API_KEY")
res = urlopen(f"{url}?id={id}&appid={api_key}&lang=ja&units=metric").read()
res_json = json.loads(res)
arr_rj = []
for rj in res_json["list"]:
conv_rj = {}
timestamp = timezone("Asia/Tokyo").localize(datetime.fromtimestamp(rj["dt"]))
conv_rj["date"] = timestamp.strftime("%m/%d %a")
conv_rj["time"] = timestamp.strftime("%H")
conv_rj["description"] = rj["weather"][0]["description"]
conv_rj["icon"] = rj["weather"][0]["icon"]
conv_rj["temp"] = round(rj["main"]["temp"])
conv_rj["rain"] = round(rj["rain"]["3h"], 1) if "rain" in rj else 0
arr_rj.append(conv_rj)
send_to_line(pd.DataFrame(arr_rj).groupby("date"))
load_dotenv()
main()
When you execute the above code, the app you registered earlier will be notified as follows.
Since there are many processes that process messages, it is rather long if you look only at the code, but if you only process the weather information acquisition and push to LINE, it will be as follows. I'm using python-dotenv to set secure information such as tokens in environment variables
Get weather information (JSON format) from OpenWeatherMap API
def main():
url = "http://api.openweathermap.org/data/2.5/forecast"
id = os.getenv("OWM_PLACE_ID")
api_key = os.getenv("OWM_API_KEY")
res = urlopen(f"{url}?id={id}&appid={api_key}&lang=ja&units=metric").read()
...
This time, I just wanted to know the weather only where I live, so I passed the ID of the area where I live directly to the parameter ʻid. You can check the region ID by downloading
city.list.json.gz from [here](http://bulk.openweathermap.org/sample/). In addition to ʻid
, it is also possible to specify lat
(latitude), lon
(longitude), and zip
(zip code) as parameters to get the result (this app is compatible Is not)
You can check the API_KEY from here
Push a message to LINE
def send_to_line(df):
...
line_bot = LineBotApi(os.getenv("LINE_ACCESS_TOKEN"))
line_bot.push_message(
os.getenv("LINE_USER_ID"), TextSendMessage(text="Hello")
LINE_ACCESS_TOKEN can be issued from the management screen of LINE Developer You can also check LINE_USER_ID from the same management screen.
At the time of writing this article, I thought that everyone who registered the created weather app as a friend would be notified of the message, but with the above method, only I will be notified of the message. (I'm sorry, I made it without checking that area at all.)
Write a procedure to send to people other than yourself To send to someone other than yourself, you only need to know the UserID of the sender, but it is a little troublesome to know.
When a person who wants to know the UserID registers an app as a friend
, Line sends a callback function prepared by us with a Post request and confirms it in that function.
I think there are various ways, but I will write the way I did below
Made with GAS
var SLACK_ACCESS_TOKEN = ''
function doPost(e) {
SlackApp.create(SLACK_ACCESS_TOKEN).postMessage(
'#event-line',
JSON.stringify(e),
{ username: 'kurosame-gas' }
)
}
You can also check it with console.log (e)
, but since it is troublesome to open GAS and check each time, I notify Slack.
ʻE` contains information such as UserID
You can publish as Web API from Publish-> Introduce as Web Application
from the GAS screen.
At this time, the disclosure range should be everyone (including anonymous)
Make a note of the URL of the app as it will appear on the screen when you publish it.
You can set it on the LINE Developer management screen as follows.
It's okay if you run Verify and get SUCCESSBy the way, please also set the following to Disabled on the same screen
If you send a character on the talk screen of the created Line app and the character and information such as your UserID reach Slack, it is successful. Also, if someone else registers your app as a friend, Slack will be notified so you can get that person's UserID.
#Change before
line_bot.push_message(
os.getenv("LINE_USER_ID"), TextSendMessage(text="\n".join(texts))
)
#After change
line_bot.multicast(
os.getenv("LINE_USER_ID").split(","), TextSendMessage(text="\n".join(texts))
)
Set UserID for LINE_USER_ID separated by commas.
Use the cron feature of GitHub Actions to set the weather to notify you every morning at 7am
Below is the yaml file that Actions loads
You can use GitHub Actions just by putting the following files in the directory .github / workflows
on the root directory.
name: Weather
on:
schedule:
- cron: '00 22 * * *' # UTC
jobs:
weather:
name: Run weather
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: 3.7
- name: Install Pipenv
uses: dschep/install-pipenv-action@v1
- name: Install dependencies
run: pipenv sync
- name: Run weather
env:
OWM_PLACE_ID: ${{ secrets.OWM_PLACE_ID }}
OWM_API_KEY: ${{ secrets.OWM_API_KEY }}
LINE_ACCESS_TOKEN: ${{ secrets.LINE_ACCESS_TOKEN }}
LINE_USER_ID: ${{ secrets.LINE_USER_ID }}
run: pipenv run python3 ./bots/weather.py
I'm using environment variables in my Python code, so I need to make them available on the Actions server.
You can set environment variables that can be used in Actions from the Settings tab-> Secrets
in the GitHub repository.
And as mentioned above, we use the secrets context to allow runners to use environment variables.
After using it, I was a little worried that the workflow is executed 5 to 6 minutes later than the time specified by cron.
My wife also uses LINE on a regular basis, so it seems that this app will be used. (When I used the memo app that can be operated on Slack before, it was troublesome to start Slack and I stopped using it)
The code implemented this time is given below https://github.com/kurosame/bots-python