AutoPoller.py: fix missing import
[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 # for localized messages
22 from . import _
23
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
38
39 config.plugins.WeatherPlugin = ConfigSubsection()
40 config.plugins.WeatherPlugin.entriescount =  ConfigInteger(0)
41 config.plugins.WeatherPlugin.Entries = ConfigSubList()
42 initConfig()
43
44 UserAgent = "Mozilla/5.0 (X11; U; Linux x86_64; de; rv:1.9.0.15) Gecko/2009102815 Ubuntu/9.04 (jaunty) Firefox/3."
45
46 class WeatherIconItem:
47         def __init__(self, url = "", filename = "", index = -1, error = False):
48                 self.url = url
49                 self.filename = filename
50                 self.index = index
51                 self.error = error
52
53 def getXML(url):
54         return getPage(url, agent=UserAgent)
55
56 def download(item):
57         return downloadPage(item.url, file(item.filename, 'wb'), agent=UserAgent)
58
59
60 def main(session,**kwargs):
61         session.open(WeatherPlugin)
62
63 def Plugins(**kwargs):
64         list = [PluginDescriptor(name=_("Weather Plugin"), description=_("Weather Plugin"), where = [PluginDescriptor.WHERE_EXTENSIONSMENU], fnc=main)]
65         return list
66
67
68 class WeatherPlugin(Screen):
69
70         skin = """
71                 <screen name="WeatherPlugin" position="center,center" size="664,190" title="%s">
72                         <widget render="Label" source="caption" position="10,20" zPosition="1" size="300,23" font="Regular;22" transparent="1"/>
73                         <widget render="Label" source="currentTemp" position="10,45" zPosition="1" size="300,23" font="Regular;22" transparent="1"/>
74                         <widget render="Label" source="condition" position="10,100" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
75                         <widget render="Label" source="wind_condition" position="10,125" zPosition="1" size="300,20" font="Regular;18" transparent="1"/>
76                         <widget render="Label" source="humidity" position="10,150" zPosition="1" size="300,20" font="Regular;18" valign="bottom" transparent="1"/>
77                         <widget render="Label" source="weekday1" position="255,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
78                         <widget name="weekday1_icon" position="255,70" zPosition="1" size="72,72" alphatest="blend"/>
79                         <widget render="Label" source="weekday1_temp" position="241,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
80                         <widget render="Label" source="weekday2" position="358,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
81                         <widget name="weekday2_icon" position="358,70" zPosition="1" size="72,72" alphatest="blend"/>
82                         <widget render="Label" source="weekday2_temp" position="344,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
83                         <widget render="Label" source="weekday3" position="461,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
84                         <widget name="weekday3_icon" position="461,70" zPosition="1" size="72,72" alphatest="blend"/>
85                         <widget render="Label" source="weekday3_temp" position="448,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
86                         <widget render="Label" source="weekday4" position="564,50" zPosition="1" size="72,20" halign="center" valign="center" font="Regular;18" transparent="1"/>
87                         <widget name="weekday4_icon" position="564,70" zPosition="1" size="72,72" alphatest="blend"/>
88                         <widget render="Label" source="weekday4_temp" position="550,150" zPosition="1" size="100,20" halign="center" valign="bottom" font="Regular;16" transparent="1"/>
89                         <widget render="Label" source="statustext" position="0,0" zPosition="1" size="664,190" font="Regular;20" halign="center" valign="center" transparent="1"/>
90                 </screen>"""
91         
92         def __init__(self, session):
93                 Screen.__init__(self, session)
94                 self.title = _("Weather Plugin")
95                 self["actions"] = ActionMap(["WizardActions", "DirectionActions", "ColorActions", "EPGSelectActions"],
96                 {
97                         "back": self.close,
98                         "input_date_time": self.config,
99                         "right": self.nextItem,
100                         "left": self.previousItem
101                 }, -1)
102
103                 self["statustext"] = StaticText()
104                 self["caption"] = StaticText()
105                 self["currentTemp"] = StaticText()
106                 self["condition"] = StaticText()
107                 self["wind_condition"] = StaticText()
108                 self["humidity"] = StaticText()
109
110                 i = 1
111                 while i < 5:
112                         self["weekday%s" % i] = StaticText()
113                         self["weekday%s_icon" %i] = WeatherIcon()
114                         self["weekday%s_temp" % i] = StaticText()
115                         i += 1
116                 del i
117
118                 self.appdir = "/usr/lib/enigma2/python/Plugins/Extensions/WeatherPlugin/icons/" 
119                 if not os_path.exists(self.appdir):
120                         os_mkdir(self.appdir)
121
122                 self.weatherPluginEntryIndex = -1
123                 self.weatherPluginEntryCount = config.plugins.WeatherPlugin.entriescount.value
124                 if self.weatherPluginEntryCount >= 1:
125                         self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[0]
126                         self.weatherPluginEntryIndex = 1
127                 else:
128                         self.weatherPluginEntry = None
129
130                 self.onLayoutFinish.append(self.startRun)
131
132         def startRun(self):
133                 if self.weatherPluginEntry is not None:
134                         self["statustext"].text = _("Getting weather information...")
135                         url = ("http://www.google.com/ig/api?weather=%s&hl=%s" % (quote(self.weatherPluginEntry.city.value), self.weatherPluginEntry.language.value))
136                         getXML(url).addCallback(self.xmlCallback).addErrback(self.error)
137                 else:
138                         self["statustext"].text = _("No locations defined...\nPress 'Menu' to do that.")
139
140         def nextItem(self):
141                 if self.weatherPluginEntryCount != 0:
142                         if self.weatherPluginEntryIndex < self.weatherPluginEntryCount:
143                                 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex + 1
144                         else:
145                                 self.weatherPluginEntryIndex = 1
146                         self.setItem()
147
148         def previousItem(self):
149                 if self.weatherPluginEntryCount != 0:
150                         if self.weatherPluginEntryIndex >= 2:
151                                 self.weatherPluginEntryIndex = self.weatherPluginEntryIndex - 1
152                         else:
153                                 self.weatherPluginEntryIndex = self.weatherPluginEntryCount
154                         self.setItem()
155
156         def setItem(self):
157                 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[self.weatherPluginEntryIndex-1]
158                 self.clearFields()
159                 self.startRun()
160
161         def clearFields(self):
162                 self["caption"].text = ""
163                 self["currentTemp"].text = ""
164                 self["condition"].text = ""
165                 self["wind_condition"].text = ""
166                 self["humidity"].text = ""
167                 i = 1
168                 while i < 5:
169                         self["weekday%s" % i].text = ""
170                         self["weekday%s_icon" %i].hide()
171                         self["weekday%s_temp" % i].text = ""
172                         i += 1
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"].text = ""
187                 metric = 0
188                 index = 0
189                 UnitSystemText = "F"
190                 IconDownloadList = []
191                 root = cet_fromstring(xmlstring)
192                 for childs in root.findall("weather"):
193                         for items in childs:
194                                 if items.tag == "problem_cause":
195                                         self["statustext"].text = items.attrib.get("data").encode("utf-8", 'ignore')
196                                 elif items.tag == "forecast_information":
197                                         for items2 in items:
198                                                 if items2.tag == "city":
199                                                         self["caption"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
200                                                 elif items2.tag == "unit_system":
201                                                         if items2.attrib.get("data").encode("utf-8", 'ignore') == "SI":
202                                                                 metric = 1
203                                                                 UnitSystemText = "C"
204                                 elif items.tag == "current_conditions":
205                                         for items2 in items:
206                                                 if items2.tag == "condition":
207                                                         self["condition"].text = _("Current: %s") % items2.attrib.get("data").encode("utf-8", 'ignore')
208                                                 elif items2.tag == "temp_f" and metric == 0:
209                                                         self["currentTemp"].text =  ("%s °F" % items2.attrib.get("data").encode("utf-8", 'ignore')) 
210                                                 elif items2.tag == "temp_c" and metric == 1:
211                                                         self["currentTemp"].text =  ("%s °C" % items2.attrib.get("data").encode("utf-8", 'ignore')) 
212                                                 elif items2.tag == "humidity":
213                                                         self["humidity"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
214                                                 elif items2.tag == "wind_condition":
215                                                         self["wind_condition"].text = items2.attrib.get("data").encode("utf-8", 'ignore')
216                                 elif items.tag == "forecast_conditions":
217                                         index = index + 1
218                                         lowTemp = ""
219                                         highTemp = ""
220                                         icon = ""
221                                         for items2 in items:
222                                                 if items2.tag == "day_of_week":
223                                                         self["weekday%s" % index].text = items2.attrib.get("data").encode("utf-8", 'ignore')
224                                                 elif items2.tag == "low":
225                                                         lowTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
226                                                 elif items2.tag == "high":
227                                                         highTemp = items2.attrib.get("data").encode("utf-8", 'ignore')
228                                                         self["weekday%s_temp" % index].text = "%s °%s | %s °%s" % (highTemp, UnitSystemText, lowTemp, UnitSystemText)
229                                                 elif items2.tag == "icon":
230                                                         url = "http://www.google.com%s" % items2.attrib.get("data").encode("utf-8", 'ignore')
231                                                         parts = url.split("/")
232                                                         filename = self.appdir + parts[-1]
233                                                         if not os_path.exists(filename):
234                                                                 IconDownloadList.append(WeatherIconItem(url = url,filename = filename, index = index))
235                                                         else:
236                                                                 self.showIcon(index,filename)
237                 if len(IconDownloadList) != 0:
238                         ds = defer.DeferredSemaphore(tokens=len(IconDownloadList))
239                         downloads = [ds.run(download,item ).addErrback(self.errorIconDownload, item).addCallback(self.finishedIconDownload,item) for item in IconDownloadList]
240                         finished = defer.DeferredList(downloads).addErrback(self.error)
241
242         def config(self):
243                 self.session.openWithCallback(self.setupFinished, WeatherPluginEntriesListConfigScreen)
244
245         def setupFinished(self, index, entry = None):
246                 self.weatherPluginEntryCount = config.plugins.WeatherPlugin.entriescount.value
247                 if self.weatherPluginEntryCount >= 1:
248                         if entry is not None:
249                                 self.weatherPluginEntry = entry
250                                 self.weatherPluginEntryIndex = index + 1
251                         if self.weatherPluginEntry is None:
252                                 self.weatherPluginEntry = config.plugins.WeatherPlugin.Entries[0]
253                                 self.weatherPluginEntryIndex = 1
254                 else:
255                         self.weatherPluginEntry = None
256                         self.weatherPluginEntryIndex = -1
257
258                 self.clearFields()
259                 self.startRun()
260
261         def error(self, error = None):
262                 if error is not None:
263                         self.clearFields()
264                         self["statustext"].text = str(error.getErrorMessage())
265
266
267 class WeatherIcon(Pixmap):
268         def __init__(self):
269                 Pixmap.__init__(self)
270                 self.IconFileName = ""
271                 self.picload = ePicLoad()
272                 self.picload.PictureData.get().append(self.paintIconPixmapCB)
273
274         def onShow(self):
275                 Pixmap.onShow(self)
276                 sc = AVSwitch().getFramebufferScale()
277                 self.picload.setPara((self.instance.size().width(), self.instance.size().height(), sc[0], sc[1], 0, 0, '#00000000'))
278
279         def paintIconPixmapCB(self, picInfo=None):
280                 ptr = self.picload.getData()
281                 if ptr != None:
282                         self.instance.setPixmap(ptr.__deref__())
283
284         def updateIcon(self, filename):
285                 new_IconFileName = filename
286                 if (self.IconFileName != new_IconFileName):
287                         self.IconFileName = new_IconFileName
288                         self.picload.startDecode(self.IconFileName)
289