├── ListSelector.py ├── README.md ├── lcdmenu.py ├── lcdmenu.xml └── lcdmenuinit /ListSelector.py: -------------------------------------------------------------------------------- 1 | # ListSelector.py 2 | # 3 | # Created by Alan Aufderheide, February 2013 4 | # 5 | # Given a list of items in the passed list, 6 | # allow quick access by picking letters progressively. 7 | # Uses up/down to go up and down where cursor is. 8 | # Move left/right to further filter to quickly get to item. 9 | # Still need to do case insensitive, and sort. 10 | from time import sleep 11 | from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate 12 | 13 | class ListSelector: 14 | def __init__(self, theList, theLcd): 15 | self.list = [] 16 | for item in theList: 17 | if isinstance(item, basestring): 18 | self.list.append(item) 19 | else: 20 | self.list.append(item[0]) 21 | self.lcd = theLcd 22 | 23 | def Pick(self): 24 | sleep(0.5) 25 | curitem = 0 26 | curlen = 1 27 | self.lcd.clear() 28 | self.lcd.message(self.list[curitem]) 29 | self.lcd.home() 30 | self.lcd.blink() 31 | self.lcd.setCursor(0,0) 32 | while 1: 33 | if self.lcd.buttonPressed(self.lcd.SELECT): 34 | sleep(0.5) 35 | break 36 | if self.lcd.buttonPressed(self.lcd.UP): 37 | tempitem = curitem 38 | prevstr = self.list[tempitem][:curlen] 39 | while tempitem > 0 and self.list[tempitem-1][:curlen-1] == self.list[curitem][:curlen-1] and self.list[tempitem][:curlen] >= prevstr: 40 | tempitem -= 1 41 | curitem = tempitem 42 | # overwrite message, uses spaces to clear previous entries 43 | self.lcd.home() 44 | self.lcd.message(self.list[curitem]+' ') 45 | self.lcd.setCursor(curlen-1,0) 46 | sleep(0.5) 47 | if self.lcd.buttonPressed(self.lcd.DOWN): 48 | nextstr = self.list[curitem][:curlen-1]+chr(ord(self.list[curitem][curlen-1])+1) 49 | tempitem = curitem 50 | while tempitem+1 < len(self.list) and self.list[tempitem+1][:curlen-1] == self.list[curitem][:curlen-1] and self.list[tempitem] < nextstr: 51 | tempitem += 1 52 | if tempitem < len(self.list): 53 | curitem = tempitem 54 | # overwrite message, uses spaces to clear previous entries 55 | self.lcd.home() 56 | self.lcd.message(self.list[curitem]+' ') 57 | self.lcd.setCursor(curlen-1,0) 58 | sleep(0.5) 59 | if self.lcd.buttonPressed(self.lcd.RIGHT): 60 | if curlen < len(self.list[curitem]): 61 | curlen += 1 62 | self.lcd.setCursor(curlen-1,0) 63 | self.lcd.blink() 64 | sleep(0.5) 65 | if self.lcd.buttonPressed(self.lcd.LEFT): 66 | if curlen > 1: 67 | curlen -= 1 68 | else: 69 | sleep(0.5) 70 | curitem = -1 71 | break 72 | self.lcd.setCursor(curlen-1,0) 73 | self.lcd.blink() 74 | sleep(0.5) 75 | 76 | self.lcd.setCursor(0,0) 77 | self.lcd.noBlink() 78 | return curitem 79 | 80 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | RaspberryPiLcdMenu 2 | ================== 3 | 4 | A menu driven application template for the Adafruit LCD Plates on a 5 | Raspberry Pi. 6 | 7 | It provides a simple way to navigate a nested set of menus, and run 8 | various functions, by pressing the buttons on the Adafruit LCD Plate. 9 | Included is a way to determine the IP address of the Pi when running 10 | headless. Also, allows the user to select from a large list of choices 11 | (using List Selector), by cycling through letters vertically and 12 | horizontally. 13 | It uses an XML file to configure the menu structure, and processes tags 14 | to enable different options. XML element support includes: 15 | - folders, for organizing menus. 16 | - widgets, which are really just functions to call in the code. 17 | - run, which allows you to run any command and see the output on the LCD. 18 | 19 | It assumes the user has the LCD Plate from Adafruit already attached. 20 | It is also possible to make a quick modification to the LCD libraries to 21 | detect if the LCD is attached before progressing into the app. Though 22 | with their new updates, not sure how to do that now. Support is 23 | included also to turn on the LCD to different colors. (at least for 24 | the 16x2 positive LCD plate) 25 | You can also launch the Python based application from /etc/init.d using 26 | the provided init file. In that mode, you can launch right into the 27 | application without keyboard or monitor, yet still determine the IP 28 | address, change networks if you like, or any other capability you build 29 | in. Obviously double check the content of the provided init file before 30 | use. Also note that once you put it in init.d, if you don't actually 31 | connect the LCD, you may find lots of error messages. You may want to 32 | test for presence of the LCD before running it. 33 | Included also is an approach to switch networks from the UI, in case you 34 | want to switch between different network layouts if you travel with it. 35 | 36 | Some of the canned menu items are functional, but other are place 37 | holders to spawn ideas. Such as using gphoto2 to trigger DSLR camera 38 | operations, or using raspistill to capture images from the Pi Camera. 39 | Or using the ephem library to do astronomy calculations. Or connecting 40 | the Pi to your GPS to auto locate. 41 | 42 | To get started, put all these files somewhere. Then obtain the Adafruit 43 | LCD python code. From that, copy the files from: 44 | Adafruit-Raspberry-Pi-Python-Code/Adafruit_CharLCDPlate/ 45 | into the same folder as this code. 46 | 47 | Then you should be able to do: 48 | python lcdmenu.py 49 | 50 | Enjoy! 51 | 52 | =========== 53 | Changes: 54 | 24-Oct-2014 55 | - Added support to optionally turn LCD light off/on with use. 56 | - Added support to enter a text phrase into the UI, as a function to 57 | use as you like. 58 | 59 | 25-Jan-2014 60 | - Added support to set date/time 61 | - Fixed bug to allow backing out of ListSelector 62 | - Added support for a reboot command 63 | 64 | Written by Alan Aufderheide 65 | 66 | GPL v3 license, kindly include text above in any redistribution. 67 | -------------------------------------------------------------------------------- /lcdmenu.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # 3 | # Created by Alan Aufderheide, February 2013 4 | # 5 | # This provides a menu driven application using the LCD Plates 6 | # from Adafruit Electronics. 7 | 8 | import commands 9 | import os 10 | from string import split 11 | from time import sleep, strftime, localtime 12 | from datetime import datetime, timedelta 13 | from xml.dom.minidom import * 14 | from Adafruit_I2C import Adafruit_I2C 15 | from Adafruit_MCP230xx import Adafruit_MCP230XX 16 | from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate 17 | from ListSelector import ListSelector 18 | 19 | import smbus 20 | 21 | configfile = 'lcdmenu.xml' 22 | # set DEBUG=1 for print debug statements 23 | DEBUG = 0 24 | DISPLAY_ROWS = 2 25 | DISPLAY_COLS = 16 26 | 27 | # set to 0 if you want the LCD to stay on, 1 to turn off and on auto 28 | AUTO_OFF_LCD = 0 29 | 30 | # set busnum param to the correct value for your pi 31 | lcd = Adafruit_CharLCDPlate(busnum = 1) 32 | # in case you add custom logic to lcd to check if it is connected (useful) 33 | #if lcd.connected == 0: 34 | # quit() 35 | 36 | lcd.begin(DISPLAY_COLS, DISPLAY_ROWS) 37 | lcd.backlight(lcd.OFF) 38 | 39 | # commands 40 | def DoQuit(): 41 | lcd.clear() 42 | lcd.message('Are you sure?\nPress Sel for Y') 43 | while 1: 44 | if lcd.buttonPressed(lcd.LEFT): 45 | break 46 | if lcd.buttonPressed(lcd.SELECT): 47 | lcd.clear() 48 | lcd.backlight(lcd.OFF) 49 | quit() 50 | sleep(0.25) 51 | 52 | def DoShutdown(): 53 | lcd.clear() 54 | lcd.message('Are you sure?\nPress Sel for Y') 55 | while 1: 56 | if lcd.buttonPressed(lcd.LEFT): 57 | break 58 | if lcd.buttonPressed(lcd.SELECT): 59 | lcd.clear() 60 | lcd.backlight(lcd.OFF) 61 | commands.getoutput("sudo shutdown -h now") 62 | quit() 63 | sleep(0.25) 64 | 65 | def DoReboot(): 66 | lcd.clear() 67 | lcd.message('Are you sure?\nPress Sel for Y') 68 | while 1: 69 | if lcd.buttonPressed(lcd.LEFT): 70 | break 71 | if lcd.buttonPressed(lcd.SELECT): 72 | lcd.clear() 73 | lcd.backlight(lcd.OFF) 74 | commands.getoutput("sudo reboot") 75 | quit() 76 | sleep(0.25) 77 | 78 | def LcdOff(): 79 | global currentLcd 80 | currentLcd = lcd.OFF 81 | lcd.backlight(currentLcd) 82 | 83 | def LcdOn(): 84 | global currentLcd 85 | currentLcd = lcd.ON 86 | lcd.backlight(currentLcd) 87 | 88 | def LcdRed(): 89 | global currentLcd 90 | currentLcd = lcd.RED 91 | lcd.backlight(currentLcd) 92 | 93 | def LcdGreen(): 94 | global currentLcd 95 | currentLcd = lcd.GREEN 96 | lcd.backlight(currentLcd) 97 | 98 | def LcdBlue(): 99 | global currentLcd 100 | currentLcd = lcd.BLUE 101 | lcd.backlight(currentLcd) 102 | 103 | def LcdYellow(): 104 | global currentLcd 105 | currentLcd = lcd.YELLOW 106 | lcd.backlight(currentLcd) 107 | 108 | def LcdTeal(): 109 | global currentLcd 110 | currentLcd = lcd.TEAL 111 | lcd.backlight(currentLcd) 112 | 113 | def LcdViolet(): 114 | global currentLcd 115 | currentLcd = lcd.VIOLET 116 | lcd.backlight(currentLcd) 117 | 118 | def ShowDateTime(): 119 | if DEBUG: 120 | print('in ShowDateTime') 121 | lcd.clear() 122 | while not(lcd.buttonPressed(lcd.LEFT)): 123 | sleep(0.25) 124 | lcd.home() 125 | lcd.message(strftime('%a %b %d %Y\n%I:%M:%S %p', localtime())) 126 | 127 | def ValidateDateDigit(current, curval): 128 | # do validation/wrapping 129 | if current == 0: # Mm 130 | if curval < 1: 131 | curval = 12 132 | elif curval > 12: 133 | curval = 1 134 | elif current == 1: #Dd 135 | if curval < 1: 136 | curval = 31 137 | elif curval > 31: 138 | curval = 1 139 | elif current == 2: #Yy 140 | if curval < 1950: 141 | curval = 2050 142 | elif curval > 2050: 143 | curval = 1950 144 | elif current == 3: #Hh 145 | if curval < 0: 146 | curval = 23 147 | elif curval > 23: 148 | curval = 0 149 | elif current == 4: #Mm 150 | if curval < 0: 151 | curval = 59 152 | elif curval > 59: 153 | curval = 0 154 | elif current == 5: #Ss 155 | if curval < 0: 156 | curval = 59 157 | elif curval > 59: 158 | curval = 0 159 | return curval 160 | 161 | def SetDateTime(): 162 | if DEBUG: 163 | print('in SetDateTime') 164 | # M D Y H:M:S AM/PM 165 | curtime = localtime() 166 | month = curtime.tm_mon 167 | day = curtime.tm_mday 168 | year = curtime.tm_year 169 | hour = curtime.tm_hour 170 | minute = curtime.tm_min 171 | second = curtime.tm_sec 172 | ampm = 0 173 | if hour > 11: 174 | hour -= 12 175 | ampm = 1 176 | curr = [0,0,0,1,1,1] 177 | curc = [2,5,11,1,4,7] 178 | curvalues = [month, day, year, hour, minute, second] 179 | current = 0 # start with month, 0..14 180 | 181 | lcd.clear() 182 | lcd.message(strftime("%b %d, %Y \n%I:%M:%S %p ", curtime)) 183 | lcd.blink() 184 | lcd.setCursor(curc[current], curr[current]) 185 | sleep(0.5) 186 | while 1: 187 | curval = curvalues[current] 188 | if lcd.buttonPressed(lcd.UP): 189 | curval += 1 190 | curvalues[current] = ValidateDateDigit(current, curval) 191 | curtime = (curvalues[2], curvalues[0], curvalues[1], curvalues[3], curvalues[4], curvalues[5], 0, 0, 0) 192 | lcd.home() 193 | lcd.message(strftime("%b %d, %Y \n%I:%M:%S %p ", curtime)) 194 | lcd.setCursor(curc[current], curr[current]) 195 | if lcd.buttonPressed(lcd.DOWN): 196 | curval -= 1 197 | curvalues[current] = ValidateDateDigit(current, curval) 198 | curtime = (curvalues[2], curvalues[0], curvalues[1], curvalues[3], curvalues[4], curvalues[5], 0, 0, 0) 199 | lcd.home() 200 | lcd.message(strftime("%b %d, %Y \n%I:%M:%S %p ", curtime)) 201 | lcd.setCursor(curc[current], curr[current]) 202 | if lcd.buttonPressed(lcd.RIGHT): 203 | current += 1 204 | if current > 5: 205 | current = 5 206 | lcd.setCursor(curc[current], curr[current]) 207 | if lcd.buttonPressed(lcd.LEFT): 208 | current -= 1 209 | if current < 0: 210 | lcd.noBlink() 211 | return 212 | lcd.setCursor(curc[current], curr[current]) 213 | if lcd.buttonPressed(lcd.SELECT): 214 | # set the date time in the system 215 | lcd.noBlink() 216 | os.system(strftime('sudo date --set="%d %b %Y %H:%M:%S"', curtime)) 217 | break 218 | sleep(0.25) 219 | 220 | lcd.noBlink() 221 | 222 | def ShowIPAddress(): 223 | if DEBUG: 224 | print('in ShowIPAddress') 225 | lcd.clear() 226 | lcd.message(commands.getoutput("/sbin/ifconfig").split("\n")[1].split()[1][5:]) 227 | while 1: 228 | if lcd.buttonPressed(lcd.LEFT): 229 | break 230 | sleep(0.25) 231 | 232 | #only use the following if you find useful 233 | def Use10Network(): 234 | "Allows you to switch to a different network for local connection" 235 | lcd.clear() 236 | lcd.message('Are you sure?\nPress Sel for Y') 237 | while 1: 238 | if lcd.buttonPressed(lcd.LEFT): 239 | break 240 | if lcd.buttonPressed(lcd.SELECT): 241 | # uncomment the following once you have a separate network defined 242 | #commands.getoutput("sudo cp /etc/network/interfaces.hub.10 /etc/network/interfaces") 243 | lcd.clear() 244 | lcd.message('Please reboot') 245 | sleep(1.5) 246 | break 247 | sleep(0.25) 248 | 249 | #only use the following if you find useful 250 | def UseDHCP(): 251 | "Allows you to switch to a network config that uses DHCP" 252 | lcd.clear() 253 | lcd.message('Are you sure?\nPress Sel for Y') 254 | while 1: 255 | if lcd.buttonPressed(lcd.LEFT): 256 | break 257 | if lcd.buttonPressed(lcd.SELECT): 258 | # uncomment the following once you get an original copy in place 259 | #commands.getoutput("sudo cp /etc/network/interfaces.orig /etc/network/interfaces") 260 | lcd.clear() 261 | lcd.message('Please reboot') 262 | sleep(1.5) 263 | break 264 | sleep(0.25) 265 | 266 | def ShowLatLon(): 267 | if DEBUG: 268 | print('in ShowLatLon') 269 | 270 | def SetLatLon(): 271 | if DEBUG: 272 | print('in SetLatLon') 273 | 274 | def SetLocation(): 275 | if DEBUG: 276 | print('in SetLocation') 277 | global lcd 278 | list = [] 279 | # coordinates usable by ephem library, lat, lon, elevation (m) 280 | list.append(['New York', '40.7143528', '-74.0059731', 9.775694]) 281 | list.append(['Paris', '48.8566667', '2.3509871', 35.917042]) 282 | selector = ListSelector(list, lcd) 283 | item = selector.Pick() 284 | # do something useful 285 | if (item >= 0): 286 | chosen = list[item] 287 | 288 | def CompassGyroViewAcc(): 289 | if DEBUG: 290 | print('in CompassGyroViewAcc') 291 | 292 | def CompassGyroViewMag(): 293 | if DEBUG: 294 | print('in CompassGyroViewMag') 295 | 296 | def CompassGyroViewHeading(): 297 | if DEBUG: 298 | print('in CompassGyroViewHeading') 299 | 300 | def CompassGyroViewTemp(): 301 | if DEBUG: 302 | print('in CompassGyroViewTemp') 303 | 304 | def CompassGyroCalibrate(): 305 | if DEBUG: 306 | print('in CompassGyroCalibrate') 307 | 308 | def CompassGyroCalibrateClear(): 309 | if DEBUG: 310 | print('in CompassGyroCalibrateClear') 311 | 312 | def TempBaroView(): 313 | if DEBUG: 314 | print('in TempBaroView') 315 | 316 | def TempBaroCalibrate(): 317 | if DEBUG: 318 | print('in TempBaroCalibrate') 319 | 320 | def AstroViewAll(): 321 | if DEBUG: 322 | print('in AstroViewAll') 323 | 324 | def AstroViewAltAz(): 325 | if DEBUG: 326 | print('in AstroViewAltAz') 327 | 328 | def AstroViewRADecl(): 329 | if DEBUG: 330 | print('in AstroViewRADecl') 331 | 332 | def CameraDetect(): 333 | if DEBUG: 334 | print('in CameraDetect') 335 | 336 | def CameraTakePicture(): 337 | if DEBUG: 338 | print('in CameraTakePicture') 339 | 340 | def CameraTimeLapse(): 341 | if DEBUG: 342 | print('in CameraTimeLapse') 343 | 344 | # Get a word from the UI, a character at a time. 345 | # Click select to complete input, or back out to the left to quit. 346 | # Return the entered word, or None if they back out. 347 | def GetWord(): 348 | lcd.clear() 349 | lcd.blink() 350 | sleep(0.75) 351 | curword = list("A") 352 | curposition = 0 353 | while 1: 354 | if lcd.buttonPressed(lcd.UP): 355 | if (ord(curword[curposition]) < 127): 356 | curword[curposition] = chr(ord(curword[curposition])+1) 357 | else: 358 | curword[curposition] = chr(32) 359 | if lcd.buttonPressed(lcd.DOWN): 360 | if (ord(curword[curposition]) > 32): 361 | curword[curposition] = chr(ord(curword[curposition])-1) 362 | else: 363 | curword[curposition] = chr(127) 364 | if lcd.buttonPressed(lcd.RIGHT): 365 | if curposition < DISPLAY_COLS - 1: 366 | curword.append('A') 367 | curposition += 1 368 | lcd.setCursor(curposition, 0) 369 | sleep(0.75) 370 | if lcd.buttonPressed(lcd.LEFT): 371 | curposition -= 1 372 | if curposition < 0: 373 | lcd.noBlink() 374 | return 375 | lcd.setCursor(curposition, 0) 376 | if lcd.buttonPressed(lcd.SELECT): 377 | # return the word 378 | sleep(0.75) 379 | return ''.join(curword) 380 | lcd.home() 381 | lcd.message(''.join(curword)) 382 | lcd.setCursor(curposition, 0) 383 | sleep(0.25) 384 | 385 | lcd.noBlink() 386 | 387 | # An example of how to get a word input from the UI, and then 388 | # do something with it 389 | def EnterWord(): 390 | if DEBUG: 391 | print('in EnterWord') 392 | word = GetWord() 393 | lcd.clear() 394 | lcd.home() 395 | if word is not None: 396 | lcd.message('>'+word+'<') 397 | sleep(5) 398 | 399 | class CommandToRun: 400 | def __init__(self, myName, theCommand): 401 | self.text = myName 402 | self.commandToRun = theCommand 403 | def Run(self): 404 | self.clist = split(commands.getoutput(self.commandToRun), '\n') 405 | if len(self.clist) > 0: 406 | lcd.clear() 407 | lcd.message(self.clist[0]) 408 | for i in range(1, len(self.clist)): 409 | while 1: 410 | if lcd.buttonPressed(lcd.DOWN): 411 | break 412 | sleep(0.25) 413 | lcd.clear() 414 | lcd.message(self.clist[i-1]+'\n'+self.clist[i]) 415 | sleep(0.5) 416 | while 1: 417 | if lcd.buttonPressed(lcd.LEFT): 418 | break 419 | 420 | class Widget: 421 | def __init__(self, myName, myFunction): 422 | self.text = myName 423 | self.function = myFunction 424 | 425 | class Folder: 426 | def __init__(self, myName, myParent): 427 | self.text = myName 428 | self.items = [] 429 | self.parent = myParent 430 | 431 | def HandleSettings(node): 432 | global lcd 433 | if node.getAttribute('lcdColor').lower() == 'red': 434 | LcdRed() 435 | elif node.getAttribute('lcdColor').lower() == 'green': 436 | LcdGreen() 437 | elif node.getAttribute('lcdColor').lower() == 'blue': 438 | LcdBlue() 439 | elif node.getAttribute('lcdColor').lower() == 'yellow': 440 | LcdYellow() 441 | elif node.getAttribute('lcdColor').lower() == 'teal': 442 | LcdTeal() 443 | elif node.getAttribute('lcdColor').lower() == 'violet': 444 | LcdViolet() 445 | elif node.getAttribute('lcdColor').lower() == 'white': 446 | LcdOn() 447 | if node.getAttribute('lcdBacklight').lower() == 'on': 448 | LcdOn() 449 | elif node.getAttribute('lcdBacklight').lower() == 'off': 450 | LcdOff() 451 | 452 | def ProcessNode(currentNode, currentItem): 453 | children = currentNode.childNodes 454 | 455 | for child in children: 456 | if isinstance(child, xml.dom.minidom.Element): 457 | if child.tagName == 'settings': 458 | HandleSettings(child) 459 | elif child.tagName == 'folder': 460 | thisFolder = Folder(child.getAttribute('text'), currentItem) 461 | currentItem.items.append(thisFolder) 462 | ProcessNode(child, thisFolder) 463 | elif child.tagName == 'widget': 464 | thisWidget = Widget(child.getAttribute('text'), child.getAttribute('function')) 465 | currentItem.items.append(thisWidget) 466 | elif child.tagName == 'run': 467 | thisCommand = CommandToRun(child.getAttribute('text'), child.firstChild.data) 468 | currentItem.items.append(thisCommand) 469 | 470 | class Display: 471 | def __init__(self, folder): 472 | self.curFolder = folder 473 | self.curTopItem = 0 474 | self.curSelectedItem = 0 475 | def display(self): 476 | if self.curTopItem > len(self.curFolder.items) - DISPLAY_ROWS: 477 | self.curTopItem = len(self.curFolder.items) - DISPLAY_ROWS 478 | if self.curTopItem < 0: 479 | self.curTopItem = 0 480 | if DEBUG: 481 | print('------------------') 482 | str = '' 483 | for row in range(self.curTopItem, self.curTopItem+DISPLAY_ROWS): 484 | if row > self.curTopItem: 485 | str += '\n' 486 | if row < len(self.curFolder.items): 487 | if row == self.curSelectedItem: 488 | cmd = '-'+self.curFolder.items[row].text 489 | if len(cmd) < 16: 490 | for row in range(len(cmd), 16): 491 | cmd += ' ' 492 | if DEBUG: 493 | print('|'+cmd+'|') 494 | str += cmd 495 | else: 496 | cmd = ' '+self.curFolder.items[row].text 497 | if len(cmd) < 16: 498 | for row in range(len(cmd), 16): 499 | cmd += ' ' 500 | if DEBUG: 501 | print('|'+cmd+'|') 502 | str += cmd 503 | if DEBUG: 504 | print('------------------') 505 | lcd.home() 506 | lcd.message(str) 507 | 508 | def update(self, command): 509 | global currentLcd 510 | global lcdstart 511 | lcd.backlight(currentLcd) 512 | lcdstart = datetime.now() 513 | if DEBUG: 514 | print('do',command) 515 | if command == 'u': 516 | self.up() 517 | elif command == 'd': 518 | self.down() 519 | elif command == 'r': 520 | self.right() 521 | elif command == 'l': 522 | self.left() 523 | elif command == 's': 524 | self.select() 525 | def up(self): 526 | if self.curSelectedItem == 0: 527 | return 528 | elif self.curSelectedItem > self.curTopItem: 529 | self.curSelectedItem -= 1 530 | else: 531 | self.curTopItem -= 1 532 | self.curSelectedItem -= 1 533 | def down(self): 534 | if self.curSelectedItem+1 == len(self.curFolder.items): 535 | return 536 | elif self.curSelectedItem < self.curTopItem+DISPLAY_ROWS-1: 537 | self.curSelectedItem += 1 538 | else: 539 | self.curTopItem += 1 540 | self.curSelectedItem += 1 541 | def left(self): 542 | if isinstance(self.curFolder.parent, Folder): 543 | # find the current in the parent 544 | itemno = 0 545 | index = 0 546 | for item in self.curFolder.parent.items: 547 | if self.curFolder == item: 548 | if DEBUG: 549 | print('foundit') 550 | index = itemno 551 | else: 552 | itemno += 1 553 | if index < len(self.curFolder.parent.items): 554 | self.curFolder = self.curFolder.parent 555 | self.curTopItem = index 556 | self.curSelectedItem = index 557 | else: 558 | self.curFolder = self.curFolder.parent 559 | self.curTopItem = 0 560 | self.curSelectedItem = 0 561 | def right(self): 562 | if isinstance(self.curFolder.items[self.curSelectedItem], Folder): 563 | self.curFolder = self.curFolder.items[self.curSelectedItem] 564 | self.curTopItem = 0 565 | self.curSelectedItem = 0 566 | elif isinstance(self.curFolder.items[self.curSelectedItem], Widget): 567 | if DEBUG: 568 | print('eval', self.curFolder.items[self.curSelectedItem].function) 569 | eval(self.curFolder.items[self.curSelectedItem].function+'()') 570 | elif isinstance(self.curFolder.items[self.curSelectedItem], CommandToRun): 571 | self.curFolder.items[self.curSelectedItem].Run() 572 | 573 | def select(self): 574 | if DEBUG: 575 | print('check widget') 576 | if isinstance(self.curFolder.items[self.curSelectedItem], Widget): 577 | if DEBUG: 578 | print('eval', self.curFolder.items[self.curSelectedItem].function) 579 | eval(self.curFolder.items[self.curSelectedItem].function+'()') 580 | 581 | # now start things up 582 | uiItems = Folder('root','') 583 | 584 | dom = parse(configfile) # parse an XML file by name 585 | 586 | top = dom.documentElement 587 | 588 | currentLcd = lcd.OFF 589 | LcdOff() 590 | ProcessNode(top, uiItems) 591 | 592 | display = Display(uiItems) 593 | display.display() 594 | 595 | if DEBUG: 596 | print('start while') 597 | 598 | lcdstart = datetime.now() 599 | while 1: 600 | if (lcd.buttonPressed(lcd.LEFT)): 601 | display.update('l') 602 | display.display() 603 | sleep(0.25) 604 | 605 | if (lcd.buttonPressed(lcd.UP)): 606 | display.update('u') 607 | display.display() 608 | sleep(0.25) 609 | 610 | if (lcd.buttonPressed(lcd.DOWN)): 611 | display.update('d') 612 | display.display() 613 | sleep(0.25) 614 | 615 | if (lcd.buttonPressed(lcd.RIGHT)): 616 | display.update('r') 617 | display.display() 618 | sleep(0.25) 619 | 620 | if (lcd.buttonPressed(lcd.SELECT)): 621 | display.update('s') 622 | display.display() 623 | sleep(0.25) 624 | 625 | if AUTO_OFF_LCD: 626 | lcdtmp = lcdstart + timedelta(seconds=5) 627 | if (datetime.now() > lcdtmp): 628 | lcd.backlight(lcd.OFF) 629 | 630 | -------------------------------------------------------------------------------- /lcdmenu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ls 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /lcdmenuinit: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # /etc/init.d/lcdmenuinit 3 | 4 | case "$1" in 5 | start) 6 | echo "Starting lcdmenu" 7 | cd /home/pi/lcdmenu 8 | sudo /usr/bin/python /home/pi/lcdmenu/lcdmenu.py & 9 | ;; 10 | stop) 11 | echo "Stopping lcdmenu" 12 | killall python 13 | ;; 14 | *) 15 | echo "Usage: /etc/init.d/lcdmenuinit {start|stop}" 16 | exit 1 17 | ;; 18 | esac 19 | 20 | exit 0 21 | --------------------------------------------------------------------------------