Last active
August 26, 2018 19:05
-
-
Save d3d9/694370048c8255b289bbfcdcf0855506 to your computer and use it in GitHub Desktop.
boxmatrix.py: stellt Boxdaten siehe https://gist.github.com/d3d9/fc3ab7a8c6af6212a25f9456c866cb0b mit https://github.com/hzeller/rpi-rgb-led-matrix auf LED-Matrizen dar
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3.7 | |
# -*- coding: utf-8 -*- | |
import traceback | |
import argparse | |
from radbox import * | |
from datetime import datetime | |
from decimal import Decimal, ROUND_HALF_UP | |
from subprocess import check_output | |
from rgbmatrix import RGBMatrix, RGBMatrixOptions, graphics | |
from time import localtime, sleep | |
from PIL import Image | |
### Arguments | |
parser = argparse.ArgumentParser() | |
parser.add_argument("-u", "--base-url", action="store", help="Box service URL (not the booking page)", default=URL("https://www.dein-radschloss.de/"), type=URL) | |
parser.add_argument("-i", "--station-id", action="store", help="Station ID to be selected. Default: 185", default='185', type=str) | |
parser.add_argument("-r", "--enable-right", action="store_true", help="Enable sidebar on the right side with additional info.") | |
parser.add_argument("-sx", "--box-spacing-x", action="store", help="Horizontal space between boxes. Default: 2", default=2, type=int) | |
parser.add_argument("-sy", "--box-spacing-y", action="store", help="Vertical space between boxes. Default: 2", default=2, type=int) | |
parser.add_argument("--disable-progress", action="store_false", help="Disable progress bar at the bottom") | |
parser.add_argument("-d", "--daemon", action="store_true", help="Run as daemon") | |
parser.add_argument("--update-steps", action="store", help="Loop steps until reload of data. Default: 1500", default=1500, type=int) | |
parser.add_argument("--sleep-interval", action="store", help="Sleep interval (inside the main loop). Default: 0.0375", default=0.0375, type=float) | |
# matrix settings | |
parser.add_argument("-c", "--led-chain", action="store", help="Daisy-chained boards. Default: 2.", default=2, type=int) | |
parser.add_argument("-b", "--led-brightness", action="store", help="Sets brightness level. Default: 30. Range: 1..100", default=30, type=int) | |
parser.add_argument("--led-rows", action="store", help="Display rows. 16 for 16x32, 32 for 32x32. Default: 32", default=32, type=int) | |
parser.add_argument("--led-cols", action="store", help="Panel columns. Typically 32 or 64. (Default: 64)", default=64, type=int) | |
parser.add_argument("--led-parallel", action="store", help="For Plus-models or RPi2: parallel chains. 1..3. Default: 1", default=1, type=int) | |
parser.add_argument("--led-pwm-bits", action="store", help="Bits used for PWM. Something between 1..11. Default: 11", default=11, type=int) | |
parser.add_argument("--led-gpio-mapping", help="Hardware Mapping: regular, adafruit-hat, adafruit-hat-pwm" , choices=['regular', 'adafruit-hat', 'adafruit-hat-pwm'], type=str) | |
parser.add_argument("--led-scan-mode", action="store", help="Progressive or interlaced scan. 0 Progressive, 1 Interlaced (default)", default=1, choices=range(2), type=int) | |
parser.add_argument("--led-pwm-lsb-nanoseconds", action="store", help="Base time-unit for the on-time in the lowest significant bit in nanoseconds. Default: 130", default=130, type=int) | |
parser.add_argument("--led-show-refresh", action="store_true", help="Shows the current refresh rate of the LED panel") | |
parser.add_argument("--led-slowdown-gpio", action="store", help="Slow down writing to GPIO. Range: 1..100. Default: 1", choices=range(3), type=int) | |
parser.add_argument("--led-no-hardware-pulse", action="store", help="Don't use hardware pin-pulse generation") | |
parser.add_argument("--led-rgb-sequence", action="store", help="Switch if your matrix has led colors swapped. Default: RGB", default="RGB", type=str) | |
parser.add_argument("--led-pixel-mapper", action="store", help="Apply pixel mappers. e.g \"Rotate:90\"", default="", type=str) | |
parser.add_argument("--led-row-addr-type", action="store", help="0 = default; 1=AB-addressed panels;2=row direct", default=0, type=int, choices=[0,1,2]) | |
parser.add_argument("--led-multiplexing", action="store", help="Multiplexing type: 0=direct; 1=strip; 2=checker; 3=spiral; 4=ZStripe; 5=ZnMirrorZStripe; 6=coreman; 7=Kaler2Scan; 8=ZStripeUneven (Default: 0)", default=0, type=int) | |
args = parser.parse_args() | |
options = RGBMatrixOptions() | |
if args.led_gpio_mapping != None: | |
options.hardware_mapping = args.led_gpio_mapping | |
options.rows = args.led_rows | |
options.cols = args.led_cols | |
options.chain_length = args.led_chain | |
options.parallel = args.led_parallel | |
options.row_address_type = args.led_row_addr_type | |
options.multiplexing = args.led_multiplexing | |
options.pwm_bits = args.led_pwm_bits | |
options.brightness = args.led_brightness | |
options.pwm_lsb_nanoseconds = args.led_pwm_lsb_nanoseconds | |
options.led_rgb_sequence = args.led_rgb_sequence | |
options.pixel_mapper_config = args.led_pixel_mapper | |
if args.led_show_refresh: | |
options.show_refresh_rate = 1 | |
if args.led_slowdown_gpio != None: | |
options.gpio_slowdown = args.led_slowdown_gpio | |
if args.led_no_hardware_pulse: | |
options.disable_hardware_pulsing = True | |
options.daemon = args.daemon | |
options.drop_privileges = 1 | |
matrix = RGBMatrix(options=options) | |
canvas = matrix.CreateFrameCanvas() | |
### Fonts | |
fontdir = "../rpi-rgb-led-matrix/fonts/" | |
fontmin = graphics.Font() | |
fontmin.LoadFont(fontdir+"tom-thumb.bdf") | |
fontnum = graphics.Font() | |
fontnum.LoadFont(fontdir+"4x6.bdf") | |
fontlargernum = graphics.Font() | |
fontlargernum.LoadFont(fontdir+"5x7.bdf") | |
### Colors | |
bookableColor = graphics.Color(0, 255, 0) | |
occupiedColor = graphics.Color(255, 0, 0) | |
lighttextColor = graphics.Color(100, 100, 100) | |
textColor = graphics.Color(190, 190, 190) | |
barColor = graphics.Color(8, 8, 8) | |
if options.brightness < 15: | |
barColor = graphics.Color(12, 12, 12) | |
### Display configuration | |
stationid = args.station_id | |
step = args.update_steps | |
interval = args.sleep_interval | |
rightbar = args.enable_right | |
progress = args.disable_progress | |
spacebr = 1 | |
text_startr = 8 | |
lineheight = 6 | |
rightbarwidth = 21 | |
### End of configuration | |
def drawtime(canvas, x_max, r, color, hour, minute, large=False): | |
width = x_max+1 | |
if large: | |
graphics.DrawText(canvas, fontlargernum, width - 21, r, color, str(hour).zfill(2)) | |
canvas.SetPixel(width - 11, r-4, color.red, color.green, color.blue) | |
canvas.SetPixel(width - 11, r-2, color.red, color.green, color.blue) | |
graphics.DrawText(canvas, fontlargernum, width - 9, r, color, str(minute).zfill(2)) | |
else: | |
graphics.DrawText(canvas, fontnum, width - 17, r, color, str(hour).zfill(2)) | |
canvas.SetPixel(width - 9, r-4, color.red, color.green, color.blue) | |
canvas.SetPixel(width - 9, r-2, color.red, color.green, color.blue) | |
graphics.DrawText(canvas, fontnum, width - 7, r, color, str(minute).zfill(2)) | |
def drawppm(canvas, ppm, cx, cy, unsafe=True): | |
canvas.SetImage(ppm, cx-ppm.size[0]//2, cy-ppm.size[1]//2, unsafe) | |
return canvas | |
def drawsquare(canvas, x1, y1, x2, y2, color): | |
for y in range(y1, y2): | |
graphics.DrawLine(canvas, x1, y, x2, y, color) | |
cx = (x1+x2)//2 | |
cy = (y1+y2)//2 | |
return canvas, (cx, cy) | |
def loop(canvas, baseurl, station): | |
i = 0 | |
x_max = canvas.width - 1 - (rightbarwidth + spacebr)*int(rightbar) | |
y_max = canvas.height - 1 | |
sqw = 0 | |
sqh = 0 | |
spx = args.box_spacing_x | |
spy = args.box_spacing_y | |
time_measure = datetime.now() | |
prev_time_measure = datetime.now() | |
while True: | |
canvas.Clear() | |
r = text_startr | |
if not i % step: | |
try: | |
if not station.getinfo(baseurl=baseurl, loadprices=False): | |
print("loading current data for selected station was unsuccessful") | |
maxboxperrow = max(list(len(list(filter(lambda box: box.row == row, station.boxes))) for row in range(station.boxrows or 1))) | |
sqw = int(Decimal((x_max-spx*maxboxperrow)/maxboxperrow).quantize(0, ROUND_HALF_UP)) | |
startx = (x_max+1-(maxboxperrow*sqw+(maxboxperrow-1)*spx))//2 | |
boxrows = (station.boxrows or 1) | |
sqh = int(Decimal((y_max-spy*boxrows)/boxrows).quantize(0, ROUND_HALF_UP)) | |
starty = (y_max+1-(boxrows*sqh+(boxrows-1)*spy))//2 | |
except Exception: | |
print(traceback.print_exc()) | |
rowpos = [startx]*(station.boxrows or 1) | |
for box in (station.boxes or []): | |
row = box.row or 0 | |
if type(box) == Box: | |
if box.state == "bookable": | |
color = bookableColor | |
elif box.state == "occupied": | |
color = occupiedColor | |
else: | |
color = lighttextColor | |
boxnum = (box.displayas or box.number.lstrip('0')).zfill(2) | |
canvas, (cx, cy) = drawsquare(canvas, rowpos[row], starty+row*(sqh+spy), rowpos[row]+sqw-1, starty+row*(sqh+spy)+sqh, color) | |
# canvas.SetPixel(cx, cy, 255, 255, 255) | |
rowpos[row] += sqw + spx | |
if rightbar: | |
currenttime = localtime() | |
drawtime(canvas, canvas.width-1, 8, textColor, currenttime.tm_hour, currenttime.tm_min, True) | |
if progress: | |
x_progress = int(x_max - ((i % step)*(x_max/step))) | |
graphics.DrawLine(canvas, 0, y_max, x_progress, y_max, barColor) | |
canvas = matrix.SwapOnVSync(canvas) | |
prev_time_measure = time_measure | |
time_measure = datetime.now() | |
sleep(max(interval-(time_measure-prev_time_measure).total_seconds(), 0)) | |
i += 1 | |
time_measure = datetime.now() | |
try: | |
baseurl = args.base_url | |
buchenurl = URL(baseurl+"boxbuchen/") | |
stations, references = getstations(buchenurl) | |
station = stations[stationid] | |
loop(canvas, baseurl, station) | |
except KeyboardInterrupt: | |
print("exiting") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment