Add application code and install script
This commit is contained in:
		
							parent
							
								
									213d1cc99b
								
							
						
					
					
						commit
						0cc16d97a4
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,2 @@ | ||||
| __pycache__/ | ||||
| *.swp | ||||
							
								
								
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1 @@ | ||||
| python 3.10.9 | ||||
							
								
								
									
										152
									
								
								character_display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								character_display.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,152 @@ | ||||
| # There are 4 different types of patterns used when generating | ||||
| # a number that is to be placed in a rectangle 3X5 pixels. Combinations of these | ||||
| # are used to create a number pattern such as: | ||||
| #   * * * | ||||
| #   * | ||||
| #   * * * | ||||
| #   *   * | ||||
| #   * * * | ||||
| 
 | ||||
| # 1) * * * Full Row | ||||
| # 2) *   * Both Sides | ||||
| # 3)     * Right Side | ||||
| # 4) *     Left Side | ||||
| 
 | ||||
| 
 | ||||
| class CharacterDisplay: | ||||
| 
 | ||||
|     def __init__(self, unicorn): | ||||
|         self.unicorn = unicorn | ||||
| 
 | ||||
|     def fullLine(self, start, row): | ||||
|         for x in range(max(start, 0), start+3): | ||||
|             self.unicorn.set_pixel(x, row, 255, 0, 0) | ||||
| 
 | ||||
|     def bothSides(self, start, row): | ||||
|         if (start >= 0): | ||||
|             self.unicorn.set_pixel(start, row, 255, 0, 0) | ||||
| 
 | ||||
|         self.unicorn.set_pixel(start+2, row, 255, 0, 0) | ||||
| 
 | ||||
|     def leftSide(self, start, row): | ||||
|         if (start >= 0): | ||||
|             self.unicorn.set_pixel(start, row, 255, 0, 0) | ||||
| 
 | ||||
|     def rightSide(self, start, row): | ||||
|         self.unicorn.set_pixel(start+2, row, 255, 0, 0) | ||||
| 
 | ||||
|     def displayZero(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.bothSides(x, y-1) | ||||
|         self.bothSides(x, y-2) | ||||
|         self.bothSides(x, y-3) | ||||
|         self.fullLine(x, y-4) | ||||
| 
 | ||||
|     def displayOne(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.rightSide(x, y) | ||||
|         self.rightSide(x, y-1) | ||||
|         self.rightSide(x, y-2) | ||||
|         self.rightSide(x, y-3) | ||||
|         self.rightSide(x, y-4) | ||||
| 
 | ||||
|     def displayTwo(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.rightSide(x, y-1) | ||||
|         self.fullLine(x, y-2) | ||||
|         self.leftSide(x, y-3) | ||||
|         self.fullLine(x, y-4) | ||||
| 
 | ||||
|     def displayThree(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.rightSide(x, y-1) | ||||
|         self.fullLine(x, y-2) | ||||
|         self.rightSide(x, y-3) | ||||
|         self.fullLine(x, y-4) | ||||
| 
 | ||||
|     def displayFour(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.bothSides(x, y) | ||||
|         self.bothSides(x, y-1) | ||||
|         self.fullLine(x, y-2) | ||||
|         self.rightSide(x, y-3) | ||||
|         self.rightSide(x, y-4) | ||||
| 
 | ||||
|     def displayFive(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.leftSide(x, y-1) | ||||
|         self.fullLine(x, y-2) | ||||
|         self.rightSide(x, y-3) | ||||
|         self.fullLine(x, y-4) | ||||
| 
 | ||||
|     def displaySix(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.leftSide(x, y-1) | ||||
|         self.fullLine(x, y-2) | ||||
|         self.bothSides(x, y-3) | ||||
|         self.fullLine(x, y-4) | ||||
| 
 | ||||
|     def displaySeven(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.rightSide(x, y-1) | ||||
|         self.rightSide(x, y-2) | ||||
|         self.rightSide(x, y-3) | ||||
|         self.rightSide(x, y-4) | ||||
| 
 | ||||
|     def displayEight(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.bothSides(x, y-1) | ||||
|         self.fullLine(x, y-2) | ||||
|         self.bothSides(x, y-3) | ||||
|         self.fullLine(x, y-4) | ||||
| 
 | ||||
|     def displayNine(self, x, y): | ||||
|         self.clearNumberPixels(x, y) | ||||
|         self.fullLine(x, y) | ||||
|         self.bothSides(x, y-1) | ||||
|         self.fullLine(x, y-2) | ||||
|         self.rightSide(x, y-3) | ||||
|         self.fullLine(x, y-4) | ||||
| 
 | ||||
|     def displayNumber(self, x, y, number): | ||||
|         if number == 0: | ||||
|             self.displayZero(x, y) | ||||
|         elif number == 1: | ||||
|             self.displayOne(x, y) | ||||
|         elif number == 2: | ||||
|             self.displayTwo(x, y) | ||||
|         elif number == 3: | ||||
|             self.displayThree(x, y) | ||||
|         elif number == 4: | ||||
|             self.displayFour(x, y) | ||||
|         elif number == 5: | ||||
|             self.displayFive(x, y) | ||||
|         elif number == 6: | ||||
|             self.displaySix(x, y) | ||||
|         elif number == 7: | ||||
|             self.displaySeven(x, y) | ||||
|         elif number == 8: | ||||
|             self.displayEight(x, y) | ||||
|         elif number == 9: | ||||
|             self.displayNine(x, y) | ||||
| 
 | ||||
|         self.unicorn.show() | ||||
| 
 | ||||
|     def clearNumberPixels(self, x, y): | ||||
|         for y1 in range(y, y-5, -1): | ||||
|             for x1 in range(max(x, 0), x+3): | ||||
|                 self.unicorn.set_pixel(x1, y1, 0, 0, 0) | ||||
| 
 | ||||
|         self.unicorn.show() | ||||
| 
 | ||||
|     def displayTimeDots(self, x, y): | ||||
|         self.unicorn.set_pixel(x, y-1, 255, 0, 0) | ||||
|         self.unicorn.set_pixel(x, y-3, 255, 0, 0) | ||||
|         self.unicorn.show() | ||||
							
								
								
									
										37
									
								
								chutney.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								chutney.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| import sys | ||||
| 
 | ||||
| from character_display import CharacterDisplay | ||||
| from signal import signal, SIGTERM | ||||
| from time import sleep | ||||
| from time_display import TimeDisplay | ||||
| 
 | ||||
| try: | ||||
|     import unicornhathd as unicorn | ||||
|     unicorn.rotation(90) | ||||
| except ImportError: | ||||
|     from unicorn_hat_sim import unicornhathd as unicorn | ||||
|     unicorn.rotation(180) | ||||
| 
 | ||||
| 
 | ||||
| def cleanExit(unicorn): | ||||
|     def _exit_(signum, frame): | ||||
|         unicorn.off() | ||||
|         sys.exit(0) | ||||
| 
 | ||||
|     return _exit_ | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|     signal(SIGTERM, cleanExit(unicorn)) | ||||
|     unicorn.brightness(0.3) | ||||
| 
 | ||||
|     character_display = CharacterDisplay(unicorn) | ||||
|     timeDisplay = TimeDisplay(character_display, lineTop=15) | ||||
| 
 | ||||
|     while True: | ||||
|         timeDisplay.showTime() | ||||
|         sleep(1) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
							
								
								
									
										3
									
								
								chutney.sample.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								chutney.sample.cfg
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | ||||
| [DEFAULT] | ||||
| weather_user=user | ||||
| weather_pass=password | ||||
							
								
								
									
										13
									
								
								chutney.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								chutney.service
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | ||||
| [Unit] | ||||
| Description=Chutney | ||||
| After=multi.user.target | ||||
| 
 | ||||
| [Service] | ||||
| Type=simple | ||||
| WorkingDirectory=$workingDirectory | ||||
| ExecStart=$execStart | ||||
| Restart=on-failure | ||||
| SyslogIdentifier=chutney | ||||
| 
 | ||||
| [Install] | ||||
| WantedBy=multi-user.target | ||||
							
								
								
									
										33
									
								
								install
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										33
									
								
								install
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,33 @@ | ||||
| #! /usr/bin/env python3 | ||||
| 
 | ||||
| import os | ||||
| import sys | ||||
| 
 | ||||
| from string import Template | ||||
| from subprocess import check_call | ||||
| 
 | ||||
| EXEC       = 'chutney.py' | ||||
| SERVICE    = 'chutney.service' | ||||
| SYSTEM_DIR = '/etc/systemd/system' | ||||
| 
 | ||||
| CURRENT_DIR      = os.path.dirname(os.path.realpath(__file__)) | ||||
| SERVICE_TEMPLATE = os.path.join(CURRENT_DIR, SERVICE) | ||||
| SERVICE_FILE     = os.path.join(SYSTEM_DIR, SERVICE) | ||||
| PYTHON           = sys.executable | ||||
| EXEC_START       = f'{PYTHON} {EXEC}' | ||||
| 
 | ||||
| with open(SERVICE_TEMPLATE) as f: | ||||
|     serviceTemplate = Template(f.read()) | ||||
| 
 | ||||
| serviceFile = serviceTemplate.substitute( | ||||
|     workingDirectory=CURRENT_DIR, | ||||
|     execStart=EXEC_START | ||||
| ) | ||||
| 
 | ||||
| with open(SERVICE_FILE, 'w') as f: | ||||
|     f.write(serviceFile) | ||||
| 
 | ||||
| check_call(['systemctl', 'daemon-reload']) | ||||
| check_call(['systemctl', 'enable', '--no-pager', SERVICE]) | ||||
| check_call(['systemctl', 'restart', '--no-pager', SERVICE]) | ||||
| check_call(['systemctl', 'status', '--no-pager', SERVICE]) | ||||
							
								
								
									
										41
									
								
								time_display.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								time_display.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | ||||
| from datetime import datetime | ||||
| 
 | ||||
| 
 | ||||
| class TimeDisplay: | ||||
| 
 | ||||
|     def __init__(self, character_display, lineTop): | ||||
|         self.displayedHourParts = [-1, -1] | ||||
|         self.displayedMinuteParts = [-1, -1] | ||||
|         self.character_display = character_display | ||||
|         self.lineTop = lineTop | ||||
| 
 | ||||
|         self.character_display.displayTimeDots(7, self.lineTop) | ||||
| 
 | ||||
|     def showTime(self): | ||||
|         hourParts = self.getTimeParts('%l') | ||||
|         minuteParts = self.getTimeParts('%M') | ||||
| 
 | ||||
|         if hourParts[0] != self.displayedHourParts[0]: | ||||
|             self.displayedHourParts[0] = hourParts[0] | ||||
| 
 | ||||
|             if hourParts[0] == 0: | ||||
|                 self.character_display.clearNumberPixels(-1, self.lineTop) | ||||
|             else: | ||||
|                 self.character_display.displayNumber(-1, self.lineTop, hourParts[0]) | ||||
| 
 | ||||
|         if hourParts[1] != self.displayedHourParts[1]: | ||||
|             self.displayedHourParts[1] = hourParts[1] | ||||
|             self.character_display.displayNumber(3, self.lineTop, hourParts[1]) | ||||
| 
 | ||||
|         if minuteParts[0] != self.displayedMinuteParts[0]: | ||||
|             self.displayedMinuteParts[0] = minuteParts[0] | ||||
|             self.character_display.displayNumber(9, self.lineTop, minuteParts[0]) | ||||
| 
 | ||||
|         if minuteParts[1] != self.displayedMinuteParts[1]: | ||||
|             self.displayedMinuteParts[1] = minuteParts[1] | ||||
|             self.character_display.displayNumber(13, self.lineTop, minuteParts[1]) | ||||
| 
 | ||||
|     def getTimeParts(self, timePart): | ||||
|         parts = datetime.now().strftime(timePart).strip().rjust(2, "0") | ||||
| 
 | ||||
|         return [int(x) for x in parts] | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user