Send daily email with predictions
Tags: #openweathermap #weather #plotly #prediction #email #naas_drivers #automation
Author: Gautier Vivard

Input

Import libraries

1
import requests
2
import markdown2
3
import time
4
import pandas as pd
5
import naas
6
from naas_drivers import plotly, prediction
Copied!

Setup your open weather info

1
OPENWEATHER_KEY = '***************' # get your key from here https://home.openweathermap.org/api_keys (it takes couples of minutes)
2
city = 'rouen'
3
country_code = 'fr' # if you don't want to specify a country code, let ''
Copied!
1
# Output paths image and html
2
output_image = f'{city}.png'
3
output_html = f'{city}.html'
Copied!

Input email parameter

1
email_to = ["[email protected]"]
2
email_from = None
3
subject = f'{city} predictions as of today'
Copied!

Schedule every day

1
# naas.scheduler.add(cron='0 8 * * *')
2
# naas.scheduler.delete()
Copied!

Model

Get the data from open weather map

The historical open weather api need the latitude, longitude in order to have the data
1
def get_geoloc(city: str, country_code: str = ''):
2
""" Get the geoloc of a city, country
3
4
:param city: name of the city
5
:type city: str
6
:param country_code: Please use ISO 3166 country codes, default to ''
7
:type country_code: str
8
"""
9
url = f'http://api.openweathermap.org/geo/1.0/direct?q={city},,{country_code}&appid={OPENWEATHER_KEY}'
10
return requests.get(url).json()
11
12
def get_lat_lon(city: str, country_code: str = ''):
13
""" Get the geoloc of a city, country
14
15
:param city: name of the city
16
:type city: str
17
:param country_code: Please use ISO 3166 country codes, default to ''
18
:type country_code: str
19
"""
20
geoloc = get_geoloc(city, country_code)
21
22
if len(geoloc) == 0:
23
return None, None
24
25
return geoloc[0]['lat'], geoloc[0]['lon']
26
27
# get_lat_lon('paris')
28
# get_lat_lon('paris', 'us')
Copied!
1
def get_historical_weather(city: str, country_code: str = '', nbr_days_before_now: int = 0):
2
"""Get historical weather data. For free API, maximum history is 5 days before now
3
4
:param city: name of the city
5
:type city: str
6
:param country_code: Please use ISO 3166 country codes, default to ''
7
:type country_code: str
8
:param nbr_hours_before_now: number of hour before now
9
"""
10
unix_dt = int(time.time() - 60 * 60 * 24 * nbr_days_before_now)
11
lat, lon = get_lat_lon(city, country_code)
12
if lat is None:
13
return None
14
url = f'https://api.openweathermap.org/data/2.5/onecall/timemachine?lat={lat}&lon={lon}&dt={unix_dt}&appid={OPENWEATHER_KEY}&units=metric'
15
return requests.get(url).json()
16
17
def weather_data_to_df(city: str, country_code: str = '', nbr_days_before_now: int = 0) -> pd.DataFrame:
18
data = get_historical_weather(city, country_code, nbr_days_before_now)
19
df = pd.DataFrame(data['hourly'])
20
df['date_time'] = pd.to_datetime(df['dt'], unit='s')
21
df['city'] = city
22
df['country_code'] = country_code
23
24
df_explode_weather = pd.concat([df.drop(['weather', 'dt'], axis=1), df['weather'].str[0].apply(pd.Series)], axis=1)
25
# df_explode_weather.set_index('date_time', inplace=True)
26
return df_explode_weather
Copied!
1
df_histo_weather = pd.concat([weather_data_to_df(city, country_code, _) for _ in range(6)], ignore_index=True)
2
df_histo_weather = df_histo_weather.sort_values(by='date_time').reset_index(drop=True).rename(columns={"date_time": "Date"})
3
df_histo_weather
Copied!

Add prediction column

1
df_predict = prediction.get(dataset=df_histo_weather,
2
date_column='Date',
3
column="temp",
4
data_points=5,
5
prediction_type="all")
6
7
df_predict
Copied!

Build chart

1
chart = plotly.linechart(df_predict,
2
x='Date',
3
y=['temp', 'ARIMA', "LINEAR", "SVR", "COMPOUND"],
4
showlegend=True,
5
title=f'Temp in {city} last 5 days')
Copied!

Output

Create markdown template

1
%%writefile message.md
2
Hey
3
4
The *CITY* temperature on the last 5 days
5
6
In +2 days, basic ML models predict the following temperature:
7
8
- *linear*: LINEAR
9
10
11
<img href=link_html target="_blank" src=link_image style="width:640px; height:360px;" /><br>
12
[Open dynamic chart](link_html)<br>
13
14
15
Have a nice day.
16
<br>
17
18
PS: You can [send the email again](link_webhook) if you need a fresh update.<br>
19
<div><strong>Full Name</strong></div>
20
<div>Open source lover | <a href="http://www.naas.ai/" target="_blank">Naas</a></div>
Copied!

Save as html and png

1
chart.write_html(output_html)
2
chart.write_image(output_image, width=1200)
Copied!

Expose chart

1
link_image = naas.asset.add(output_image)
2
link_html = naas.asset.add(output_html, {'inline': True})
Copied!

Add webhook to run your notebook again

1
link_webhook = naas.webhook.add()
Copied!

Create email content

1
markdown_file = "message.md"
2
content = open(markdown_file, "r").read()
3
md = markdown2.markdown(content)
4
md
Copied!
1
post = md.replace("DATANOW", str(DATANOW))
2
post = post.replace("CITY", str(city))
3
post = post.replace("LINEAR", str(LINEAR))
4
post = post.replace("link_image", str(link_image))
5
post = post.replace("link_html", str(link_html))
6
post = post.replace("link_webhook", str(link_webhook))
7
post
Copied!

Send email

1
content = post
2
naas.notification.send(email_to=email_to,
3
subject=subject,
4
html=content,
5
files=files,
6
email_from=email_from)
Copied!

Add email template as a dependency

1
naas.dependency.add("message.md")
Copied!
Copy link
Edit on GitHub