js: play with ordering. this all doesn't seem to work with timeseries charts.
[chrisu/seepark.git] / owm.py
1 #!/usr/bin/python3
2
3 # needs ~/seepark.ini with
4 # [openweathermap]
5 # apikey=...
6 # cityid=..
7 # 3319578 for Obsteig, AT
8
9 from pprint import pprint
10 import argparse
11 import configparser
12 import os
13 import csv
14 import datetime
15 import math
16 import json
17 import warnings
18 import sqlalchemy
19 from sqlalchemy import create_engine
20 import MySQLdb.cursors
21 from seeparklib.openweathermap import openweathermap_json
22
23
24 def fromtimestamp(timestamp):
25     return datetime.datetime.fromtimestamp(timestamp)
26
27
28 # https://stackoverflow.com/questions/7490660/converting-wind-direction-in-angles-to-text-words
29 def degToCompass(num):
30     if num is None or num is math.nan:
31         return 'N/A'
32     val=int((num/22.5)+.5)
33     arr=["N","NNO","NO","ONO","O","OSO", "SO", "SSO","S","SSW","SW","WSW","W","WNW","NW","NNW"]
34     return arr[(val % 16)]
35
36
37 def extractweatherdata(w):
38     data = dict(
39         datetime = fromtimestamp(w['dt']),
40         sunrise = fromtimestamp(w['sys']['sunrise']),
41         sunset = fromtimestamp(w['sys']['sunset']),
42         temp = w['main']['temp'],
43         pressure = w['main']['pressure'],
44         humidity = w['main']['humidity'],
45         weather = w['weather'][0]['description'],
46         sky = w['weather'][0]['main'],
47         windspeed = w['wind']['speed'],
48         cloudiness = w['clouds']['all'],
49     )
50
51     data['winddegrees'] = w['wind']['deg'] if 'deg' in w['wind'] else math.nan
52     data['winddirection'] = degToCompass(data['winddegrees'])
53     data['precipitation'] = w['rain']['3h'] if 'rain' in w else math.nan
54     data['visibility'] = w.get('visibility', math.nan)
55
56     return data
57
58
59 def write_csv(csv_file, weather_data):
60     """output like wetter.at.pl"""
61     with open(csv_file, "a", newline="") as file:
62         writer = csv.writer(file, dialect="excel", delimiter=';')
63         writer.writerow([
64             weather_data['datetime'].date(),
65             weather_data['datetime'].time(),
66             weather_data['sunrise'].time(),
67             weather_data['sunset'].time(),
68             "{:.2f}".format(weather_data['temp']),
69             "{:.2f} mm/h".format(weather_data['precipitation']),
70             "{:.1f} km/h {}".format(weather_data['windspeed'], weather_data['winddirection']),
71             weather_data['weather'],
72             "{}".format(weather_data['cloudiness'])
73         ])
74
75
76 def write_db(config, url, weather_json, weather_data):
77     user = config.get('database', 'user')
78     pwd = config.get('database','password')
79     host = config.get('database','hostname')
80     db = config.get('database','database')
81
82     engine = create_engine('mysql+mysqldb://{}:{}@{}/{}'.format(user, pwd, host, db), echo=False)
83     conn = engine.connect()
84     row = dict(cityid=config.get('openweathermap', 'cityid'), url=url, result=json.dumps(weather_json))
85     row.update(weather_data)
86     for key, value in row.items():
87         if isinstance(value, float) and math.isnan(value):
88             row[key] = None
89     sql_columns = list(row.keys())
90     sql_values = list(row.values())
91     sql = 'insert ignore into openweathermap ({}) values ({})'.format(', '.join(sql_columns), ','.join(['%s'] * len(sql_columns)))
92     with warnings.catch_warnings():
93         # ignore _mysql_exceptions.Warning: Duplicate entry '3319578-2018-08-01 20:50:00' for key 'cityid_datetime'
94         warnings.simplefilter("ignore", category=MySQLdb.cursors.Warning)
95         conn.execute(sql, *sql_values)
96     conn.close()
97
98
99 def main(configfile, debug):
100     config = configparser.ConfigParser()
101     config.read(configfile)
102     apikey = config.get('openweathermap', 'apikey')
103     cityid = config.get('openweathermap', 'cityid')
104     csvfile = config.get("openweathermap", 'csvfilename')
105
106     url, weather_json = openweathermap_json(apikey, cityid)
107     if debug:
108         pprint(weather_json)
109     weather_data = extractweatherdata(weather_json)
110     if debug:
111         pprint(weather_data)
112
113     # write to db
114     write_db(config, url, weather_json, weather_data)
115
116     # write to csv
117     write_csv(os.path.expanduser(csvfile), weather_data)
118
119
120 if __name__ == '__main__':
121     default_config_file = os.path.expanduser('~/seewasser.ini')
122     parser = argparse.ArgumentParser(description='Get OpenWeathermap data')
123     parser.add_argument('--config', default=default_config_file, help='configuration file')
124     parser.add_argument('--debug', action='store_true', default=False, help='print debug information')
125     args = parser.parse_args()
126     main(args.config, args.debug)