Пример #1
0
    def __init__(self, screensection, screenname):
        debugprint(config.dbgscreenbuild, "New WeatherScreenDesc ", screenname)

        screen.ScreenDesc.__init__(self, screensection, screenname,
                                   (('which', ('', )), ))
        utilities.LocalizeParams(self,
                                 screensection,
                                 WunderKey='',
                                 location='')
        self.scrlabel = screen.FlatenScreenLabel(self.label)
        # entries are (fontsize, centered, formatstring, values)
        self.conditions = [
            (2, True, "{d}", self.scrlabel),
            (1, True, "{d[0]}", ('Location', )),
            (1, False, u"Now: {d[0]} {d[1]}\u00B0F", ('Sky', 'Temp')),
            (0, False, u"  Feels like: {d[0]}\u00B0", ('Feels', )),
            (1, False, "Wind {d[0]}", ('WindStr', )),
            (1, False, "Sunrise: {d[0]:02d}:{d[1]:02d}", ('SunriseH',
                                                          'SunriseM')),
            (1, False, "Sunset:  {d[0]:02d}:{d[1]:02d}", ('SunsetH',
                                                          'SunsetM')),
            (0, False, "Moon rise: {d[0]} set: {d[1]}", ('Moonrise',
                                                         'Moonset')),
            (0, False, "     {d[0]}% illuminated", ('MoonPct', )),
            (0, False, "will be replaced", "")
        ]
        self.forecast = [
            (1, False, u"{d[0]}   {d[1]}\u00B0/{d[2]}\u00B0 {d[3]}",
             ('Day', 'High', 'Low', 'Sky')),
            (1, False, "Wind: {d[0]} at {d[1]}", ('WindDir', 'WindSpd'))
        ]
        self.Info = weatherinfo.WeatherInfo(self.WunderKey, self.location)
        utilities.register_example("WeatherScreenDesc", self)
Пример #2
0
    def __init__(self, screensection, screenname):
        debug.debugPrint('Screen', "New WeatherScreenDesc ", screenname)
        screen.ScreenDesc.__init__(self, screensection, screenname)

        self.fmt = WFormatter()

        butsize = self.ButSize(1, 1, 0)
        self.Keys = OrderedDict({
            'condorfcst':
            toucharea.TouchPoint('condorfcst',
                                 (self.HorizBorder + .5 * butsize[0],
                                  self.TopBorder + .5 * butsize[1]),
                                 butsize,
                                 proc=self.CondOrFcst)
        })
        self.currentconditions = True  # show conditions or forecast
        screen.AddUndefaultedParams(self,
                                    screensection,
                                    location='',
                                    LocationSize=40)

        self.SetScreenTitle(screen.FlatenScreenLabel(self.label), 50,
                            self.CharColor)

        self.condformat = u"{d[0]} {d[1]}\u00B0F", u"  Feels like: {d[2]}\u00B0", "Wind {d[3]}@{d[4]}"
        self.condfields = list(
            ((self.location, 'Cond', x)
             for x in ('Sky', 'Temp', 'Feels', 'WindDir', 'WindMPH')))

        # self.dayformat  = "Sunrise: {d[0]:02d}:{d[1]:02d}","Sunset:  {d[2]:02d}:{d[3]:02d}","Moon rise: {d[4]} set: {d[5]}","{d[6]}% illuminated"
        # self.dayfields  = list(((self.location, 'Cond', x) for x in ('SunriseH','SunriseM','SunsetH','SunsetM','Moonrise','Moonset','MoonPct')))
        self.dayformat = "Sunrise: {d[0]}", "Sunset:  {d[1]}", "Moon rise: {d[2]} set: {d[3]}"
        self.dayfields = list(
            ((self.location, 'Cond', x)
             for x in ('Sunrise', 'Sunset', 'Moonrise', 'Moonset')))

        self.footformat = "Readings as of {d[0]}",
        self.footfields = ((self.location, 'Cond', 'Age'), )

        self.fcstformat = u"{d[0]}   {d[1]}\u00B0/{d[2]}\u00B0 {d[3]}", "Wind: {d[4]}"
        self.fcstfields = list(
            ((self.location, 'Fcst', x)
             for x in ('Day', 'High', 'Low', 'Sky', 'WindSpd')))

        try:
            self.store = valuestore.ValueStores[self.location]
        except KeyError:
            logsupport.Logs.Log(
                "Weather screen {} using non-existent location {}".format(
                    screenname, self.location),
                severity=logsupport.ConsoleWarning)
            raise ValueError
        utilities.register_example("WeatherScreenDesc", self)
Пример #3
0
	def __init__(self, screensection, screenname):
		debugprint(config.dbgscreenbuild, "New ThermostatScreenDesc ", screenname)
		screen.BaseKeyScreenDesc.__init__(self, screensection, screenname)
		utilities.LocalizeParams(self, screensection, 'KeyColor', 'KeyOffOutlineColor', 'KeyOnOutlineColor')
		self.info = {}
		self.fsize = (30, 50, 80, 160)

		if screenname in config.ISY.NodesByName:
			self.RealObj = config.ISY.NodesByName[screenname]
		else:
			self.RealObj = None
			config.Logs.Log("No Thermostat: " + screenname, severity=logsupport.ConsoleWarning)

		self.TitleRen = config.fonts.Font(self.fsize[1]).render(screen.FlatenScreenLabel(self.label), 0,
																wc(self.CharColor))
		self.TitlePos = ((config.screenwidth - self.TitleRen.get_width())/2, config.topborder)
		self.TempPos = config.topborder + self.TitleRen.get_height()
		self.StatePos = self.TempPos + config.fonts.Font(self.fsize[3]).get_linesize() - scaleH(20)
		self.SPPos = self.StatePos + scaleH(25)
		self.AdjButSurf = pygame.Surface((config.screenwidth, scaleH(40)))
		self.AdjButTops = self.SPPos + config.fonts.Font(self.fsize[2]).get_linesize() - scaleH(5)
		centerspacing = config.screenwidth/5
		self.AdjButSurf.fill(wc(self.BackgroundColor))
		arrowsize = scaleH(40)  # pixel

		for i in range(4):
			gfxdraw.filled_trigon(self.AdjButSurf, *trifromtop(centerspacing, arrowsize/2, i + 1, arrowsize,
															   wc(("red", "blue", "red", "blue")[i]), i%2 <> 0))
			self.keysbyord.append(toucharea.TouchPoint((centerspacing*(i + 1), self.AdjButTops + arrowsize/2),
													   (arrowsize*1.2, arrowsize*1.2)))
		self.ModeButPos = self.AdjButTops + scaleH(85)  # pixel

		bsize = (scaleW(100), scaleH(50))  # pixel
		self.keysbyord.append(toucharea.ManualKeyDesc("Mode", ["Mode"],
													  self.KeyColor, self.CharColor, self.CharColor,
													  center=(config.screenwidth/4, self.ModeButPos), size=bsize,
													  KOn=config.KeyOffOutlineColor))  # todo clean up
		self.keysbyord.append(toucharea.ManualKeyDesc("Fan", ["Fan"],
													  self.KeyColor, self.CharColor, self.CharColor,
													  center=(3*config.screenwidth/4, self.ModeButPos), size=bsize,
													  KOn=config.KeyOffOutlineColor))
		self.keysbyord[4].FinishKey((0,0),(0,0))
		self.keysbyord[5].FinishKey((0,0),(0,0))
		self.ModesPos = self.ModeButPos + bsize[1]/2 + scaleH(5)
		utilities.register_example("ThermostatScreenDesc", self)
Пример #4
0
    def __init__(self, key, gomsg, nogomsg, procyes, procno, callingscreen,
                 bcolor, keycoloroff, charcolor, state, interestlist):
        screen.BaseKeyScreenDesc.__init__(self, {},
                                          key.name + '-Verify',
                                          parentscreen=key)
        debug.debugPrint('Screen', "Build Verify Screen")
        self.NavKeysShowing = False
        self.DefaultNavKeysShowing = False
        self.HubInterestList = interestlist
        self.DimTO = 20
        self.PersistTO = 10
        self.label = screen.FlatenScreenLabel(key.label)
        self.ClearScreenTitle()  # don't use parent screen title
        self.CallingScreen = callingscreen
        screen.AddUndefaultedParams(self,
                                    None,
                                    TitleFontSize=40,
                                    SubFontSize=25)
        self.SetScreenTitle(self.label, 40, charcolor)
        self.Keys['yes'] = ManualKeyDesc(self,
                                         'yes',
                                         gomsg,
                                         bcolor,
                                         keycoloroff,
                                         charcolor,
                                         State=state)
        self.Keys['yes'].Proc = procyes  # functools.partial(proc, True)
        self.Keys['no'] = ManualKeyDesc(self,
                                        'no',
                                        nogomsg,
                                        bcolor,
                                        keycoloroff,
                                        charcolor,
                                        State=state)
        self.Keys[
            'no'].Proc = procno if procno is not None else self.DefaultNo  # functools.partial(proc, False)

        self.LayoutKeys(self.startvertspace, self.useablevertspace)
        utilities.register_example("VerifyScreen", self)
Пример #5
0
    def __init__(self, screensection, screenname):
        debugprint(config.dbgscreenbuild, "New TimeTempDesc ", screenname)

        screen.ScreenDesc.__init__(self, screensection, screenname)
        utilities.LocalizeParams(self,
                                 screensection,
                                 WunderKey='',
                                 location='',
                                 CharSize=[20],
                                 Font='droidsansmono',
                                 TimeFormat=[],
                                 ConditionFields=[],
                                 ConditionFormat=[],
                                 ForecastFields=[],
                                 ForecastFormat=[],
                                 ForecastDays=1)
        self.scrlabel = screen.FlatenScreenLabel(self.label)
        self.WInfo = weatherinfo.WeatherInfo(self.WunderKey, self.location)
        for i in range(
                len(self.CharSize),
                len(self.TimeFormat) + len(self.ConditionFormat) +
                len(self.ForecastFormat)):
            self.CharSize.append(self.CharSize[-1])
Пример #6
0
	def __init__(self, screensection, screenname):
		screen.ScreenDesc.__init__(self, screensection, screenname)
		debug.debugPrint('Screen', "New TimeTempDesc ", screenname)
		self.Font = None
		self.ClockSize = -1
		self.LocationSize = -1
		self.ConditionFormat = []
		self.ConditionFields = []
		self.CondSize = []
		self.CondIcon = True
		self.TimeFormat = []
		self.ForecastFormat = []
		self.ForecastFields = []
		self.ForecastDays = 1
		self.FcstSize = []
		self.FcstLayout = 'Block'
		self.FcstIcon = True
		self.WunderKey = ''
		self.location = ''
		self.SkipDays = 0
		self.CharSize = None  # type: list

		utilities.LocalizeParams(self, screensection, '-', 'WunderKey', location='', CharSize=[-1],
								 ClockSize=-1, LocationSize=-1, CondSize=[20], FcstSize=[20],
								 Font=config.monofont, FcstLayout='Block',
								 FcstIcon=True, CondIcon=True,
								 TimeFormat=[], ConditionFields=[], ConditionFormat=[], ForecastFields=[],
								 ForecastFormat=[], ForecastDays=1, SkipDays=0)
		if self.CharSize != [-1]:
			# old style
			logsupport.Logs.Log(
				"TimeTemp screen CharSize parameter deprecated, change to specific block size parameters",
				severity=ConsoleWarning)
			self.ClockSize = extref(self.CharSize, 0)
			self.LocationSize = extref(self.CharSize, 1)
			self.CondSize = extref(self.CharSize, 2)
			self.FcstSize = extref(self.CharSize, 3)
		if self.ForecastDays + self.SkipDays > 10:
			self.ForecastDays = 10 - self.SkipDays
			logsupport.Logs.Log("Long forecast requested; days reduced to: " + str(self.ForecastDays),
								severity=ConsoleWarning)
		if self.FcstLayout not in ('Block', 'BlockCentered', 'LineCentered', '2ColVert', '2ColHoriz'):
			logsupport.Logs.Log(
				'FcstLayout Param not Block, BlockCentered, LineCentered, 2ColVert, or 2ColHoriz - using "Block" for ',
				screenname, severity=ConsoleWarning)
			self.FcstLayout = "Block"
		self.scrlabel = screen.FlatenScreenLabel(self.label)
		self.store = valuestore.NewValueStore(weatherstore.WeatherVals(self.location, self.WunderKey))
		self.DecodedCondFields = []
		for f in self.ConditionFields:
			if ':' in f:
				self.DecodedCondFields.append(f.split(':'))
			else:
				self.DecodedCondFields.append((self.location, 'Cond', f))

		self.condicon = (self.location, 'Cond', 'Icon') if self.CondIcon else None

		self.DecodedFcstFields = []
		for f in self.ForecastFields:
			if ':' in f:
				self.DecodedFcstFields.append(f.split(':'))
			else:
				self.DecodedFcstFields.append((self.location, 'Fcst', f))
		self.fcsticon = (self.location, 'Fcst', 'Icon') if self.FcstIcon else None

		self.ClockRepaintEvent = ProcEventItem(id(self), 'repaintTimeTemp', self.repaintClock)
		self.fmt = WFormatter()
Пример #7
0
    def __init__(self, screensection, screenname):
        debug.debugPrint('Screen', "New Nest ThermostatScreenDesc ",
                         screenname)
        screen.BaseKeyScreenDesc.__init__(self, screensection, screenname)
        screen.IncorporateParams(
            self, 'NestThermostatScreen',
            {'KeyColor', 'KeyOffOutlineColor', 'KeyOnOutlineColor'},
            screensection)
        nominalfontsz = (30, 50, 80, 160)
        nominalspacers = (5, 20, 25, 40, 50, 85)
        self.fsize = []
        self.spacer = []

        self.HA = self.DefaultHubObj
        self.ThermNode = self.HA.GetNode(screenname)[0]  # use ControlObj (0)
        if self.ThermNode is None:
            logsupport.Logs.Log("No Thermostat: " + screenname,
                                severity=ConsoleWarning)
            raise ValueError
        # if isinstance(self.DefaultHub,hasshub.HA):
        #	self.HA = self.DefaultHub
        #	self.ThermNode = self.HA.GetNode(screenname)[0]  # use ControlObj (0)
        #	if self.ThermNode is None:
        #		logsupport.Logs.Log("No Thermostat: " + screenname, severity=ConsoleWarning)
        #		raise ValueError
        # else:
        #	logsupport.Logs.Log("Nest Thermostat screen only works with HA hub", severity=ConsoleError)
        #	self.self.ThermNode = None
        #	raise ValueError

        self.SetScreenTitle(screen.FlatenScreenLabel(self.label),
                            nominalfontsz[1], self.CharColor)
        self.TempPos = self.startvertspace
        '''
		Size and positions based on nominal 480 vertical screen less top/bottom borders less default title size of 50
		Compute other fonts sizes based on what is left after that given user ability to set actual title size
		'''
        tempsurf = fonts.fonts.Font(50).render('Temp', 0, wc(self.CharColor))
        useable = self.useablevertspace / (self.useablevertspace -
                                           tempsurf.get_height())

        for fs in nominalfontsz:
            self.fsize.append(int(fs * useable))

        for fs in nominalspacers:
            self.spacer.append(int(fs * useable))

        self.StatePos = self.TempPos + fonts.fonts.Font(
            self.fsize[3]).get_linesize() - scaleH(self.spacer[1])
        self.SPVPos = self.StatePos + scaleH(self.spacer[2])
        sp = fonts.fonts.Font(self.fsize[2]).render("{:2d}".format(99), 0,
                                                    wc(self.CharColor))
        self.SPHgt = sp.get_height()
        self.SPWdt = sp.get_width()
        self.SetPointSurf = pygame.Surface((self.SPWdt, self.SPHgt))
        self.SetPointSurf.fill(wc(self.BackgroundColor))
        self.AdjButSurf = pygame.Surface(
            (hw.screenwidth, scaleH(self.spacer[3])))
        self.AdjButTops = self.SPVPos + fonts.fonts.Font(
            self.fsize[2]).get_linesize() - scaleH(self.spacer[0])
        centerspacing = hw.screenwidth // 5
        self.SPHPosL = int(1.5 * centerspacing)
        self.SPHPosR = int(3.5 * centerspacing)
        self.AdjButSurf.fill(wc(self.BackgroundColor))
        self.LocalOnly = [0.0, 0.0
                          ]  # Heat setpoint, Cool setpoint:  0 is normal color
        self.ModeLocal = 0.0
        self.FanLocal = 0.0
        arrowsize = scaleH(
            40)  # pixel todo should this be other than a constant?
        self.t_low = 0
        self.t_high = 99
        self.t_cur = 0
        self.t_state = "Unknown"
        self.mode = 'auto'
        self.fan = 'auto'
        self.modes, self.fanstates = self.ThermNode.GetModeInfo()
        self.TimeBumpSP = None
        self.TimeBumpModes = None
        self.TimeBumpFan = None
        self.TimerName = 0

        for i in range(4):
            gfxdraw.filled_trigon(
                self.AdjButSurf,
                *trifromtop(centerspacing, arrowsize // 2, i + 1, arrowsize,
                            wc(("red", "blue", "red", "blue")[i]), i % 2 != 0))
            self.Keys['temp' + str(i)] = toucharea.TouchPoint(
                'temp' + str(i),
                (centerspacing * (i + 1), self.AdjButTops + arrowsize // 2),
                (arrowsize * 1.2, arrowsize * 1.2),
                proc=functools.partial(self.BumpTemp,
                                       (True, True, False, False)[i],
                                       (1, -1, 1, -1)[i]))

        self.ModeButPos = self.AdjButTops + scaleH(self.spacer[5])  # pixel

        bsize = (scaleW(100), scaleH(self.spacer[4]))  # pixel

        self.Keys['Mode'] = toucharea.ManualKeyDesc(
            self,
            "Mode", ["Mode"],
            self.KeyColor,
            self.CharColor,
            self.CharColor,
            center=(self.SPHPosL, self.ModeButPos),
            size=bsize,
            KOn=self.KeyOffOutlineColor,
            proc=self.BumpMode)

        self.Keys['Fan'] = toucharea.ManualKeyDesc(self,
                                                   "Fan", ["Fan"],
                                                   self.KeyColor,
                                                   self.CharColor,
                                                   self.CharColor,
                                                   center=(self.SPHPosR,
                                                           self.ModeButPos),
                                                   size=bsize,
                                                   KOn=self.KeyOffOutlineColor,
                                                   proc=self.BumpFan)

        self.ModesPos = self.ModeButPos + bsize[1] // 2 + scaleH(
            self.spacer[0])
        if self.ThermNode is not None:
            self.HubInterestList[self.HA.name] = {
                self.ThermNode.address: self.Keys['Mode']
            }  # placeholder for thermostat node
        utilities.register_example("NestThermostatScreenDesc", self)
Пример #8
0
    def __init__(self, screensection, screenname):
        screen.ScreenDesc.__init__(self, screensection, screenname)
        debug.debugPrint('Screen', "New TimeTempDesc ", screenname)

        screen.AddUndefaultedParams(self,
                                    screensection,
                                    location='',
                                    CharSize=[-1],
                                    ClockSize=-1,
                                    LocationSize=-1,
                                    CondSize=[20],
                                    FcstSize=[20],
                                    Font=fonts.monofont,
                                    FcstLayout='Block',
                                    FcstIcon=True,
                                    CondIcon=True,
                                    TimeFormat=[],
                                    ConditionFields=[],
                                    ConditionFormat=[],
                                    ForecastFields=[],
                                    ForecastFormat=[],
                                    ForecastDays=1,
                                    SkipDays=0,
                                    IconSizePct=100)
        if self.CharSize != [-1]:
            # old style
            logsupport.Logs.Log(
                "TimeTemp screen CharSize parameter deprecated, change to specific block size parameters",
                severity=ConsoleWarning)
            self.ClockSize = extref(self.CharSize, 0)
            self.LocationSize = extref(self.CharSize, 1)
            self.CondSize = extref(self.CharSize, 2)
            self.FcstSize = extref(self.CharSize, 3)
        if self.ForecastDays + self.SkipDays > 10:
            self.ForecastDays = 10 - self.SkipDays
            logsupport.Logs.Log("Long forecast requested; days reduced to: " +
                                str(self.ForecastDays),
                                severity=ConsoleWarning)
        if self.FcstLayout not in ('Block', 'BlockCentered', 'LineCentered',
                                   '2ColVert', '2ColHoriz'):
            logsupport.Logs.Log(
                'FcstLayout Param not Block, BlockCentered, LineCentered, 2ColVert, or 2ColHoriz - using "Block" for ',
                screenname,
                severity=ConsoleWarning)
            self.FcstLayout = "Block"
        self.scrlabel = screen.FlatenScreenLabel(self.label)
        try:
            self.store = valuestore.ValueStores[self.location]
        except KeyError:
            logsupport.Logs.Log(
                "Timetemp screen {} using non-existent location {}".format(
                    screenname, self.location),
                severity=ConsoleWarning)
            raise ValueError
        self.DecodedCondFields = []
        for f in self.ConditionFields:
            if ':' in f:
                self.DecodedCondFields.append(f.split(':'))
            else:
                self.DecodedCondFields.append((self.location, 'Cond', f))

        self.condicon = (self.location, 'Cond',
                         'Icon') if self.CondIcon else None

        self.DecodedFcstFields = []
        for f in self.ForecastFields:
            if ':' in f:
                self.DecodedFcstFields.append(f.split(':'))
            else:
                self.DecodedFcstFields.append((self.location, 'Fcst', f))
        self.fcsticon = (self.location, 'Fcst',
                         'Icon') if self.FcstIcon else None

        self.poster = RepeatingPost(1.0,
                                    paused=True,
                                    name=self.name,
                                    proc=self.repaintClock)
        self.poster.start()
        self.fmt = WFormatter()
Пример #9
0
    def __init__(self, screensection, screenname):
        debug.debugPrint('Screen', "New ThermostatScreenDesc ", screenname)
        screen.BaseKeyScreenDesc.__init__(self, screensection, screenname)
        screen.IncorporateParams(
            self, 'ThermostatScreen',
            {'KeyColor', 'KeyOffOutlineColor', 'KeyOnOutlineColor'},
            screensection)
        self.info = {}
        self.oldinfo = {}
        nominalfontsz = (30, 50, 80, 160)
        nominalspacers = (5, 20, 25, 40, 50, 85)

        self.fsize = []
        self.spacer = []
        if isinstance(self.DefaultHubObj, isy.ISY):
            self.isy = self.DefaultHubObj
            self.ISYObj = self.isy.GetNode(screenname)[0]  # use ControlObj (0)
            if self.ISYObj is None:
                logsupport.Logs.Log("No Thermostat: " + screenname,
                                    severity=ConsoleWarning)
        else:
            logsupport.Logs.Log("Thermostat screen only works with ISY hub",
                                severity=ConsoleError)
            self.ISYObj = None

        self.SetScreenTitle(screen.FlatenScreenLabel(self.label),
                            nominalfontsz[1], self.CharColor)
        self.TempPos = self.startvertspace
        '''
		Size and positions based on vertical screen space less top/bottom borders less default title size of 50
		Compute other fonts sizes based on what is left after that given user ability to set actual title size
		'''
        tempsurf = fonts.fonts.Font(50).render('Temp', 0, wc(
            self.CharColor))  # todo should the 50 be scaled now?
        sizingratio = self.useablevertspace / (self.useablevertspace -
                                               tempsurf.get_height())

        for fs in nominalfontsz:
            self.fsize.append(int(fs * sizingratio))
        for fs in nominalspacers:
            self.spacer.append(int(fs * sizingratio))

        self.StatePos = self.TempPos + fonts.fonts.Font(
            self.fsize[3]).get_linesize() - scaleH(self.spacer[1])
        self.SPPos = self.StatePos + scaleH(self.spacer[2])
        self.AdjButSurf = pygame.Surface(
            (hw.screenwidth, scaleH(self.spacer[3])))
        self.AdjButTops = self.SPPos + fonts.fonts.Font(
            self.fsize[2]).get_linesize() - scaleH(self.spacer[0])
        centerspacing = hw.screenwidth // 5
        self.SPHPosL = int(1.5 * centerspacing)
        self.SPHPosR = int(3.5 * centerspacing)
        self.AdjButSurf.fill(wc(self.BackgroundColor))
        arrowsize = scaleH(self.spacer[3])  # pixel

        for i in range(4):
            gfxdraw.filled_trigon(
                self.AdjButSurf,
                *trifromtop(centerspacing, arrowsize // 2, i + 1, arrowsize,
                            wc(("red", "blue", "red", "blue")[i]), i % 2 != 0))
            self.Keys['temp' + str(i)] = toucharea.TouchPoint(
                'temp' + str(i),
                (centerspacing * (i + 1), self.AdjButTops + arrowsize // 2),
                (arrowsize * 1.2, arrowsize * 1.2),
                proc=functools.partial(self.BumpTemp, ('CLISPH', 'CLISPH',
                                                       'CLISPC', 'CLISPC')[i],
                                       (2, -2, 2, -2)[i]))

        self.ModeButPos = self.AdjButTops + scaleH(self.spacer[5])  # pixel

        bsize = (scaleW(100), scaleH(self.spacer[4]))  # pixel

        self.Keys['Mode'] = toucharea.ManualKeyDesc(
            self,
            "Mode", ["Mode"],
            self.KeyColor,
            self.CharColor,
            self.CharColor,
            center=(self.SPHPosL, self.ModeButPos),
            size=bsize,
            KOn=self.KeyOffOutlineColor,
            proc=functools.partial(self.BumpMode, 'CLIMD', range(8)))

        self.Keys['Fan'] = toucharea.ManualKeyDesc(
            self,
            "Fan", ["Fan"],
            self.KeyColor,
            self.CharColor,
            self.CharColor,
            center=(self.SPHPosR, self.ModeButPos),
            size=bsize,
            KOn=self.KeyOffOutlineColor,
            proc=functools.partial(self.BumpMode, 'CLIFS', (7, 8)))

        self.ModesPos = self.ModeButPos + bsize[1] // 2 + scaleH(
            self.spacer[0])
        if self.ISYObj is not None:
            self.HubInterestList[self.isy.name] = {
                self.ISYObj.address: self.Keys['Mode']
            }  # placeholder for thermostat node
        utilities.register_example("ThermostatScreenDesc", self)