Skip to content

Instantly share code, notes, and snippets.

@WillemJan
Created October 8, 2021 15:19
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save WillemJan/8f573fb24e80bf67629a93ce9c52c6db to your computer and use it in GitHub Desktop.
Save WillemJan/8f573fb24e80bf67629a93ce9c52c6db to your computer and use it in GitHub Desktop.
Interactive bookshelf
#!/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