Skip to content

Instantly share code, notes, and snippets.

@nick3499
Last active April 29, 2022 23:43
Show Gist options
  • Save nick3499/10aa037bab43dbcc0072be739aa0744c to your computer and use it in GitHub Desktop.
Save nick3499/10aa037bab43dbcc0072be739aa0744c to your computer and use it in GitHub Desktop.
Display weather data from Timeline API in terminal emulator; Python 3; json, pendulum.parse

README

Import Module Methods

from json import loads
from pendulum import parse
from requests import get
from os import environ
  • json.load() takes the read_file object and returns the json object which contains the weather data from Timeline API
  • pendulum.parse() method is used to parse formatted strings based on ISO 8601
  • requests.get() sends a GET request to the URL
  • os.environ() maps environmental variables as a dictionary

pendulum.parse() example: {grn}Time{res} {parse(cc['datetime']).format('h:mm A')}

Text Color Formats

red = '\x1b[31m'
grn = '\x1b[32m'
blu = '\x1b[34m'
res = '\x1b[0m'

The color format variables above help to keep cryptic text-formatting codes out of view and make associated f-strings appear more human-readable to coders (see Print Data to Terminal section):

{grn}Time{res} {parse(cc['datetime']).format('h:mm A')}

Get Open Weather Data

response = get(f'https://weather.visualcrossing.com/\
VisualCrossingWebServices/rest/services/timeline/{environ["GEO_COORDS"]}\
?key={environ["TIMELINE_API_KEY"]}').text
data = loads(response)

This object accesses sunrise data: data['currentConditions']['sunrise']

Obfuscate Environmental Variables

The two environmental variables in the URL above can be stored in the /etc/environment file which can be accessed using the os.environ() method.

Print Data to Terminal

The following is an example of how to print weather data for current conditions to the terminal emulator display. Such multi-line f-strings were used to minimize excessive print calls.

current_conditions = data['currentConditions']
print(f'''\
{grn}Time{res}           {parse(current_conditions['datetime']).format('h:mm A')}
{grn}Description{res}    {current_conditions['conditions']}
{grn}Temperature{res}    {current_conditions['temp']}
{grn}Feels like{res}     {current_conditions['feelslike']}
{grn}Humidity{res}       {current_conditions['humidity']}%
{grn}Dew point{res}      {current_conditions['dew']}
{grn}Precipitation{res}  {current_conditions['precip']}
{grn}Precip. prob.{res}  {current_conditions['precipprob']}
{grn}Snow{res}           {current_conditions['snow']}
{grn}Snow depth{res}     {current_conditions['snowdepth']}
{grn}Precip. type{res}   {current_conditions['preciptype']}
{grn}Wind gust{res}      {current_conditions['windgust']}
{grn}Wind speed{res}     {current_conditions['windspeed']}
{grn}Wind Direction{res} {current_conditions['winddir']}
{grn}Air pressure{res}   {current_conditions['pressure']}
{grn}Visibility{res}     {current_conditions['visibility']}mi
{grn}Cloud cover{res}    {current_conditions['cloudcover']}
{grn}UV index{res}       {current_conditions['uvindex']}
{grn}Sunrise{res}        {parse(data['currentConditions']['sunrise']).format('h:mm A')}
{grn}Sunset{res}         {parse(data['currentConditions']['sunset']).format('h:mm A')}
{grn}Moon phase{res}     {current_conditions['moonphase']}''')

Try/Except Block

On days during which there are no weather alerts, a try/except block can be used to handle any IndexError which occurs.

try:
    alerts = data['alerts'][0]
    ends = parse(alerts['ends'])
    print(f'''\
{red}Alerts{res} {alerts['event'].upper()}
{red}Headline{res}\n{alerts['headline']}
{red}Description{res}\n{alerts['description']}
{red}Ends{res}   {ends.format('dddd D MMMM YYYY hh:mm A')}
{blu}========= CURRENT =========={res}''')
except IndexError:
    print(f'''There are no alerts at this time.
{blu}========= CURRENT =========={res}''')

Wind Direction

To include all 16 cardinal wind directions, a 360 degree circle is cut into 16 x 22.5% slices.

cardinal = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
            'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
wind_dir = cardinal[int(day['winddir']/22.5)]

Gist

The Gist for this project is linked to the following...

https://gist.github.com/nick3499/10aa037bab43dbcc0072be739aa0744c

...which may or may not be updated to current version.

#!/bin/python3.10
'''Display weather data from Timeline API.'''
# https://gist.github.com/nick3499/10aa037bab43dbcc0072be739aa0744c
from json import loads
from pendulum import parse
from requests import get
from os import environ
def display_weather_data():
'''Print weather data to terminal.'''
# get data from API
response = get(f'https://weather.visualcrossing.com/\
VisualCrossingWebServices/rest/services/timeline/{environ["GEO_COORDS"]}\
?key={environ["TIMELINE_API_KEY"]}').text
data = loads(response)
# color formats
red = '\x1b[31m'
grn = '\x1b[32m'
blu = '\x1b[34m'
res = '\x1b[0m'
# cardinal directions
cardinal = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE',
'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']
# weather data
print(f'''\
{grn}Long-term forecast{res}: {data['description']}
{blu}======================={res}''')
# daily forecast
for day in data['days']:
dt_0 = parse(day['datetime'])
wind_dir = cardinal[int(day['winddir']/22.5)]
print(f'''\
{grn}Date{res} {dt_0.format('dddd D MMMM YYYY')}
{grn}Description{res} {day['description']}
{grn}High{res} {day['tempmax']}℉
{grn}Low{res} {day['tempmin']}℉
{grn}Dewpoint{res} {day['dew']}
{grn}Humidity{res} {day['humidity']}%
{grn}Chance of rain{res} {day['precipprob']}%
{grn}Precip. type{res} {day['preciptype']}
{grn}Wind gust{res} {day['windgust']}
{grn}Wind speed{res} {day['windspeed']}
{grn}Wind direction{res} {wind_dir}
{grn}Air Pressure{res} {day['pressure']}
{grn}UV Index{res} {day['uvindex']}
{grn}Sunrise{res} {parse(day['sunrise']).format('h:mm A')}
{grn}Sunset{res} {parse(day['sunset']).format('h:mm A')}
{grn}Moon Phase{res} {day['moonphase']}
{blu}======================={res}''')
# alerts
try:
alerts = data['alerts'][0]
ends = parse(alerts['ends'])
print(f'''\
{red}Alerts{res} {alerts['event'].upper()}
{red}Headline{res}\n{alerts['headline']}
{red}Description{res}\n{alerts['description']}
{red}Ends{res} {ends.format('dddd D MMMM YYYY hh:mm A')}
{blu}========= CURRENT =========={res}''')
except IndexError:
print(f'''There are no alerts at this time.
{blu}========= CURRENT =========={res}''')
# current conditions
current_conditions = data['currentConditions']
print(f'''\
{grn}Time{res} {parse(current_conditions['datetime']).format('h:mm A')}
{grn}Description{res} {current_conditions['conditions']}
{grn}Temperature{res} {current_conditions['temp']}℉
{grn}Feels like{res} {current_conditions['feelslike']}℉
{grn}Humidity{res} {current_conditions['humidity']}%
{grn}Dew point{res} {current_conditions['dew']}℉
{grn}Precipitation{res} {current_conditions['precip']}
{grn}Precip. prob.{res} {current_conditions['precipprob']}
{grn}Snow{res} {current_conditions['snow']}
{grn}Snow depth{res} {current_conditions['snowdepth']}
{grn}Precip. type{res} {current_conditions['preciptype']}
{grn}Wind gust{res} {current_conditions['windgust']}
{grn}Wind speed{res} {current_conditions['windspeed']}
{grn}Wind Direction{res} {current_conditions['winddir']}
{grn}Air pressure{res} {current_conditions['pressure']}
{grn}Visibility{res} {current_conditions['visibility']}mi
{grn}Cloud cover{res} {current_conditions['cloudcover']}
{grn}UV index{res} {current_conditions['uvindex']}
{grn}Sunrise{res} {parse(data['currentConditions']['sunrise']).format('h:mm A')}
{grn}Sunset{res} {parse(data['currentConditions']['sunset']).format('h:mm A')}
{grn}Moon phase{res} {current_conditions['moonphase']}''')
if __name__ == '__main__':
display_weather_data()
@nick3499
Copy link
Author

Used the Timeline Weather API for weather data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment