d6370af118934ba4733a72972cbeece0b82ee0ee
[vuplus_dvbapp-plugin] / weatherplugin / src / plugin.py
1 # -*- coding: utf-8 -*-
2 #
3 #  Weather Plugin E2
4 #
5 #  $Id$
6 #
7 #  Coded by Dr.Best (c) 2009
8 #  Support: www.dreambox-tools.info
9 #
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.
14 #
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.
19 #
20
21 from Plugins.Plugin import PluginDescriptor
22 from Screens.Screen import Screen
23 from Components.ActionMap import ActionMap
24 from Components.Label import Label
25 from Components.Button import Button
26 from Tools.LoadPixmap import LoadPixmap
27 import xml.etree.cElementTree
28 from twisted.internet import reactor, defer
29 from twisted.web import client
30 import urllib
31 from Components.Pixmap import Pixmap
32 from enigma import ePicLoad
33 import string
34 import os
35 from enigma import getDesktop
36 from Components.ConfigList import ConfigList, ConfigListScreen
37 from Components.AVSwitch import AVSwitch
38 from Components.ConfigList import ConfigList, ConfigListScreen
39 from Components.config import ConfigSubsection, ConfigSubList, ConfigText, ConfigInteger, config
40 from setup import initConfig, WeatherPluginEntriesListConfigScreen
41
42 config.plugins.WeatherPlugin = ConfigSubsection()
43 config.plugins.WeatherPlugin.entriescount =  ConfigInteger(0)
44 config.plugins.WeatherPlugin.Entries = ConfigSubList()
45 initConfig()
46
47 UserAgent = "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3."
48
49 class WeatherIconItem:
50         def __init__(self, url = "", filename = "", index = -1, error = False):
51                 self.url = url
52                 self.filename = filename
53                 self.index = index
54                 self.error = error
55
56 def getXML(url):
57         return client.getPage(url, agent=UserAgent)
58
59 def download(item):
60         return client.downloadPage(item.url, file(item.filename, 'wb'), agent=UserAgent)
61
62
63 def main(session,**kwargs):
64         session.open(WeatherPlugin)
65
66 def Plugins(**kwargs):
67         list = [PluginDescriptor(name="Weather Plugin", description=_("Weather Plugin"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=main)]
68         return list
69
70
71 class WeatherPlugin(Screen):
72
73         skin = """
74                 <screen name="WeatherPlugin" position="center,center" size="664,170" title="Weather Plugin">
75                         <widget name="caption" position="10,20" zPosition="1" size="300,23" font="Regular;22" transparent="1"/>
76                         <widget name="currentTemp" position="10,45" zPosition="1" size="300,23" font="Regular;22" transparent="1"/>
77                         <widget name="condition" position="10,80" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
78                         <widget name="wind_condition" position="10,105" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
79                         <widget name="humidity" position="10,130" zPosition="1" size="300,20" font="Regular;18" valign="bottom" transparent="1"/>
80                         <widget name="weekday1" position="255,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
81                         <widget name="weekday1_icon" position="255,50" zPosition="1" size="72,72" alphatest="blend"/>
82                         <widget name="weekday1_temp" position="241,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
83                         <widget name="weekday2" position="358,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
84                         <widget name="weekday2_icon" position="358,50" zPosition="1" size="72,72" alphatest="blend"/>
85                         <widget name="weekday2_temp" position="344,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
86                         <widget name="weekday3" position="461,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
87                         <widget name="weekday3_icon" position="461,50" zPosition="1" size="72,72" alphatest="blend"/>
88                         <widget name="weekday3_temp" position="448,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
89                         <widget name="weekday4" position="564,30" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
90                         <widget name="weekday4_icon" position="564,50" zPosition="1" size="72,72" alphatest="blend"/>
91                         <widget name="weekday4_temp" position="550,130" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
92                         <widget name="statustext" position="0,0" zPosition="1" size="664,170" font="Regular;20" halign="center" valign="center" transparent="1"/>
93                 </screen>"""
94         
95         def __init__(self, session):
96                 self.session = session
97                 Screen.__init__(self, session)
98                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
99                 {
100                         "back": self.close,
101                         "input_date_time": self.config,
102                         "right": self.nextItem,
103                         "left": self.previousItem
104                 }, -1)
105
106                 self["statustext"] = Label()
107
108                 self["caption"] = Label()
109                 self["currentTemp"] = Label()
110                 self["condition"] = Label()
111                 self["wind_condition"] = Label()
112                 self["humidity"] = Label()
113
114                 for i in range(1, 5):
115                         self["weekday%s" % i] = Label()
116                         self["weekday%s_icon" %i] = WeatherIcon()
117                         self["weekday%s_temp" % i] = Label()
118
119                 self.appdir = "/usr/lib/enigma2/python/Plugins/Extensions/WeatherPlugin/icons/" 
120                 if not os.path.exists(self.appdir):
121                         os.mkdir(self.appdir)
122
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
128                 else:
129                         self.weatherPluginEntry = None
130
131                 self.onLayoutFinish.append(self.startRun)
132
133         def startRun(self):
134                 if self.weatherPluginEntry is not None:
135                         self["statustext"].setText(_("Getting weather information..."))
136                         url = ("http://www.google.com/ig/api?weather=%s&hl=%s" % (urllib.quote(self.weatherPluginEntry.city.value), self.weatherPluginEntry.language.value))
137                         getXML(url).addCallback(self.xmlCallback).addErrback(self.error)
138                 else:
139                         self["statustext"].setText(_("No locations defined...\nPress 'Menu' to do that."))
140                 self["statustext"].show()
141
142         def nextItem(self):
143                 if self.weatherPluginEntryCount != 0:
144                         if self.weatherPluginEntryIndex < self.weatherPluginEntryCount:
145                                 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex + 1
146                         else:
147                                 self.weatherPluginEntryIndex = 1
148                         self.setItem()
149
150         def previousItem(self):
151                 if self.weatherPluginEntryCount != 0:
152                         if self.weatherPluginEntryIndex >= 2:
153                                 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex - 1
154                         else:
155                                 self.weatherPluginEntryIndex = self.weatherPluginEntryCount
156                         self.setItem()
157
158         def setItem(self):
159                 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[self.weatherPluginEntryIndex-1]
160                 self.clearFields()
161                 self.startRun()
162
163         def clearFields(self):
164                 self["caption"].setText("")
165                 self["currentTemp"].setText("")
166                 self["condition"].setText("")
167                 self["wind_condition"].setText("")
168                 self["humidity"].setText("")
169                 for i in range(1, 5):
170                         self["weekday%s" % i].setText("")
171                         self["weekday%s_icon" %i].hide()
172                         self["weekday%s_temp" % i].setText("")
173
174         def errorIconDownload(self, error = None, item = None):
175                 item.error = True
176
177         def finishedIconDownload(self, result, item):
178                 if not item.error:
179                         self.showIcon(item.index,item.filename)
180
181         def showIcon(self,index, filename):
182                 self["weekday%s_icon" % index].updateIcon(filename)
183                 self["weekday%s_icon" % index].show()
184
185         def xmlCallback(self, xmlstring):
186                 self["statustext"].hide()
187                 metric = 0
188                 index = 0
189                 UnitSystemText = "F"
190                 IconDownloadList = []
191                 root = xml.etree.cElementTree.fromstring(xmlstring)
192                 for childs in root.findall("weather"):
193                         for items in childs:
194                                 if items.tag == "problem_cause":
195                                         self["statustext"].setText(items.attrib.get("data").encode("utf-8", 'ignore'))
196                                         self["statustext"].show()
197                                 if items.tag == "forecast_information":
198                                         for items2 in items:
199                                                 if items2.tag == "city":
200                                                         self["caption"].setText(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":
203                                                                 metric = 1
204                                                                 UnitSystemText = "C"
205                                 elif items.tag == "current_conditions":
206                                         for items2 in items:
207                                                 if items2.tag == "condition":
208                                                         self["condition"].setText(_("Current: %s") % items2.attrib.get("data").encode("utf-8", 'ignore'))
209                                                 elif items2.tag == "temp_f" and metric == 0:
210                                                         self["currentTemp"].setText( ("%s °F" % items2.attrib.get("data").encode("utf-8", 'ignore')) )
211                                                 elif items2.tag == "temp_c" and metric == 1:
212                                                         self["currentTemp"].setText( ("%s °C" % items2.attrib.get("data").encode("utf-8", 'ignore')) )
213                                                 elif items2.tag == "humidity":
214                                                         self["humidity"].setText(items2.attrib.get("data").encode("utf-8", 'ignore'))
215                                                 elif items2.tag == "wind_condition":
216                                                         self["wind_condition"].setText(items2.attrib.get("data").encode("utf-8", 'ignore'))
217                                 elif items.tag == "forecast_conditions":
218                                         index = index + 1
219                                         lowTemp = ""
220                                         highTemp = ""
221                                         icon = ""
222                                         for items2 in items:
223                                                 if items2.tag == "day_of_week":
224                                                         self["weekday%s" % index].setText(items2.attrib.get("data").encode("utf-8", 'ignore'))
225                                                 if items2.tag == "low":
226                                                         lowTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
227                                                 if items2.tag == "high":
228                                                         highTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
229                                                         self["weekday%s_temp" % index].setText("%s °%s | %s °%s" % (highTemp, UnitSystemText, lowTemp, UnitSystemText))
230                                                 if items2.tag == "icon":
231                                                         url = "http://www.google.com%s" % items2.attrib.get("data").encode("utf-8", 'ignore')
232                                                         parts = string.split(url,"/")
233                                                         filename = self.appdir + parts[-1]
234                                                         if not os.path.exists(filename):
235                                                                 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = index))
236                                                         else:
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)
242
243         def config(self):
244                 self.session.openWithCallback(self.setupFinished, WeatherPluginEntriesListConfigScreen)
245
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
255                 else:
256                         self.weatherPluginEntry = None
257                         self.weatherPluginEntryIndex = -1
258
259                 self.clearFields()
260                 self.startRun()
261
262         def error(self, error = None):
263                 if error is not None:
264                         self.clearFields()
265                         self["statustext"].setText(str(error.getErrorMessage()))
266                         self["statustext"].show()
267                 
268                 
269 class WeatherIcon(Pixmap):
270         def __init__(self):
271                 Pixmap.__init__(self)
272                 self.IconFileName = ""
273                 self.picload = ePicLoad()
274                 self.picload.PictureData.get().append(self.paintIconPixmapCB)
275
276         def onShow(self):
277                 Pixmap.onShow(self)
278                 sc = AVSwitch().getFramebufferScale()
279                 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], 0, 0, '#00000000'))
280
281         def paintIconPixmapCB(self, picInfo=None):
282                 ptr = self.picload.getData()
283                 if ptr != None:
284                         self.instance.setPixmap(ptr.__deref__())
285
286         def updateIcon(self, filename):
287                 new_IconFileName = filename
288                 if (self.IconFileName != new_IconFileName):
289                         self.IconFileName = new_IconFileName
290                         self.picload.startDecode(self.IconFileName)
291