|
#!/usr/bin/env python3 |
|
|
|
# Copyright (c) 2019 OBONO |
|
# |
|
# Permission is hereby granted, free of charge, to any person obtaining a copy |
|
# of this software and associated documentation files (the "Software"), to deal |
|
# in the Software without restriction, including without limitation the rights |
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
# copies of the Software, and to permit persons to whom the Software is |
|
# furnished to do so, subject to the following conditions: |
|
# |
|
# The above copyright notice and this permission notice shall be included in all |
|
# copies or substantial portions of the Software. |
|
# |
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
# SOFTWARE. |
|
|
|
import Adafruit_GPIO.SPI as SPI |
|
import Adafruit_SSD1306 |
|
import RPi.GPIO as GPIO |
|
import subprocess |
|
import sys |
|
import time |
|
|
|
FONT_DATA = [ # import from "glcdfont.c" |
|
b"\x00\x00\x00\x00\x00", b"\x00\x00\x5f\x00\x00", b"\x00\x07\x00\x07\x00", |
|
b"\x14\x7f\x14\x7f\x14", b"\x24\x2a\x7f\x2a\x12", b"\x23\x13\x08\x64\x62", |
|
b"\x36\x49\x56\x20\x50", b"\x00\x08\x07\x03\x00", b"\x00\x1c\x22\x41\x00", |
|
b"\x00\x41\x22\x1c\x00", b"\x2a\x1c\x7f\x1c\x2a", b"\x08\x08\x3e\x08\x08", |
|
b"\x00\x80\x70\x30\x00", b"\x08\x08\x08\x08\x08", b"\x00\x00\x60\x60\x00", |
|
b"\x20\x10\x08\x04\x02", b"\x3e\x51\x49\x45\x3e", b"\x00\x42\x7f\x40\x00", |
|
b"\x72\x49\x49\x49\x46", b"\x21\x41\x49\x4d\x33", b"\x18\x14\x12\x7f\x10", |
|
b"\x27\x45\x45\x45\x39", b"\x3c\x4a\x49\x49\x31", b"\x41\x21\x11\x09\x07", |
|
b"\x36\x49\x49\x49\x36", b"\x46\x49\x49\x29\x1e", b"\x00\x00\x14\x00\x00", |
|
b"\x00\x40\x34\x00\x00", b"\x00\x08\x14\x22\x41", b"\x14\x14\x14\x14\x14", |
|
b"\x00\x41\x22\x14\x08", b"\x02\x01\x59\x09\x06", b"\x3e\x41\x5d\x59\x4e", |
|
b"\x7c\x12\x11\x12\x7c", b"\x7f\x49\x49\x49\x36", b"\x3e\x41\x41\x41\x22", |
|
b"\x7f\x41\x41\x41\x3e", b"\x7f\x49\x49\x49\x41", b"\x7f\x09\x09\x09\x01", |
|
b"\x3e\x41\x41\x51\x73", b"\x7f\x08\x08\x08\x7f", b"\x00\x41\x7f\x41\x00", |
|
b"\x20\x40\x41\x3f\x01", b"\x7f\x08\x14\x22\x41", b"\x7f\x40\x40\x40\x40", |
|
b"\x7f\x02\x1c\x02\x7f", b"\x7f\x04\x08\x10\x7f", b"\x3e\x41\x41\x41\x3e", |
|
b"\x7f\x09\x09\x09\x06", b"\x3e\x41\x51\x21\x5e", b"\x7f\x09\x19\x29\x46", |
|
b"\x26\x49\x49\x49\x32", b"\x03\x01\x7f\x01\x03", b"\x3f\x40\x40\x40\x3f", |
|
b"\x1f\x20\x40\x20\x1f", b"\x3f\x40\x38\x40\x3f", b"\x63\x14\x08\x14\x63", |
|
b"\x03\x04\x78\x04\x03", b"\x61\x59\x49\x4d\x43", b"\x00\x7f\x41\x41\x41", |
|
b"\x02\x04\x08\x10\x20", b"\x00\x41\x41\x41\x7f", b"\x04\x02\x01\x02\x04", |
|
b"\x40\x40\x40\x40\x40", b"\x00\x03\x07\x08\x00", b"\x20\x54\x54\x78\x40", |
|
b"\x7f\x28\x44\x44\x38", b"\x38\x44\x44\x44\x28", b"\x38\x44\x44\x28\x7f", |
|
b"\x38\x54\x54\x54\x18", b"\x00\x08\x7e\x09\x02", b"\x18\xa4\xa4\x9c\x78", |
|
b"\x7f\x08\x04\x04\x78", b"\x00\x44\x7d\x40\x00", b"\x20\x40\x40\x3d\x00", |
|
b"\x7f\x10\x28\x44\x00", b"\x00\x41\x7f\x40\x00", b"\x7c\x04\x78\x04\x78", |
|
b"\x7c\x08\x04\x04\x78", b"\x38\x44\x44\x44\x38", b"\xfc\x18\x24\x24\x18", |
|
b"\x18\x24\x24\x18\xfc", b"\x7c\x08\x04\x04\x08", b"\x48\x54\x54\x54\x24", |
|
b"\x04\x04\x3f\x44\x24", b"\x3c\x40\x40\x20\x7c", b"\x1c\x20\x40\x20\x1c", |
|
b"\x3c\x40\x30\x40\x3c", b"\x44\x28\x10\x28\x44", b"\x4c\x90\x90\x90\x7c", |
|
b"\x44\x64\x54\x4c\x44", b"\x00\x08\x36\x41\x00", b"\x00\x00\x77\x00\x00", |
|
b"\x00\x41\x36\x08\x00", b"\x02\x01\x02\x04\x02" |
|
] |
|
FONT_WIDTH = 6 |
|
BUTTON_PIN = 17 |
|
BOUNCE_TIME = 300 |
|
LOOP_WAIT = 5 |
|
DISP_COUNT_MAX = 6 |
|
|
|
### Custom class |
|
|
|
class MySSD1306(Adafruit_SSD1306.SSD1306_128_64): |
|
|
|
def __init__(self): |
|
super().__init__(rst=None) |
|
|
|
def putstring(self, page, x, str): |
|
for c in str: |
|
if 0x20 <= c <= 0x7e: |
|
self.putchar(page, x, c) |
|
x += FONT_WIDTH |
|
elif c == 0x0a: |
|
page += 1 |
|
x = 0 |
|
|
|
def putchar(self, page, x, c): |
|
idx = page * self.width + x |
|
buffer_len = len(self._buffer) |
|
for b in FONT_DATA[c - 0x20]: |
|
if 0 <= idx < buffer_len: self._buffer[idx] = b |
|
idx += 1 |
|
|
|
def on(self): |
|
self.command(Adafruit_SSD1306.SSD1306_DISPLAYON) |
|
|
|
def off(self): |
|
self.command(Adafruit_SSD1306.SSD1306_DISPLAYOFF) |
|
|
|
### Callback function |
|
|
|
def gpio_handler(gpio_pin): |
|
global disp, disp_count, script |
|
if disp_count == 0: disp.on() |
|
disp_count = DISP_COUNT_MAX |
|
disp.clear() |
|
text = subprocess.check_output(script) |
|
disp.putstring(0, 0, text) |
|
disp.display() |
|
|
|
### Main procedure |
|
|
|
disp = MySSD1306() |
|
disp.begin() |
|
disp.off() |
|
disp_count = 0 |
|
script = sys.argv[1] if len(sys.argv) >= 2 else "date '+%T'" |
|
|
|
GPIO.setmode(GPIO.BCM) |
|
GPIO.setup(BUTTON_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) |
|
GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callback=gpio_handler, bouncetime=BOUNCE_TIME) |
|
|
|
try: |
|
while True: |
|
time.sleep(LOOP_WAIT) |
|
if disp_count > 0: |
|
disp_count -= 1 |
|
if disp_count == 0: disp.off() |
|
except KeyboardInterrupt: |
|
GPIO.cleanup() |