fix file permissions of non-executable files
[enigma2-plugins.git] / eibox / src / plugin.py
1 # -*- coding: UTF-8 -*-
2
3 from Components.ActionMap import ActionMap
4 from Components.Sensors import sensors
5 from Components.Sources.Sensor import SensorSource
6 from Components.Sources.StaticText import StaticText
7 from Components.Sources.Progress import Progress
8 from Components.ConfigList import ConfigListScreen
9 from Components.Pixmap import Pixmap,MultiPixmap
10 from Components.Label import MultiColorLabel
11 from Components.config import config, getConfigListEntry, ConfigSubsection, ConfigBoolean, ConfigOnOff, ConfigInteger, ConfigSlider, ConfigText, ConfigSelectionNumber, ConfigNothing, ConfigFloat, ConfigText
12 from Screens.Screen import Screen
13 from Screens.MessageBox import MessageBox
14 from Plugins.Plugin import PluginDescriptor
15 from Tools.Directories import fileExists, resolveFilename, SCOPE_PLUGINS
16 from Tools.LoadPixmap import LoadPixmap
17 from enigma import eTimer, eListbox, gFont, eListboxPythonMultiContent, \
18         RT_HALIGN_LEFT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, RT_WRAP, eRect, eTimer
19
20 from socket import *
21 import xml.dom.minidom
22
23 from Components.Language import language
24 from os import environ as os_environ
25 import gettext
26
27 def localeInit():
28         lang = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
29         os_environ["LANGUAGE"] = lang # Enigma doesn't set this (or LC_ALL, LC_MESSAGES, LANG). gettext needs it!
30         gettext.bindtextdomain("EIBox", resolveFilename(SCOPE_PLUGINS, "Extensions/EIBox/locale"))
31
32 def _(txt):
33         t = gettext.dgettext("EIBox", txt)
34         if t == txt:
35                 print "[EIBox] fallback to default translation for", txt 
36                 t = gettext.gettext(txt)
37         return t
38
39 localeInit()
40 language.addCallback(localeInit)
41
42 config.eib = ConfigSubsection()
43 config.eib.xmlfile = ConfigText(default="design.xml")
44 config.eib.host = ConfigText(default="")
45 config.eib.port = ConfigInteger(default="1028")
46 config.eib.debug = ConfigBoolean(default=True)
47 config.eib.refresh = ConfigInteger(default="1000")
48
49 EIB_SWITCH, EIB_DIMMER, EIB_GOTO, EIB_THERMO, EIB_TEXT = ("switch", "dimmer", "goto", "thermostat", "text")
50
51 file_prefix = resolveFilename(SCOPE_PLUGINS, 'Extensions/EIBox/')
52 img_prefix = file_prefix + 'images/'
53
54 up_down_descriptions = {False: _("up"), True: _("down")}
55 class ConfigUpDown(ConfigBoolean):
56         def __init__(self, default = False):
57                 ConfigBoolean.__init__(self, default = default, descriptions = up_down_descriptions)
58
59 goto_descriptions = {False: "", True: ""}
60 class ConfigGoto(ConfigBoolean):
61         def __init__(self, default = False):
62                 ConfigBoolean.__init__(self, default = default, descriptions = goto_descriptions)
63
64 class ConfigEIBText(ConfigText):
65         def __init__(self, default = "", fixed_size = True, visible_width = False):
66                 ConfigText.__init__(self, default, fixed_size, visible_width)
67         
68         def onSelect(self, session):
69                 self.allmarked = (self.value != "")
70
71 class EIBObject(object):
72         def __init__(self, order, object_id, object_type, label, position, img=None, custom_img=None, textformat=None, readonly=False):
73                 self.order = order
74                 self.object_id = object_id
75                 self.object_type = object_type
76                 self.label = label
77                 self.position = position
78                 self.img = img
79                 self.custom_img = custom_img
80                 self.textformat = textformat
81                 self.readonly = readonly
82                 self.config_element = None
83                 self.createConfigElement()
84
85         def createConfigElement(self):
86                 if self.object_type == EIB_SWITCH and self.img == "light":
87                         self.config_element = ConfigOnOff()
88                 elif self.object_type == EIB_SWITCH and self.img == "blinds":
89                         self.config_element = ConfigUpDown()
90                 elif self.object_type == EIB_SWITCH:
91                         self.config_element = ConfigBoolean()
92                 elif self.object_type == EIB_DIMMER:
93                         self.config_element = ConfigSelectionNumber(0,255,15)
94                         #self.config_element = ConfigSlider(increment = 10, limits=(0,255))
95                 elif self.object_type == EIB_THERMO:
96                         self.config_element = ConfigFloat(default=[0,0],limits=[(-31,+31),(0,99)])
97                 elif self.object_type == EIB_GOTO:
98                         self.config_element = ConfigGoto()
99                 elif self.object_type == EIB_TEXT:
100                         self.config_element = ConfigEIBText()
101                 else:
102                         print "[createConfigElement] couldn't create config_element for", self.getInfo()
103
104         def getValue(self):
105                 if self.config_element:
106                         if self.object_type == EIB_THERMO:
107                                 val = self.config_element.getValue()
108                                 return "%d.%d" % (val[0], val[1])
109                         else:
110                                 return self.config_element.getValue()
111
112         def getText(self):
113                 if self.config_element:
114                         if self.object_type == EIB_THERMO:
115                                 return str(self.value+"C")
116                         elif self.object_type == EIB_TEXT:
117                                 return str(self.textformat.replace("$1",str(self.value)))
118                         else:
119                                 return str(self.value)
120
121         def getPos(self, offset=[0,0]):
122                 x = self.position[0] - offset[0]
123                 y = self.position[1] - offset[1]
124                 return "%d,%d" % (x,y)
125
126         def setValue(self, val):
127                 if self.config_element:
128                         if self.object_type == EIB_SWITCH:
129                                 if val == "off" or val == "down" or val == 0 or val == False:
130                                         self.config_element.setValue(False)
131                                 if val == "on" or val == "up" or val == 1 or val == True:
132                                         self.config_element.setValue(True)
133                         else:
134                                 try:
135                                         if self.object_type == EIB_THERMO:
136                                                 val = val.split('.')
137                                                 if len(val) == 1:
138                                                         val.append(0)
139                                                 self.config_element.setValue([int(val[0]),int(val[1])])
140                                         elif self.object_type == EIB_TEXT:
141                                                 self.config_element.setValue(str(val))
142                                         else:
143                                                 self.config_element.setValue(int(val))
144                                 except ValueError:
145                                         print "[setValue] Error setting", val, self.getInfo()
146                                         return
147                         if config.eib.debug.value:
148                                 print "[setValue]", self.object_id, ":=", val, "now: ", self.config_element.getValue()
149                 else:
150                         print "[setValue] error: no config_element", self.getInfo()
151
152         def getInfo(self):
153                 print "[EIBOject] order=%d, id=%s, type=%s, label=%s, position=(%d,%d), img=%s, custom_img=%s, textformat=%s, readonly=%s, config_element=%s, value=%s" % (self.order, self.object_id, str(self.object_type), self.label, self.position[0], self.position[1], str(self.img), str(self.custom_img), str(self.textformat), str(self.readonly), str(self.config_element), self.value)
154
155         def getKNXvalue(self):
156                 value = self.value
157                 if type(value) == bool and value == True:
158                         return "on"
159                 elif type(value) == bool and value == False:
160                         return "off"
161                 else:
162                         return str(value)
163
164         value = property(getValue, setValue)
165                 
166 class EIBObjects(object):
167         def __init__(self, zone_id, zone_name, zone_img):
168                 self.ids = {}
169                 self.cfg = {}
170                 self.zone_id = zone_id
171                 self.zone_name = zone_name
172                 self.zone_img = zone_img
173
174         def by_id (self, x): return self.ids[x]
175         def by_cfg(self, x): return self.cfg[x]
176
177         def append(self, x):
178                 self.ids[x.object_id] = x
179                 self.cfg[x.config_element] = x
180
181         def EIBwriteSingle(self, EIBObject):
182                 ret = True
183                 if not EIBObject.readonly:
184                         query = '<write><object id="%s" value="%s"/></write>\n\x04' % (EIBObject.object_id, EIBObject.getKNXvalue())
185                         ret = self.sendKNX(query)
186                 return ret
187
188         def EIBreadSingle(self, EIBObject):
189                 query = '<read><object id="%s" /></read>\n\x04' % EIBObject.object_id
190                 return self.sendKNX(query, self.parseSingleRead, EIBObject)
191
192         def EIBreadAll(self):
193                 persist_request_cmd = '<read><objects>'
194                 for EIBObject in self.ids.itervalues():
195                         if EIBObject.object_type != EIB_GOTO:
196                                 persist_request_cmd += '<object id="%s"/>' % EIBObject.object_id
197                 persist_request_cmd += '</objects></read>\n\x04'
198                 return self.sendKNX(persist_request_cmd, self.parseMultiRead)
199
200         def sendKNX(self, query, callback=None, user_args=None):
201                 try:
202                         knx = socket(AF_INET, SOCK_STREAM)
203                         host = config.eib.host.getValue()
204                         port = int(config.eib.port.getValue())
205                         knx.connect((host, port))
206                         knx.settimeout(2)
207                         ret = knx.send(query)
208                         if config.eib.debug.value:
209                                 print "[sendKNX]", query, ret
210                         
211                         knxdata = knx.recv(1024)
212                         while not knxdata.endswith('\n\x04'):
213                                 knxdata += knx.recv(1024)
214                         knx.close()
215                         if callback:
216                                 callback(knxdata[:-1], user_args)
217                         return True
218                 except timeout:
219                         print ("[sendKNX] socket timeout with linknx server %s:%d") % (host, port)
220                 except error:
221                         print ("[sendKNX] can't connect to linknx server %s:%d") % (host, port)
222                 return False
223
224         def parseSingleRead(self, knxdata, EIBObject):
225                 if config.eib.debug.value:
226                         print "[parseSingleRead]", knxdata
227                 try:
228                         dom = xml.dom.minidom.parseString(knxdata)
229                         if dom.childNodes[0].getAttribute("status") == "success":
230                                 subnode = dom.childNodes[0].childNodes[0]
231                                 if subnode.nodeType == xml.dom.minidom.Text.nodeType:
232                                         value = subnode.nodeValue
233                                         if config.eib.debug.value:
234                                                 print "[parseSingleRead] value=", value
235                                         try:
236                                                 EIBObject.value = str(value)
237                                         except KeyError:
238                                                 print "[parseSingleRead] KeyError exception"
239                                         return
240                         print ("[parseSingleRead] XML parser error parseSingleRead failed")
241                 except xml.parsers.expat.ExpatError, ValueError:
242                         print ("[parseSingleRead] XML parser error parseSingleRead DOM error")
243
244         def parseMultiRead(self, knxdata, user_args):
245                 if config.eib.debug.value:
246                         print "[parseMultiRead]", knxdata
247                 try:
248                         dom = xml.dom.minidom.parseString(knxdata)
249                         for node in dom.childNodes[0].childNodes:
250                                 if node.nodeType == xml.dom.minidom.Element.nodeType:
251                                     if node.tagName == 'objects':
252                                         for subnode in node.childNodes:
253                                             if subnode.nodeType == xml.dom.minidom.Element.nodeType:
254                                                 if subnode.tagName == 'object':
255                                                     i = 0
256                                                     object_id = None
257                                                     value = None
258                                                     while i < subnode.attributes.length:
259                                                       item = subnode.attributes.item(i)
260                                                       key = item.name.encode("utf-8")
261                                                       if key == "id":
262                                                         object_id = item.nodeValue
263                                                       elif key == "value":
264                                                         value = item.nodeValue
265                                                       i += 1
266                                                     if object_id and value != None:
267                                                           EIBObject = self.ids[object_id]
268                                                           EIBObject.value = value
269                                                           if config.eib.debug.value:
270                                                                 print "[parseMultiRead]", EIBObject.object_id, " := ", EIBObject.value
271                                                     else:
272                                                           print "[parseMultiRead] couldn't parse persistence object", object_id, value
273                 except xml.parsers.expat.ExpatError:
274                         print ("[parseMultiRead] XML parser error") 
275
276         def __iter__ (self):
277                 list = self.ids.itervalues()
278                 return iter(sorted(list, key=lambda EIBObject: EIBObject.order))
279                 
280 class EIBoxZoneScreen(Screen, ConfigListScreen):
281
282         def __init__(self, session, EIB_objects):
283                 skin = """
284                 <screen position="center,center" size="550,450" title="E.I.B.ox" >
285                         <widget name="config" position="10,420" size="530,26" zPosition="1" transparent="1" scrollbarMode="showNever" />
286                         <ePixmap pixmap="%s" position="0,0" size="550,400" zPosition="-1" alphatest="on" />\n""" % (img_prefix+EIB_objects.zone_img)
287
288                 offset = [12, 10] # fix up browser css spacing
289                 iconsize = [32, 32]
290                 
291                 self.EIB_objects = EIB_objects
292                 for EIB_object in self.EIB_objects:
293                         pixmap_src = ''
294                         if EIB_object.object_type == EIB_SWITCH:
295                                 if EIB_object.img == "light":
296                                         pixmap_src = (img_prefix+'light_off.png',img_prefix+'light_on.png')
297                                 elif EIB_object.img == "blinds":
298                                         pixmap_src = (img_prefix+'blinds_up.png',img_prefix+'blinds_down.png')
299                                 elif EIB_object.img == "custom":
300                                         pixmap_src = (img_prefix+EIB_object.custom_img[0],img_prefix+EIB_object.custom_img[1])
301                         if EIB_object.object_type == EIB_DIMMER:
302                                 pixmap_src = (img_prefix+'light_off.png',img_prefix+'light_on.png')
303                         if EIB_object.object_type == EIB_GOTO:
304                                 pixmap_src = (img_prefix+'goto'+EIB_object.img.capitalize()+'.png')
305
306                         if EIB_object.object_type in (EIB_SWITCH, EIB_DIMMER):
307                                 skin += '\t\t\t<widget name="%s" pixmaps="%s,%s" position="%s" size="32,32" transparent="1" alphatest="on" borderColor="#004679" zPosition="1" />\n' % (EIB_object.object_id, pixmap_src[0], pixmap_src[1], EIB_object.getPos(offset))  
308                                 self[EIB_object.object_id] = MultiPixmap()
309                         elif EIB_object.object_type in (EIB_GOTO):
310                                 skin += '\t\t\t<widget name="%s" pixmap="%s" position="%s" size="32,32" transparent="1" alphatest="on" borderColor="#004679" zPosition="1" />\n' % (EIB_object.object_id, pixmap_src, EIB_object.getPos(offset))
311                                 self[EIB_object.object_id] = Pixmap()
312
313                         if EIB_object.object_type == EIB_DIMMER:
314                                 skin += '\t\t\t<widget source="%s_progress" render="Progress" pixmap="skin_default/progress_small.png" position="%s" size="32,5" backgroundColor="#4f74BB" zPosition="1" />\n' % (EIB_object.object_id, EIB_object.getPos([offset[0],offset[1]-iconsize[1]]))
315                                 self[EIB_object.object_id+"_progress"] = Progress()
316                                 self[EIB_object.object_id+"_progress"].range = 255
317                         
318                         if EIB_object.object_type in (EIB_THERMO, EIB_TEXT):
319                                 skin += '\t\t\t<widget name="%s" position="%s" size="120,20" font="Regular;14" halign="left" valign="center" foregroundColors="#000000,#0000FF" transparent="1" zPosition="1" />\n' % (EIB_object.object_id, EIB_object.getPos(offset))
320                                 self[EIB_object.object_id] = MultiColorLabel()
321
322                 skin += """
323                 </screen>"""
324                 if config.eib.debug.value:
325                         print skin
326
327                 self.skin = skin
328                 Screen.__init__(self, session)
329                 
330                 self.initConfigList()
331                 ConfigListScreen.__init__(self, self.list, session = self.session, on_change = self.changedEntry)
332
333                 self["actions"] = ActionMap(["SetupActions", "OkCancelActions", "ColorActions", "DirectionActions"], 
334                 {
335                         "up": self.keyUp,
336                         "upUp": self.keyPass,
337                         "upRepeated": self.keyUp,
338                         "down": self.keyDown,
339                         "downUp": self.keyPass,
340                         "downRepeated": self.keyDown,
341                         "cancel": self.keyCancel,
342                         "red": self.keyCancel,
343                         "green": self.keyOk,
344                         "ok": self.keyOk
345                 }, -2)
346                 self.onLayoutFinish.append(self.layoutFinished)
347
348         def handleInputHelpers(self):
349                 pass
350         
351         def keyPass(self):
352                 pass
353
354         def keyUp(self):
355                 self.moveBorder(self["config"].instance.moveUp)
356
357         def keyDown(self):
358                 self.moveBorder(self["config"].instance.moveDown)
359
360         def keyOk(self):
361                 current = self["config"].getCurrent()
362                 if current:
363                         EIB_object = self.EIB_objects.by_cfg(current[1])
364                         if EIB_object.object_type == EIB_DIMMER:
365                                 if EIB_object.value < 128:
366                                         EIB_object.value = 255
367                                 else:
368                                         EIB_object.value = 0
369                                 self.changedEntry()
370                                 self["config"].invalidateCurrent()
371                         else:
372                                 self.keyRight()
373                         
374         def keyCancel(self):
375               self.exit()
376
377         def layoutFinished(self):
378                 self.moveBorder()
379                 self.refreshObjects()
380                 self.refresh_timer = eTimer()
381                 self.refresh_timer.callback.append(self.refreshObjects)
382                 interval = config.eib.refresh.value
383                 if interval >= 500:
384                         self.refresh_timer.start(interval)
385
386         def moveBorder(self, direction=None):
387                 if direction != None:
388                         for EIB_object in self.EIB_objects:
389                                 if EIB_object.object_type in (EIB_SWITCH, EIB_DIMMER, EIB_GOTO):
390                                         self[EIB_object.object_id].instance.setBorderWidth(0)
391                                 elif EIB_object.object_type in (EIB_THERMO, EIB_TEXT):
392                                         self[EIB_object.object_id].setForegroundColorNum(0)
393                         self["config"].instance.moveSelection(direction)
394                 current = self["config"].getCurrent()
395                 if current:
396                         EIB_object = self.EIB_objects.by_cfg(current[1])
397                         if EIB_object.object_type in (EIB_SWITCH, EIB_DIMMER, EIB_GOTO):
398                                 self[EIB_object.object_id].instance.setBorderWidth(5)
399                         elif EIB_object.object_type in (EIB_THERMO, EIB_TEXT):
400                                         self[EIB_object.object_id].setForegroundColorNum(1)
401
402         def refreshObjects(self):
403                 status = self.EIB_objects.EIBreadAll()
404                 for EIB_object in self.EIB_objects:
405                         self.updateObject(EIB_object)
406                 self.setWindowTitle(status)
407
408         def setWindowTitle(self, status):
409                 if status == True:
410                         self.setTitle("E.I.B.ox %s " % self.EIB_objects.zone_name + _("(online)"))
411                 else:
412                         self.setTitle("E.I.B.ox %s " % self.EIB_objects.zone_name + _("(offline!)"))
413
414         def updateObject(self, EIB_object):
415                 if EIB_object.object_type in (EIB_THERMO, EIB_TEXT):
416                         self.updateLabel(EIB_object)
417                 else:
418                         self.updateIcon(EIB_object)
419
420         def updateLabel(self, EIB_object):
421                 if config.eib.debug.value:
422                         print "[refreshObjects]", EIB_object.getInfo(), EIB_object.getText()
423                 self[EIB_object.object_id].setText(EIB_object.getText())
424
425         def updateIcon(self, EIB_object):
426                 if config.eib.debug.value:
427                         print "[updateIcon]", EIB_object.getInfo()
428                 if EIB_object.object_type not in (EIB_SWITCH, EIB_DIMMER):
429                         return
430                 if type(EIB_object.value) == bool or EIB_object.value == 0:
431                         self[EIB_object.object_id].setPixmapNum(int(EIB_object.value))
432                 elif type(EIB_object.value) == int and EIB_object.value > 0:
433                         self[EIB_object.object_id].setPixmapNum(1)
434                 if EIB_object.object_type == EIB_DIMMER:
435                         self[EIB_object.object_id+"_progress"].value = EIB_object.value
436
437         def initConfigList(self):
438                 self.list = []
439                 for EIB_object in self.EIB_objects:
440                         self.list.append(getConfigListEntry(EIB_object.label, EIB_object.config_element))
441                 
442         def changedEntry(self):
443                 current = self["config"].getCurrent()
444                 if current:
445                         EIB_object = self.EIB_objects.by_cfg(current[1])
446                         if EIB_object.object_type == EIB_GOTO:
447                                 self.exit(EIB_object.object_id)
448                         else:
449                                 if not EIB_object.readonly:
450                                         status = self.EIB_objects.EIBwriteSingle(EIB_object)
451                                 self.EIB_objects.EIBreadSingle(EIB_object)
452                                 self.updateObject(EIB_object)
453                                 self.setWindowTitle(status)
454         
455         def exit(self, gotoZone=None):
456                 self.refresh_timer.callback.remove(self.refreshObjects)
457                 self.close(gotoZone)
458
459 class EIBox(Screen, ConfigListScreen):
460         skin = """
461                 <screen position="center,center" size="570,420" title="E.I.B.ox" >
462                 </screen>"""
463
464         def __init__(self, session, args = None):               
465                 Screen.__init__(self, session)
466
467                 self["actions"] = ActionMap(["OkCancelActions", "ColorActions", "DirectionActions"], 
468                 {
469                         "cancel": self.close,
470                         "red": self.close
471                 }, -1)
472                 
473                 self.gotoZone = None
474                 self.EIB_zones = {}
475                 self.onShown.append(self.onFirstShown)
476
477         def ZoneScreenCB(self, gotoZone=None):
478                 if not gotoZone:
479                         self.close()
480                 else:
481                         self.gotoZone = gotoZone
482                         self.displayZone()
483
484         def onFirstShown(self):
485                 self.onShown.remove(self.onFirstShown)
486                 self.loadXML(resolveFilename(SCOPE_PLUGINS, file_prefix+config.eib.xmlfile.value))              
487                 self.displayZone()
488
489         def displayZone(self):
490                 if self.gotoZone in self.EIB_zones:
491                         self.session.openWithCallback(self.ZoneScreenCB, EIBoxZoneScreen, self.EIB_zones[self.gotoZone])
492         
493         def errorOut(self, message):
494                 self.session.openWithCallback(self.close, MessageBox, message, type = MessageBox.TYPE_ERROR)
495
496         def loadXML(self, filename):
497                 try:
498                         if not fileExists(filename):
499                                 self.errorOut("[loadXML] " + str(filename) + ' ' + _("not found"))
500                                 return
501                                 #raise AttributeError
502                         file = open(filename, "r")
503                         data = file.read().decode("utf-8").replace('&',"&amp;").encode("ascii",'xmlcharrefreplace')
504                         file.close()
505                         projectfiledom = xml.dom.minidom.parseString(data)
506                         for node in projectfiledom.childNodes[0].childNodes:
507                           if node.nodeType == xml.dom.minidom.Element.nodeType:
508                             if node.tagName == 'zones':
509                               for subnode in node.childNodes:
510                                 if subnode.nodeType == xml.dom.minidom.Element.nodeType:
511                                   if subnode.tagName == 'zone':
512                                     zone_id = str(subnode.getAttribute("id"))
513                                     zone_img = str(subnode.getAttribute("img"))
514                                     zone_name = str(subnode.getAttribute("name"))
515                                     filename = img_prefix + zone_img
516                                     if not fileExists(filename):
517                                         print "[loadXML] ", filename, " not found! using default image"
518                                         zone_img = "default_bg.png"
519                                     self.EIB_zones[zone_id] = EIBObjects(zone_id, zone_name, zone_img)
520                                     if config.eib.debug.value:
521                                         print "[loadXML] new EIB_zone", zone_id, zone_name, zone_img, self.EIB_zones[zone_id]
522                                     self.xmlGetZoneNode(subnode, zone_id)
523                                     if self.gotoZone == None:
524                                         self.gotoZone = zone_id
525                                     #self.EIB_zones[zone_id].EIBreadAll()
526                             if node.tagName == 'settings':
527                                 config.eib.host.value = node.getAttribute("host")
528                                 config.eib.port.value = int(node.getAttribute("port"))
529                                 config.eib.refresh.value = int(node.getAttribute("refresh"))
530                                 debug = False
531                                 if node.getAttribute("debug") == "true":
532                                         debug = True
533                                 config.eib.debug.setValue(debug)
534                                 if config.eib.debug.value:
535                                         print "[loadXML] parsed settings! host:", config.eib.host.value, "port:", config.eib.port.value, "refresh:", config.eib.refresh.value, "debug:", config.eib.debug.value
536                 except:
537                         self.errorOut("[loadXML] " + str(filename) + ' ' + _("parser error"))
538
539         def xmlGetZoneNode(self, node, zone):
540                 order = 0
541                 for subnode in node.childNodes:
542                         if subnode.nodeType == xml.dom.minidom.Element.nodeType:
543                                 i = 0
544                                 object_id = None
545                                 object_type = None
546                                 label = None
547                                 img = None
548                                 readonly = False
549                                 custom_img = [None, None]
550                                 temp_id = None
551                                 setpoint_id = None
552                                 textformat = None
553                                 while i < subnode.attributes.length:
554                                         item = subnode.attributes.item(i)
555                                         key = item.name.encode("utf-8")
556                                         if key == "object":
557                                                 object_id = item.nodeValue
558                                         #if key == "switch": # dimmer on/off (1 bit)
559                                                 #object_id = item.nodeValue
560                                         if key == "value": # dimmer brightness value (8 bit)
561                                                 object_id = item.nodeValue
562                                         if key == "target": # goto target
563                                                 object_id = item.nodeValue
564                                         if key == "temp": # thermostat actual value
565                                                 temp_id = item.nodeValue
566                                         if key == "setpoint": # thermostat set point
567                                                 setpoint_id = item.nodeValue
568                                         if key == "type":
569                                                 if item.nodeValue in ("dimmer", "switch", "goto", "thermostat", "text"):
570                                                         object_type = item.nodeValue
571                                                 if item.nodeValue == "thermostat":
572                                                         object_type == item.nodeValue
573                                         if key == "label":
574                                                 label = item.nodeValue
575                                         if key == "img":
576                                                 img = str(item.nodeValue)
577                                         if key == "x":
578                                                 x = int(item.nodeValue)
579                                         if key == "y":
580                                                 y = int(item.nodeValue)
581                                         if key == "off":
582                                                 custom_img[0] = str(item.nodeValue)
583                                         if key == "on":
584                                                 custom_img[1] = str(item.nodeValue)
585                                         if key == "format":
586                                                 textformat = item.nodeValue
587                                                 readonly = True
588                                         if key == "readonly" and item.nodeValue == "true":
589                                                 readonly = True
590                                         i += 1
591                                 if object_id and object_type and label and x and y:
592                                         obj = EIBObject(order, object_id, object_type, label, (x,y), img, custom_img, textformat, readonly)
593                                         self.EIB_zones[zone].append(obj)
594                                         if config.eib.debug.value:
595                                                 print "[xmlGetZoneNode] new EIBObject", obj.getInfo()
596                                         order += 1
597                                 elif temp_id and setpoint_id and label and x and y:
598                                         obj = EIBObject(order, temp_id, EIB_THERMO, label+' '+_("(actual)"), (x,y), readonly=True)
599                                         self.EIB_zones[zone].append(obj)
600                                         if config.eib.debug.value:
601                                                 print "[xmlGetZoneNode] new EIBObject", obj.getInfo()
602                                         order += 1
603                                         obj = EIBObject(order, setpoint_id, EIB_THERMO, label+' '+_("(set point)"), (x,y+16), readonly=readonly)
604                                         self.EIB_zones[zone].append(obj)
605                                         if config.eib.debug.value:
606                                                 print "[xmlGetZoneNode] new EIBObject", obj.getInfo()
607                                         order += 1
608                                 else:
609                                         print "[xmlGetZoneNode] couldn't parse object", object_id, object_type, label, (x,y), img, custom_img, textformat, readonly, temp_id, setpoint_id
610
611 def main(session, **kwargs):
612         session.open(EIBox)
613
614 def Plugins(**kwargs):
615         return PluginDescriptor(name = "E.I.B.ox", description = _("Visualization for European Installation Bus"), where = PluginDescriptor.WHERE_EXTENSIONSMENU, fnc = main)
616