Created
October 8, 2021 15:19
-
-
Save WillemJan/8f573fb24e80bf67629a93ce9c52c6db to your computer and use it in GitHub Desktop.
Interactive bookshelf
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 | |
# https://willemjan.github.io/2021/10/07/iot-for-libraries.html | |
import contextlib # stackoverflow.com/q/51464455 | |
with contextlib.redirect_stdout(None): | |
import pygame | |
import os | |
import json | |
import time | |
import serial | |
import board | |
import adafruit_ws2801 | |
""" | |
pi@shelf:~ $ xrandr | head -1 | |
Screen 0: minimum 320 x 200, current 1680 x 1050, maximum 2048 x 2048 | |
# apt install -y mbrola-nl3 espeak python3-pygame | |
# pip3 install adafruit-circuitpython-ws2801 | |
""" | |
SCREEN_WIDTH = 1680 | |
SCREEN_HEIGHT = 1050 | |
SENSOR_LEFT = "/dev/ttyUSB0" | |
SENSOR_RIGHT = "/dev/ttyUSB1" | |
SENSOR_READS = 3 | |
DEBUG = True | |
pygame.init() | |
screen = pygame.display.set_mode((1680, 1050), pygame.FULLSCREEN) | |
font = pygame.font.SysFont("Verdana", 50) | |
odata = board.MOSI | |
oclock = board.SCK | |
numleds = 25 | |
leds = adafruit_ws2801.WS2801(oclock, odata, numleds, brightness=0, auto_write=True) | |
with open("bl.json") as booklist_file: | |
bookshelf_contents = json.loads(booklist_file.read()) | |
left_c = right_c = -1 | |
book_align = [] | |
pygame.display.flip() | |
def draw_metadata(book, book_pos): | |
lednr = numleds - book_pos - 3 | |
colors = [(20, 20, 20), | |
(30, 30, 30), | |
(255, 255, 255), | |
(30, 30, 30), | |
(20, 20, 20)] | |
for i, j in enumerate(range(lednr - 3, lednr)): | |
try: | |
leds[j] = colors[i] | |
print(colors[i]) | |
except: | |
pass | |
for i, j in enumerate(range(lednr, lednr + 3)): | |
try: | |
leds[j] = colors[i + 2] | |
print(colors[i + 2]) | |
except: | |
pass | |
for i in range(10): | |
leds.brightness = (i/10) | |
print(lednr) | |
time.sleep(0.01) | |
screen.fill((0, 0, 0)) | |
img = font.render("Title:", True, (200, 200, 200)) | |
screen.blit(img, ((SCREEN_WIDTH / 9), 120)) | |
img = font.render(book["Title"].split(" - ")[0], True, (100, 200, 100)) | |
screen.blit(img, ((SCREEN_WIDTH / 4), 120)) | |
offset = 50 | |
if book["Title"].find(" - ") > -1: | |
title = book["Title"] | |
if len(title.split(" - ")[1]) > 0: | |
img = font.render(" - ".join(title.split(" - ")[1:]), True, (100, 200, 100)) | |
screen.blit(img, ((SCREEN_WIDTH / 4), 120 + offset)) | |
offset += 50 | |
img = font.render("Year:", True, (200, 200, 200)) | |
screen.blit(img, ((SCREEN_WIDTH / 9), 120 + offset)) | |
img = font.render(book["Year"].split(" - ")[0], True, (100, 200, 100)) | |
screen.blit(img, ((SCREEN_WIDTH / 4), 120 + offset)) | |
offset += 50 | |
img = font.render("Author(s):", True, (200, 200, 200)) | |
screen.blit(img, ((SCREEN_WIDTH / 9), 120 + offset)) | |
for author in book["Authors"]: | |
img = font.render(author, True, (100, 200, 100)) | |
screen.blit(img, ((SCREEN_WIDTH / 4), 120 + offset)) | |
offset += 50 | |
if book["Publisher"]: | |
img = font.render("Publisher:", True, (200, 200, 200)) | |
screen.blit(img, ((SCREEN_WIDTH / 9), 120 + offset)) | |
img = font.render(book["Publisher"].split(" - ")[0], True, (100, 200, 100)) | |
screen.blit(img, ((SCREEN_WIDTH / 4), 120 + offset)) | |
offset += 50 | |
pygame.display.flip() | |
if book["Language"] == "nl": | |
ESPEAK = 'espeak -a 400 -v nl+f1 "%s" --stdout | aplay' | |
os.system(ESPEAK % book["Title"]) | |
else: | |
ESPEAK = 'espeak -a 400 -v en+f1 "%s" --stdout | aplay' | |
os.system(ESPEAK % book["Title"]) | |
time.sleep(0.4) | |
detected = 0 | |
book_detected = False | |
old_book = {} | |
while True: | |
left_all = [] | |
right_all = [] | |
ser_left = serial.Serial(SENSOR_LEFT, 115200) | |
ser_right = serial.Serial(SENSOR_RIGHT, 115200) | |
for i in range(5): | |
try: | |
left = int(ser_left.readline().decode("utf-8").strip().split()[1]) | |
except: | |
pass | |
try: | |
right = int(ser_right.readline().decode("utf-8").strip().split()[1]) | |
except: | |
pass | |
for i in range(SENSOR_READS): | |
try: | |
left = int(ser_left.readline().decode("utf-8").strip().split()[1]) | |
left_all.append(left) | |
except: | |
pass | |
try: | |
right = int(ser_right.readline().decode("utf-8").strip().split()[1]) | |
right_all.append(right) | |
except: | |
pass | |
ser_left.close() | |
ser_right.close() | |
left_stable = all(element == left_all[0] for element in left_all) | |
right_stable = all(element == right_all[0] for element in right_all) | |
if DEBUG: | |
print("Left reading:", left_all, "Stable:", left_stable, | |
"\nRight reading:", right_all, "Stable:", right_stable) | |
if right_stable or left_stable and len(left_all) + len(right_all) == SENSOR_READS * 2: | |
book_pos = 0 | |
for book in bookshelf_contents: | |
book_pos += 1 | |
if book.get("pos") == [left, right]: | |
book_detected = True | |
break | |
if left_stable and left < 45: | |
if book.get("pos")[0] == left: | |
book_detected = True | |
break | |
if right_stable and right < 45: | |
if book.get("pos")[1] == right: | |
book_detected = True | |
break | |
if book_detected: | |
if left_stable and right_stable: | |
detected += 2 | |
else: | |
detected += 1 | |
if detected > 4: | |
draw_metadata(book, book_pos) | |
book_detected = False | |
detected = 0 | |
if not left_stable or not right_stable: | |
detected -= 1 | |
if detected < 2: | |
for i in range(20): | |
leds.brightness = (20 - i) / 20 | |
leds.fill((0, 0, 0)) | |
screen.fill((0, 0, 0)) | |
pygame.display.flip() | |
old_book = {} | |
detected = 0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment