1 # -*- coding: utf-8 -*-
7 # Coded by Dr.Best (c) 2009
8 # Support: www.dreambox-tools.info
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License
12 # as published by the Free Software Foundation; either version 2
13 # of the License, or (at your option) any later version.
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details.
21 # for localized messages
24 from Plugins.Plugin import PluginDescriptor
25 from Screens.Screen import Screen
26 from Components.ActionMap import ActionMap
27 from Components.Sources.StaticText import StaticText
28 from xml.etree.cElementTree import fromstring as cet_fromstring
29 from twisted.internet import defer
30 from twisted.web.client import getPage, downloadPage
31 from urllib import quote
32 from Components.Pixmap import Pixmap
33 from enigma import ePicLoad
34 from os import path as os_path, mkdir as os_mkdir
35 from Components.AVSwitch import AVSwitch
36 from Components.config import ConfigSubsection, ConfigSubList, ConfigInteger, config
37 from setup import initConfig, WeatherPluginEntriesListConfigScreen
39 config.plugins.WeatherPlugin = ConfigSubsection()
40 config.plugins.WeatherPlugin.entriescount = ConfigInteger(0)
41 config.plugins.WeatherPlugin.Entries = ConfigSubList()
44 UserAgent = "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3."
46 class WeatherIconItem:
47 def __init__(self, url = "", filename = "", index = -1, error = False):
49 self.filename = filename
54 return getPage(url, agent=UserAgent)
57 return downloadPage(item.url, file(item.filename, 'wb'), agent=UserAgent)
60 def main(session,**kwargs):
61 session.open(WeatherPlugin)
63 def Plugins(**kwargs):
64 list = [PluginDescriptor(name=_("Weather Plugin"), description=_("Show Weather Forecast"), where = [PluginDescriptor.WHERE_PLUGINMENU, PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=main)]
68 class WeatherPlugin(Screen):
71 <screen name="WeatherPlugin" position="center,center" size="664,190" title="%s">
72 <widget render="Label" source="caption" position="10,20" zPosition="1" size="600,23" font="Regular;22" transparent="1"/>
73 <ePixmap position="620,22" zPosition="1" size="36,20" pixmap="skin_default/buttons/key_menu.png" alphatest="on" />
74 <widget render="Label" source="currentTemp" position="10,45" zPosition="1" size="300,23" font="Regular;22" transparent="1"/>
75 <widget render="Label" source="condition" position="10,100" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
76 <widget render="Label" source="wind_condition" position="10,125" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
77 <widget render="Label" source="humidity" position="10,150" zPosition="1" size="300,20" font="Regular;18" valign="bottom" transparent="1"/>
78 <widget render="Label" source="weekday1" position="255,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
79 <widget name="weekday1_icon" position="255,70" zPosition="1" size="72,72" alphatest="blend"/>
80 <widget render="Label" source="weekday1_temp" position="241,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
81 <widget render="Label" source="weekday2" position="358,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
82 <widget name="weekday2_icon" position="358,70" zPosition="1" size="72,72" alphatest="blend"/>
83 <widget render="Label" source="weekday2_temp" position="344,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
84 <widget render="Label" source="weekday3" position="461,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
85 <widget name="weekday3_icon" position="461,70" zPosition="1" size="72,72" alphatest="blend"/>
86 <widget render="Label" source="weekday3_temp" position="448,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
87 <widget render="Label" source="weekday4" position="564,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
88 <widget name="weekday4_icon" position="564,70" zPosition="1" size="72,72" alphatest="blend"/>
89 <widget render="Label" source="weekday4_temp" position="550,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
90 <widget render="Label" source="statustext" position="0,0" zPosition="1" size="664,190" font="Regular;20" halign="center" valign="center" transparent="1"/>
93 def __init__(self, session):
94 Screen.__init__(self, session)
95 self.title = _("Weather Plugin")
96 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
99 "input_date_time": self.config,
100 "right": self.nextItem,
101 "left": self.previousItem
104 self["statustext"] = StaticText()
105 self["caption"] = StaticText()
106 self["currentTemp"] = StaticText()
107 self["condition"] = StaticText()
108 self["wind_condition"] = StaticText()
109 self["humidity"] = StaticText()
113 self["weekday%s" % i] = StaticText()
114 self["weekday%s_icon" %i] = WeatherIcon()
115 self["weekday%s_temp" % i] = StaticText()
119 self.appdir = "/usr/lib/enigma2/python/Plugins/Extensions/WeatherPlugin/icons/"
120 if not os_path.exists(self.appdir):
121 os_mkdir(self.appdir)
123 self.weatherPluginEntryIndex = -1
124 self.weatherPluginEntryCount = config.plugins.WeatherPlugin.entriescount.value
125 if self.weatherPluginEntryCount >= 1:
126 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[0]
127 self.weatherPluginEntryIndex = 1
129 self.weatherPluginEntry = None
131 self.onLayoutFinish.append(self.startRun)
134 if self.weatherPluginEntry is not None:
135 self["statustext"].text = _("Getting weather information...")
136 url = ("http://www.google.com/ig/api?weather=%s&hl=%s" % (quote(self.weatherPluginEntry.city.value), self.weatherPluginEntry.language.value))
137 getXML(url).addCallback(self.xmlCallback).addErrback(self.error)
139 self["statustext"].text = _("No locations defined...\nPress 'Menu' to do that.")
142 if self.weatherPluginEntryCount != 0:
143 if self.weatherPluginEntryIndex < self.weatherPluginEntryCount:
144 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex + 1
146 self.weatherPluginEntryIndex = 1
149 def previousItem(self):
150 if self.weatherPluginEntryCount != 0:
151 if self.weatherPluginEntryIndex >= 2:
152 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex - 1
154 self.weatherPluginEntryIndex = self.weatherPluginEntryCount
158 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[self.weatherPluginEntryIndex-1]
162 def clearFields(self):
163 self["caption"].text = ""
164 self["currentTemp"].text = ""
165 self["condition"].text = ""
166 self["wind_condition"].text = ""
167 self["humidity"].text = ""
170 self["weekday%s" % i].text = ""
171 self["weekday%s_icon" %i].hide()
172 self["weekday%s_temp" % i].text = ""
175 def errorIconDownload(self, error = None, item = None):
178 def finishedIconDownload(self, result, item):
180 self.showIcon(item.index,item.filename)
182 def showIcon(self,index, filename):
183 self["weekday%s_icon" % index].updateIcon(filename)
184 self["weekday%s_icon" % index].show()
186 def xmlCallback(self, xmlstring):
187 self["statustext"].text = ""
191 IconDownloadList = []
192 root = cet_fromstring(xmlstring)
193 for childs in root.findall("weather"):
195 if items.tag == "problem_cause":
196 self["statustext"].text = items.attrib.get("data").encode("utf-8", 'ignore')
197 elif items.tag == "forecast_information":
199 if items2.tag == "city":
200 self["caption"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
201 elif items2.tag == "unit_system":
202 if items2.attrib.get("data").encode("utf-8", 'ignore') == "SI":
205 elif items.tag == "current_conditions":
207 if items2.tag == "condition":
208 self["condition"].text = _("Current: %s") % items2.attrib.get("data").encode("utf-8", 'ignore')
209 elif items2.tag == "temp_f" and metric == 0:
210 self["currentTemp"].text = ("%s °F" % items2.attrib.get("data").encode("utf-8", 'ignore'))
211 elif items2.tag == "temp_c" and metric == 1:
212 self["currentTemp"].text = ("%s °C" % items2.attrib.get("data").encode("utf-8", 'ignore'))
213 elif items2.tag == "humidity":
214 self["humidity"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
215 elif items2.tag == "wind_condition":
216 self["wind_condition"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
217 elif items.tag == "forecast_conditions":
223 if items2.tag == "day_of_week":
224 self["weekday%s" % index].text = items2.attrib.get("data").encode("utf-8", 'ignore')
225 elif items2.tag == "low":
226 lowTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
227 elif items2.tag == "high":
228 highTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
229 self["weekday%s_temp" % index].text = "%s °%s | %s °%s" % (highTemp, UnitSystemText, lowTemp, UnitSystemText)
230 elif items2.tag == "icon":
231 url = items2.attrib.get("data").encode("utf-8", 'ignore')
232 parts = url.split("/")
233 filename = self.appdir + parts[-1]
234 if not os_path.exists(filename):
235 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = index))
237 self.showIcon(index,filename)
238 if len(IconDownloadList) != 0:
239 ds = defer.DeferredSemaphore(tokens=len(IconDownloadList))
240 downloads = [ds.run(download,item ).addErrback(self.errorIconDownload, item).addCallback(self.finishedIconDownload,item) for item in IconDownloadList]
241 finished = defer.DeferredList(downloads).addErrback(self.error)
244 self.session.openWithCallback(self.setupFinished, WeatherPluginEntriesListConfigScreen)
246 def setupFinished(self, index, entry = None):
247 self.weatherPluginEntryCount = config.plugins.WeatherPlugin.entriescount.value
248 if self.weatherPluginEntryCount >= 1:
249 if entry is not None:
250 self.weatherPluginEntry = entry
251 self.weatherPluginEntryIndex = index + 1
252 if self.weatherPluginEntry is None:
253 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[0]
254 self.weatherPluginEntryIndex = 1
256 self.weatherPluginEntry = None
257 self.weatherPluginEntryIndex = -1
262 def error(self, error = None):
263 if error is not None:
265 self["statustext"].text = str(error.getErrorMessage())
268 class WeatherIcon(Pixmap):
270 Pixmap.__init__(self)
271 self.IconFileName = ""
272 self.picload = ePicLoad()
273 self.picload.PictureData.get().append(self.paintIconPixmapCB)
277 sc = AVSwitch().getFramebufferScale()
278 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], 0, 0, '#00000000'))
280 def paintIconPixmapCB(self, picInfo=None):
281 ptr = self.picload.getData()
283 self.instance.setPixmap(ptr.__deref__())
285 def updateIcon(self, filename):
286 new_IconFileName = filename
287 if (self.IconFileName != new_IconFileName):
288 self.IconFileName = new_IconFileName
289 self.picload.startDecode(self.IconFileName)