#!/usr/bin/env python2.7
# -*- coding: utf-8 -*-
###############################################################################
# conkyForecast.py is a (not so) simple (anymore) python script to gather
# details of the current weather for use in conky.
#
# Author: Kaivalagi
# Created: 13/04/2008
from datetime import datetime, timedelta, tzinfo
from optparse import OptionParser
from xml.dom import minidom
import sys
import os
import socket
import urllib2
import gettext
import locale
import re
import codecs
import traceback
import time
# not sure on these, might create more trouble, but here goes...
reload(sys)
sys.setdefaultencoding('utf-8')
# cPickle is a pickle class implemented in C - so its faster
# in case its not available, use regular pickle
try:
import cPickle as pickle
except ImportError:
import pickle
app_name = "conkyForecast"
app_path = os.path.dirname(os.path.abspath(__file__))
module_name = __file__.replace(os.path.dirname (__file__) + "/", "").replace(".pyc","").replace(".py", "")
# default to standard locale translation
domain = __file__.replace(os.path.dirname (__file__) + "/", "").replace(".py", "")
localedirectory = os.path.dirname(os.path.abspath(__file__)) + "/locale"
gettext.bindtextdomain(domain, localedirectory)
gettext.textdomain(domain)
gettext.install(domain)
class CommandLineParser:
parser = None
def __init__(self):
self.parser = OptionParser()
self.parser.add_option("-C", "--config", dest="config", default="~/.conkyForecast.config", type="string", metavar="FILE", help=u"[default: %default] The path to the configuration file, allowing multiple config files to be used.")
self.parser.add_option("-l", "--location", dest="location", type="string", metavar="CODE", help=u"location code for weather data [default set in config]. Use the following url to determine your location code by city name:
http://xoap.weather.com/search/search?where=Norwich")
self.parser.add_option("-d", "--datatype", dest="datatype", default="HT", type="string", metavar="DATATYPE", help=u"[default: %default] The data type options are: DW (Day of Week), WF (Weather Font output), WI (Weather Icon Path), LT (Forecast:Low Temp,Current:Feels Like Temp), HT (Forecast:High Temp,Current:Current Temp), CC (Current Conditions), CT (Conditions Text), PC (Precipitation Chance), HM (Humidity), VI (Visibility), WD (Wind Direction), WA (Wind Angle - in degrees), WS (Wind Speed), WG (Wind Gusts), BF (Bearing Font), BI (Bearing Icon Path), BS (Bearing font with Speed), CN (City Name), CO (Country), OB (Observatory), SR (SunRise), SS (SunSet), DL (DayLight), MP (Moon Phase), MF (Moon Font), MI (Moon Icon Path), BR (Barometer Reading), BD (Barometer Description), UI (UV Index), UT (UV Text), DP (Dew Point), WM (weather map fetch and image path returned), LU (Last Update at weather.com), LF (Last Fetch from weather.com). Not applicable at command line when using templates.")
self.parser.add_option("-s", "--startday", dest="startday", type="int", metavar="NUMBER", help=u"define the starting day number, if omitted current conditions are output. Not applicable at command line when using templates.")
self.parser.add_option("-e", "--endday", dest="endday", type="int", metavar="NUMBER", help=u"define the ending day number, if omitted only starting day data is output. Not applicable at command line when using templates.")
self.parser.add_option("-S", "--spaces", dest="spaces", type="int", default=1, metavar="NUMBER", help=u"[default: %default] Define the number of spaces between ranged output. Not applicable at command line when using templates.")
self.parser.add_option("-t", "--template", dest="template", type="string", metavar="FILE", help=u"define a template file to generate output in one call. A displayable item in the file is in the form [--datatype=HT --startday=1]. The following are possible options within each item: --location,--datatype,--startday,--endday,--night,--shortweekday,--imperial,--beaufort,--metrespersecond,--hideunits,--hidedegreesymbol,--spaces,--minuteshide. Note that the short forms of the options are not supported! If any of these options is set from the commandline, it sets the default value of the option for all template items.")
self.parser.add_option("-L", "--locale", dest="locale", type="string", help=u"override the system locale for language output (bg=bulgarian, cs=czech, de=german, es=spanish, en=english, es=spanish, fj=fijian, fr=french, it=italian, nl=dutch, pl=polish, ro=romanian, sk=slovak, more to come)")
self.parser.add_option("-i", "--imperial", dest="imperial", default=False, action="store_true", help=u"request imperial units, if omitted output is in metric.")
self.parser.add_option("-b", "--beaufort", dest="beaufort", default=False, action="store_true", help=u"request beaufort scale for wind speeds, if omitted output is either metric/imperial.")
self.parser.add_option("-M", "--metrespersecond", dest="metrespersecond", default=False, action="store_true", help=u"request metres per second for wind speeds, if omitted output is either metric/imperial.")
self.parser.add_option("-n", "--night", dest="night", default=False, action="store_true", help=u"switch output to night data, if omitted day output will be output.")
self.parser.add_option("-w", "--shortweekday", dest="shortweekday", default=False, action="store_true", help=u"Shorten the day of week data type to 3 characters.")
self.parser.add_option("-u", "--hideunits", dest="hideunits", default=False, action="store_true", help=u"Hide units such as mph or C, degree symbols (°) are still shown.")
self.parser.add_option("-x", "--hidedegreesymbol", dest="hidedegreesymbol", default=False, action="store_true", help=u"Hide the degree symbol used with temperature output, this is only valid if used in conjunction with --hideunits.")
self.parser.add_option("-m", "--minuteshide", dest="minuteshide", type="int", metavar="NUMBER", help=u"Works only with LU and LF. If present, hides the date part of the LU or LF timestamp if the day of the timestamp is today. The time part is also hidden, if the timestamp is older than minutes specified in this argument. If set to 0, the time part is always shown. If set to -1, the value EXPIRY_MINUTES from the config file is used.")
self.parser.add_option("-c", "--centeredwidth", dest="centeredwidth", type="int", metavar="WIDTH", help=u"If used the output will be centered in a string of the set width, padded out with spaces, if the output width is greater than the setting it will be truncated")
self.parser.add_option("-r", "--refetch", dest="refetch", default=False, action="store_true", help=u"Fetch data regardless of data expiry.")
self.parser.add_option("-v", "--verbose", dest="verbose", default=False, action="store_true", help=u"Request verbose output, not a good idea when running through conky!")
self.parser.add_option("-V", "--version", dest="version", default=False, action="store_true", help=u"Displays the version of the script.")
self.parser.add_option("--errorlogfile", dest="errorlogfile", type="string", metavar="FILE", help=u"If a filepath is set, the script appends errors to the filepath.")
self.parser.add_option("--infologfile", dest="infologfile", type="string", metavar="FILE", help=u"If a filepath is set, the script appends info to the filepath.")
def parse_args(self):
(options, args) = self.parser.parse_args()
return (options, args)
def print_help(self):
return self.parser.print_help()
# N.B: The below class member values are defaults and should be left alone, they
# are there to provide a working script if the script is called without all
# the expected input. Any issues raised where these values have been
# changed will get the simple "put the .py file back to it's original
# state" reply
class ForecastConfig:
CACHE_FOLDERPATH = "/tmp/"
CONNECTION_TIMEOUT = 5
EXPIRY_MINUTES = 30
TIME_FORMAT = "%H:%M"
DATE_FORMAT = "%Y-%m-%d"
LOCALE = "" # with no setting the default locale of the system is used
XOAP_PARTNER_ID = "" # need config with correct partner id
DEFAULT_LOCATION = "RSXX0412"
MAXIMUM_DAYS_FORECAST = 4
AUTO_NIGHT = False
BASE_XOAP_URL =
http://xml.weather.com/weather/local/?cc=*&dayf=10&link=xoap&prod=xoap&par=&key=&unit=m
PROXY_HOST = None
PROXY_PORT = 8080
PROXY_USERNAME = None
PROXY_PASSWORD = None
class ForecastDataset:
def __init__(self, last_update, day_of_week, low, high, condition_code, condition_text, precip, humidity, wind_dir, wind_dir_numeric, wind_speed, wind_gusts, timezone, sunrise, sunset, moon_phase, moon_icon, bar_read, bar_desc, uv_index, uv_text, dew_point, observatory, visibility, city, country, weathermap):
self.last_update = last_update
self.day_of_week = day_of_week
self.low = low
self.high = high
self.condition_code = condition_code
self.condition_text = condition_text
self.precip = precip
self.humidity = humidity
self.wind_dir = wind_dir
self.wind_dir_numeric = wind_dir_numeric
self.wind_speed = wind_speed
self.wind_gusts = wind_gusts
self.timezone = timezone
self.sunrise = sunrise
self.sunset = sunset
self.moon_phase = moon_phase
self.moon_icon = moon_icon
self.bar_read = bar_read
self.bar_desc = bar_desc
self.uv_index = uv_index
self.uv_text = uv_text
self.dew_point = dew_point
self.observatory = observatory
self.visibility = visibility
self.city = city
self.country = country
self.weathermap = weathermap
class ForecastLocation:
timestamp = None
def __init__(self, current, day, night):
self.current = current
self.day = day
self.night = night
self.timestamp = datetime.today()
def outdated(self, mins):
if datetime.today() > self.timestamp + timedelta(minutes=mins):
return True
else:
return False
# start ignoring translations required at runtime
def _(text): return text