Skip to content

Instantly share code, notes, and snippets.

@isoraqathedh
Created March 21, 2017 15:12
Show Gist options
  • Save isoraqathedh/e2d58c8cdbfc0bc6f23712e70bcb3720 to your computer and use it in GitHub Desktop.
Save isoraqathedh/e2d58c8cdbfc0bc6f23712e70bcb3720 to your computer and use it in GitHub Desktop.
Display script for i3blocks: weather from Dark Sky API
#!/usr/bin/python3
# Display driver for i3blocks
# Displays weather information that's cached in a named file.
import json
import sys
import os
import math
import colorlover as colours
import time
import notify2
cacheFile = os.path.dirname(os.path.abspath(__file__)) + "/cache.json"
# Variables
quantity = os.getenv("BLOCK_INSTANCE") or 'temperature'
goodQuantities = {
'temperature': lambda x: -4 < x < 35,
'humidity': lambda x: 0.20 < x <= 0.95,
'pressure': lambda x: 950 <= x,
'windSpeed': lambda x: 0 <= x < 35,
'icon': lambda x: x in ["clear-day", "clear-night", "cloudy",
"partly-cloudy-day", "partly-cloudy-night"],
'rain': lambda x: x < 15,
'rainprob': lambda x: x < 0.95,
'visibility': lambda x: x > 0.5,
'windBearing': lambda x: True,
'cloudCover': lambda x: x > 0.20
}
units = {
'temperature': "°C",
'apparentTemperature': "°C",
'humidity': "%",
'cloudCover': "%",
'pressure': " hPa",
'windSpeed': " km/h",
'visibility': " km",
'windBearing': "°",
'precipIntensity': " mm/h"
}
colourmap = {
"scales": {
'temperature': ('div', 'RdBu'),
'humidity': ('div', 'RdBu'),
'pressure': ('div', 'RdBu'),
'windSpeed': ('seq', 'Reds'),
'visibility': ('seq', 'Reds'),
'rain': ('seq', 'Purples'),
'cloudCover': ('seq', 'Blues')
},
"thresholds": {
'temperature': [-1, 4, 10, 22, 28, 32],
'apparentTemperature': [-1, 4, 10, 22, 28, 32],
'humidity': [0.35, 0.50, 0.70, 0.85],
'pressure': [970, 1000, 1020, 1025],
'windSpeed': [12, 30, 40, 62, 87, 117],
'visibility': [1, 5],
'rain': [5, 8, 10, 20],
'cloudCover': [0.60, 0.75, 0.90]
},
"reverse": ['visibility', 'temperature']
}
urgent = 33
# Exit and formatting
def i3bexit(main_text, short_text, status=0, colour=None):
print(main_text)
print(short_text)
if colour:
print("{}".format(colour))
sys.exit(status)
def urgentp(key, value):
if goodQuantities[key](value): return 0
else: return urgent
def clamp(x):
return max(0, min(x, 255))
def colourhexcode(scheme, steps, index, reverse=False):
scale = colours.to_numeric(colours.scales[str(steps)][scheme[0]][scheme[1]])
if reverse:
scale = scale[::-1]
reqcolour = tuple(map(math.floor, scale[index]))
return "#{0:02X}{1:02X}{2:02X}".format(
clamp(reqcolour[0]), clamp(reqcolour[1]), clamp(reqcolour[2]))
def colour(key, value):
if not key in colourmap['scales']:
return None
else:
ind = 0
for i in colourmap['thresholds'][key]:
if value < i: break
else: ind += 1
return colourhexcode(colourmap["scales"][key],
len(colourmap["thresholds"][key]) + 1,
ind,
key in colourmap['reverse'])
def weathericon(status):
try:
return {
"clear-day": "☀",
"clear-night": "☽",
"rain": "☔",
"snow": "☃",
"sleet": "≅",
"wind": "⚑",
"fog": "≡",
"cloudy": "☁",
"partly-cloudy-day": "⛅",
"partly-cloudy-night": "⛅ (☽)"
}[status]
except KeyError:
return ""
###### BEGIN SCRIPT ######
# Read data
with open(cacheFile, 'r') as infile:
alldata = json.load(infile)
if 'error' in alldata:
# If error, exit with nothing.
i3bexit("Error", "—", 1)
elif os.getenv("BLOCK_BUTTON") == '1':
# Give a forecast if the block is clicked
notify2.init("i3bweather")
hoursToRead = 5
if quantity == 'status':
outText = alldata['hourly']['summary']
header = "General weather forecast"
elif quantity == 'rain':
outText = "\n".join(
["{}{}".format(x['precipIntensity'], units['precipIntensity'])
for x in alldata['hourly']['data']][:hoursToRead])
header = "Rainfall forecast"
elif quantity in units:
values = [x[quantity] for x in alldata['hourly']['data']][:hoursToRead]
if units[quantity] == '%':
values = ["{:.0%}".format(x) for x in values]
else:
values = ["{}{}".format(x, units[quantity])
for x in values]
outText = "\n".join(values)
header = "Forecast for {}".format(quantity)
notify2.Notification(header, outText, "notification-message-im").show()
# Then restore to the old data.
data = alldata['currently']
# Special values that require handling
if quantity == 'status':
i3bexit(weathericon(data['icon']) + " " + data['summary'],
data['summary'],
urgentp('icon', data['icon']))
elif quantity == 'rain':
if ((data['precipProbability'] > 0.5 and not data['precipType'] == "snow")
or data['precipIntensity'] > 5):
value = data['precipIntensity']
i3bexit("{}{}".format(value, units[quantity]),
"{}{}".format(value, units[quantity]),
urgentp('rain', value),
colour('rain', value))
elif data['precipProbability'] > 0.1:
value = data['precipProbability']
i3bexit("\u2614 {.0%}".format(value),
"\u2614 {.0%}".format(value),
urgentp('rainprob', value))
elif data['cloudCover'] > 0.25:
value = math.floor(data['cloudCover'] * 100)
i3bexit("\u2601 {.0%}".format(value),
"\u2601 {.0%}".format(value),
urgentp('cloudCover', value),
colour('cloudCover', value))
else:
i3bexit("\u2601\u20e0 ", "", urgent)
elif quantity == "apparentTemperature":
if abs(data[quantity] - data['temperature']) < 1:
# Apparent temperature is not worth listing
# If it's very close to the real temperature.
i3bexit("", "", 0)
else:
value = data[quantity] if quantity in data else "-"
i3bexit("({}{})".format(value, units[quantity]),
"",
urgentp(quantity, value),
colour(quantity, value))
# Default
elif quantity in data:
value = data[quantity] if quantity in data else "-"
if quantity == 'humidity':
i3bexit("{:.0%}".format(value),
"{:.0%}".format(value),
urgentp(quantity, value),
colour(quantity,value))
elif quantity == 'visibility' and value >= 15:
i3bexit("", "", 0)
i3bexit("{}{}".format(value, units[quantity]),
"{}{}".format(value, units[quantity]),
urgentp(quantity, value),
colour(quantity, value))
else:
# If the key is bogus or missing, just exit with a dash.
i3bexit("—", "", 0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment