Compare commits

8 Commits

19 changed files with 419 additions and 131 deletions

BIN
._README.md Normal file

Binary file not shown.

BIN
._addtoDB.py Normal file

Binary file not shown.

BIN
._carousel.py Normal file

Binary file not shown.

BIN
._epd4in2.py Normal file

Binary file not shown.

BIN
._refreshdb.py Normal file

Binary file not shown.

BIN
._ssbpost.sh Normal file

Binary file not shown.

View File

@@ -26,7 +26,8 @@ recommended hardware components:
| micro-sd card | variable, $5.8 on amazon | | | micro-sd card | variable, $5.8 on amazon | |
| buttons | $7 | https://www.adafruit.com/product/3582 | | buttons | $7 | https://www.adafruit.com/product/3582 |
| camera | $7 | [aliexpres](https://www.aliexpress.com/item/32788881215.html?spm=a2g0s.12269583.0.0.55eb6619CDSuac) (confirmed works) or [alt-aliexpress](https://www.aliexpress.com/item/32293433078.html?spm=a2g0s.9042311.0.0.349f4c4dYCXYQ3)| | camera | $7 | [aliexpres](https://www.aliexpress.com/item/32788881215.html?spm=a2g0s.12269583.0.0.55eb6619CDSuac) (confirmed works) or [alt-aliexpress](https://www.aliexpress.com/item/32293433078.html?spm=a2g0s.9042311.0.0.349f4c4dYCXYQ3)|
| total: | | $65 plus shipping and tax, ~$75 total | | printer | $50 | buy this https://www.adafruit.com/product/2751 |
| total: | | ~$115 |
you'll also need a micro-usb cable, usb power supply and materials to build a case from. you'll also need a micro-usb cable, usb power supply and materials to build a case from.
@@ -63,11 +64,21 @@ you'll also need a micro-usb cable, usb power supply and materials to build a ca
``` ```
sudo apt update -y && sudo apt upgrade -y sudo apt update -y && sudo apt upgrade -y
sudo apt install unattended-upgrades python-dev python-pip python-buttonshim libjpeg-dev zlib1g-dev git -y sudo apt install unattended-upgrades python-dev python-pip python-buttonshim libjpeg-dev zlib1g-dev git -y
pip install spidev tinydb pillow --no-cache-dir pip3 install spidev tinydb pillow pyqrcode qrcode --no-cache-dir
``` ```
(third line can take a while...) (third line can take a while...)
probably also need to install _some_ of the libraries at https://github.com/adafruit/Python-Thermal-Printer but not all
`sudo apt-get install git cups build-essential libcups2-dev libcupsimage2-dev python3-serial python3-pil python-unidecode` maybe don't need alllll of it
Do need to do this to install the printer:
```sudo lpadmin -p ZJ-58 -E -v serial:/dev/usb/lp0?baud=19200 -m zjiang/ZJ-58.ppd
sudo lpoptions -d ZJ-58```
certainly CUPS will cause you issues and you will need to reference https://www.cups.org/doc/man-cupsd.conf.html
Now need to install an ARMv6 compatible NPM. This should work: Now need to install an ARMv6 compatible NPM. This should work:
``` ```
curl -o node.tar.gz https://unofficial-builds.nodejs.org/download/release/v13.8.0/node-v13.8.0-linux-armv6l.tar.gz curl -o node.tar.gz https://unofficial-builds.nodejs.org/download/release/v13.8.0/node-v13.8.0-linux-armv6l.tar.gz
@@ -77,6 +88,10 @@ sudo cp -r node-v13.8.0-linux-armv6l/* /usr/local
If that doesn't work you can [read more about installing node on arm v6 architecture](https://www.thepolyglotdeveloper.com/2018/03/install-nodejs-raspberry-pi-zero-w-nodesource/). Also [the builds are here](https://unofficial-builds.nodejs.org/). If that doesn't work you can [read more about installing node on arm v6 architecture](https://www.thepolyglotdeveloper.com/2018/03/install-nodejs-raspberry-pi-zero-w-nodesource/). Also [the builds are here](https://unofficial-builds.nodejs.org/).
might need to run `curl https://get.pimoroni.com/buttonshim | bash` to get the buttons to work
<br> <br>
#### clone the repo #### clone the repo
ideally right in your home directory. ideally right in your home directory.
@@ -84,7 +99,12 @@ ideally right in your home directory.
`git clone https://git.laboratoryb.org/trav/ebb.git` `git clone https://git.laboratoryb.org/trav/ebb.git`
#### setup SSB #### setup SSB
I can't remember how I got ssb-server to work, `sudo npm install -g ssb-server` throws `illegal instruction`. Something to do with a woknky version of Node. So my **extremely** hacky workaround is to unzip `ssb-server.zip` from the install directory into `/usr/local/lib/node_modules/`. This is v bad and needs to be fixed asap. [SSB-server](https://github.com/ssbc/ssb-server) is made available via the MIT licese. I can't remember how I got ssb-server to work, `sudo npm install -g ssb-server` throws `illegal instruction`. Something to do with a woknky version of Node.
##### My **extremely** hacky workaround:
1. `sudo npm install -g ssb-server` to add all the npm-side ssb stuff
2. unzip `ssb-server.zip` from the install directory into `/usr/local/lib/node_modules/` to actually have a working SSB server.
This is v bad and needs to be fixed asap. [SSB-server](https://github.com/ssbc/ssb-server) is made available via the MIT licese.
As long as the EBB repo is at `/home/pi/ebb` the following service files should be configured fine. Otherwise you gotta edit ssb.service and ebb-carousel.service and update the `WorkingDirectory` field. As long as the EBB repo is at `/home/pi/ebb` the following service files should be configured fine. Otherwise you gotta edit ssb.service and ebb-carousel.service and update the `WorkingDirectory` field.

View File

@@ -4,8 +4,10 @@
#this script takes a file as an option and adds that file to the db and posts the file to scuttlebutt #this script takes a file as an option and adds that file to the db and posts the file to scuttlebutt
import optparse import optparse
import iterparse
import traceback import traceback
import os, sys import os, sys
import json
import subprocess import subprocess
from tinydb import TinyDB, Query from tinydb import TinyDB, Query
@@ -25,27 +27,43 @@ def main():
exit(1) exit(1)
def addToDB(pathToImage, pathToDB,composite):
def addFile(pathToImage, pathToDB, SSBidentify): #init db
#init db
db = TinyDB(pathToDB) db = TinyDB(pathToDB)
#add to db #add to db
db.insert({'path': pathToImage, 'date': 4, 'ssb': SSBidentify}) db.insert({'path': pathToImage, 'date': 4, 'ssb': '-2', 'composite': composite})
print("all done, added to db") print("all done, added to db")
#print("heres the whole db") #print("heres the whole db")
#print(db.all()) #print(db.all())
def addToSSB(pathToImage, pathToDB, SSBidentify):
#unless you say don't post to ssb, post to ssb #unless you say don't post to ssb, post to ssb
if SSBidentify != -1: if SSBidentify != -1:
#SEND TO SSB! WOOOO #SEND TO SSB! WOOOO
try: try:
result = subprocess.call('./ssbpost.sh ' + pathToImage, shell=True) result = subprocess.Popen('./ssbpost.sh ' + pathToImage, shell=True, stdout=subprocess.PIPE, )
except: except:
print('traceback.format_exc():\n%s' % traceback.format_exc()) print('traceback.format_exc():\n%s' % traceback.format_exc())
exit() exit()
return pathToImage
# get the ssb json from the bash command we just ran
newssb=result.stdout.read()
print(newssb)
# ADD HERE A CHECK that newssb is _anything_ if ssb-server isn't running that may show as garbage that will crash the program
#convert string to object
json_object = json.loads(newssb)
# get the key for the post we just made
key = json_object["key"]
return key
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -16,8 +16,10 @@ import buttonshim
import addtoDB import addtoDB
import refreshdb import refreshdb
import configparser import configparser
import pyqrcode
import qrcode
from tinydb import TinyDB, Query from tinydb import TinyDB, Query
from PIL import Image,ImageDraw,ImageFont from PIL import Image,ImageDraw,ImageFont,ImageEnhance
## INITIALIZE ## ## INITIALIZE ##
@@ -27,7 +29,7 @@ buttonshim.set_pixel(0xFF, 0x00, 0xFF)
#intervalTime is how many seconds before moving to next image (300 = 5 minutes) #intervalTime is how many seconds before moving to next image (300 = 5 minutes)
#sync time is how many seconds before refreshing the DB from SSB #sync time is how many seconds before refreshing the DB from SSB
#this should be moved into the config file... #this should be moved into the config file...
intervalTime = 1800 intervalTime = 200
syncTime = 3600 syncTime = 3600
#keep track of where we are moving through intervalTime, syncTime and where we are in the db, and what flier we're currently displaying #keep track of where we are moving through intervalTime, syncTime and where we are in the db, and what flier we're currently displaying
timeIndex = 1200 timeIndex = 1200
@@ -63,10 +65,9 @@ try:
bmp = Image.open(str(flierPath)) bmp = Image.open(str(flierPath))
Limage.paste(bmp) Limage.paste(bmp)
draw = ImageDraw.Draw(Limage) draw = ImageDraw.Draw(Limage)
draw.text((2, 280), 'EBB', font = font18, fill = 255) # draw.text((2, 280), 'EBB', font = font18, fill = 255)
draw.text((2, 300), 'version .02', font = font18, fill = 255) draw.text((2, 300), 'Scuttlebooth 2', font = font18, fill = 255)
epd.display(epd.getbuffer(Limage)) epd.display(epd.getbuffer(Limage))
time.sleep(2)
epd.sleep() epd.sleep()
except: except:
print('traceback.format_exc():\n%s' % traceback.format_exc()) print('traceback.format_exc():\n%s' % traceback.format_exc())
@@ -76,21 +77,21 @@ except:
@buttonshim.on_press(buttonshim.BUTTON_A) @buttonshim.on_press(buttonshim.BUTTON_A)
def button_a(button, pressed): def button_a(button, pressed):
global button_flag global button_flag
buttonshim.set_pixel(0xFF, 0x00, 0x00) # buttonshim.set_pixel(0xFF, 0x00, 0x00)
button_flag = "button_1" button_flag = "button_1"
@buttonshim.on_press(buttonshim.BUTTON_B) @buttonshim.on_press(buttonshim.BUTTON_B)
def button_b(button, pressed): def button_b(button, pressed):
global button_flag global button_flag
buttonshim.set_pixel(0x00, 0x00, 0xFF) # buttonshim.set_pixel(0x00, 0x00, 0xFF)
button_flag = "button_2" button_flag = "button_2"
@buttonshim.on_press(buttonshim.BUTTON_C) @buttonshim.on_press(buttonshim.BUTTON_C)
def button_c(button, pressed): def button_c(button, pressed):
global button_flag global button_flag
buttonshim.set_pixel(0x00, 0x00, 0xFF) # buttonshim.set_pixel(0x00, 0x00, 0xFF)
button_flag = "button_3" button_flag = "button_3"
@buttonshim.on_press(buttonshim.BUTTON_D) @buttonshim.on_press(buttonshim.BUTTON_D)
@@ -109,12 +110,62 @@ buttonshim.set_pixel(0x00, 0x00, 0x00)
buttonshim.set_pixel(0x00, 0x00, 0x00) buttonshim.set_pixel(0x00, 0x00, 0x00)
# img concat from https://note.nkmk.me/en/python-pillow-concat-images/
def get_concat_v(im1, im2):
dst = Image.new('RGB', (im1.width, im1.height + im2.height))
dst.paste(im1, (0, 0))
dst.paste(im2, (0, im1.height))
return dst
def get_concat_h(im1, im2):
dst = Image.new('RGB', (im1.width + im2.width, im1.height))
dst.paste(im1, (0, 0))
dst.paste(im2, (im1.width, 0))
return dst
def get_concat_h_blank(im1, im2, color=(0, 0, 0)):
dst = Image.new('RGB', (im1.width + im2.width, max(im1.height, im2.height)), color)
dst.paste(im1, (0, 0))
dst.paste(im2, (im1.width, 0))
return dst
def pulse(speed):
time.sleep(1)
for scale in range(0, speed):
if scale >= 1:
scale = scale / speed
buttonshim.set_pixel(0x00, 0x00, int(0xff * scale))
for scale in range(speed, 0,-1):
if scale >= 1:
scale = scale / speed
buttonshim.set_pixel(0x00, 0x00, int(0xff * scale))
time.sleep(1)
for scale in range(0, speed):
if scale >= 1:
scale = scale / speed
buttonshim.set_pixel(0x00, int(0xff * scale), 0x00)
for scale in range(speed, 0,-1):
if scale >= 1:
scale = scale / speed
buttonshim.set_pixel(0x00, int(0xff * scale), 0x00)
time.sleep(1)
for scale in range(0, speed):
buttonshim.set_pixel(0xFF, 0x00, 0x00)
time.sleep(.02)
buttonshim.set_pixel(0xFF, 0xFF, 0x00)
time.sleep(.02)
buttonshim.set_pixel(0x00, 0xFF, 0x00)
time.sleep(.02)
buttonshim.set_pixel(0xFF, 0xFF, 0x00)
time.sleep(.02)
time.sleep(1)
## MAIN LOOP ## ## MAIN LOOP ##
while True: while True:
# chill for a bit, keep track of how long we're chilling
time.sleep(2)
print("time:", timeIndex, "/", intervalTime, "index", dbIndex, "/", dbCount, "sync time:", syncIndex, "/", syncTime)
#iterate through syncTime and image time #iterate through syncTime and image time
syncIndex+=2 syncIndex+=2
timeIndex+=2 timeIndex+=2
@@ -123,10 +174,11 @@ while True:
if syncIndex >= syncTime: if syncIndex >= syncTime:
#light up red while syncing db #light up red while syncing db
buttonshim.set_pixel(0xFF, 0x00, 0x00) buttonshim.set_pixel(0xFF, 0x00, 0x00)
refreshdb.fresh() # refreshdb.fresh()
print ("uhhhhhhh skipping ssb refresh because broken also solpunk one stuck in customs rn :'(")
#db count may have changed #db count may have changed
for item in db: # for item in db:
dbCount = item.doc_id # dbCount = item.doc_id
syncIndex = 0 syncIndex = 0
buttonshim.set_pixel(0x00, 0x00, 0x00) buttonshim.set_pixel(0x00, 0x00, 0x00)
@@ -160,7 +212,6 @@ while True:
bmp = Image.open(flierPath) bmp = Image.open(flierPath)
Limage.paste(bmp) Limage.paste(bmp)
epd.display(epd.getbuffer(Limage)) epd.display(epd.getbuffer(Limage))
time.sleep(2)
timeIndex+=2 timeIndex+=2
epd.sleep() epd.sleep()
@@ -173,68 +224,112 @@ while True:
#take pic #take pic
if button_flag == "button_1": if button_flag == "button_1":
#generate unique file_name #generate 3 unique file_names
unique = uuid.uuid4() unique1 = uuid.uuid4()
unique = str(unique) unique1 = str(unique1)
jpgpath = imagesPath + unique + '.jpg' jpgpath1 = imagesPath + unique1 + '.jpg'
unique2 = uuid.uuid4()
unique2 = str(unique2)
jpgpath2 = imagesPath + unique2 + '.jpg'
unique3 = uuid.uuid4()
unique3 = str(unique3)
jpgpath3 = imagesPath + unique3 + '.jpg'
#generate unique bmp name
bmpath = imagesPath + unique + '.bmp'
#generate unique bmp names
bmpath1 = imagesPath + unique1 + '.bmp'
bmpath2 = imagesPath + unique2 + '.bmp'
bmpath3 = imagesPath + unique3 + '.bmp'
#loop in case we wanna re-take it #loop in case we wanna re-take it
exitPhotoMode = False exitPhotoMode = False
while exitPhotoMode == False: while exitPhotoMode == False:
#take photo
#take fullsize photos
pulse(20)
try: try:
result = subprocess.call(['raspistill', '-o', jpgpath, '-vf', '-hf', '-w', '300', '-h', '400', '-t', '1000']) result = subprocess.call(['raspistill', '-rot', '180', '-o', jpgpath1, '--brightness', '55', '--contrast', '1.25','-vf', '-hf', '-w', '600', '-h', '800', '-t', '20'])
except: except:
print('traceback.format_exc():\n%s' % traceback.format_exc()) print('traceback.format_exc():\n%s' % traceback.format_exc())
exit() exit()
#convert to bmp pulse(20)
im = Image.open(jpgpath)
im = im.convert("1")
im.save(bmpath)
#display the image try:
result = subprocess.call(['raspistill', '-rot', '180', '-o', jpgpath2, '--brightness', '55', '--contrast', '1.25','-vf', '-hf', '-w', '600', '-h', '800', '-t', '20'])
except:
print('traceback.format_exc():\n%s' % traceback.format_exc())
exit()
pulse(20)
try:
result = subprocess.call(['raspistill', '-rot', '180', '-o', jpgpath3, '--brightness', '55', '--contrast', '1.25', '-vf', '-hf', '-w', '600', '-h', '800', '-t', '20'])
except:
print('traceback.format_exc():\n%s' % traceback.format_exc())
exit()
buttonshim.set_pixel(0x00, 0x00, 0xff)
#create half-size bmps for cycling through
half1 = Image.open(jpgpath1)
half2 = Image.open(jpgpath2)
half3 = Image.open(jpgpath3)
newsize = (300, 400)
half1 = half1.resize(newsize)
half2 = half2.resize(newsize)
half3 = half3.resize(newsize)
half1 = half1.convert("1")
half1.save(bmpath1)
half2 = half2.convert("1")
half2.save(bmpath2)
half3 = half3.convert("1")
half3.save(bmpath3)
## CREATE screen image to display:
# create quarter sized bmps
im1 = Image.open(jpgpath1)
im2 = Image.open(jpgpath2)
im3 = Image.open(jpgpath3)
newsize = (150, 200)
im1 = im1.resize(newsize)
im2 = im2.resize(newsize)
im3 = im3.resize(newsize)
#add quarter sized photos and instructions to the image to be rendered
instructions = imagesPath + 'instructions.bmp'
im4 = Image.open(instructions)
Limage.paste(im1, (0,0))
Limage.paste(im2, (150,0))
Limage.paste(im3, (0,200))
Limage.paste(im4, (150,200))
#add the menu
# draw = ImageDraw.Draw(Limage)
# font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 10)
# draw.text((152, 200), 'press button 1 to:', font = font18, fill = 255)
# draw.text((152, 220), 'post online', font = font18, fill = 255)
# draw.text((152, 240), 'button 2: post photo', font = font18, fill = 255)
# draw.text((152, 260), 'here only', font = font18, fill = 255)
# draw.text((152, 280), 'button 3: retake', font = font18, fill = 255)
# draw.text((152, 00), 'buttons 4 or 5:', font = font18, fill = 255)
# draw.text((152, 640), 'exit photo mode', font = font18, fill = 255)
# display the image
epd.init() epd.init()
bmp = Image.open(bmpath)
Limage.paste(bmp)
epd.display(epd.getbuffer(Limage)) epd.display(epd.getbuffer(Limage))
#wait for user decision on photo
waited = 0
#pulse LED while we wait for user to press something
button_flag = "none" button_flag = "none"
#strobe light green yellow red for a while
while (button_flag == "none") and (waited < 30):
buttonshim.set_pixel(0xFF, 0x00, 0x00)
time.sleep(.2)
buttonshim.set_pixel(0xFF, 0xFF, 0x00)
time.sleep(.2)
buttonshim.set_pixel(0x00, 0xFF, 0x00)
time.sleep(.2)
buttonshim.set_pixel(0xFF, 0xFF, 0x00)
time.sleep(.2)
waited+=1
#if still not sure, give em the menu
if button_flag == "none":
#ok time to display menu
draw = ImageDraw.Draw(Limage)
font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24)
draw.text((2, 0), 'press button 1 to:', font = font18, fill = 255)
draw.text((2, 40), 'post online', font = font18, fill = 255)
draw.text((2, 80), 'button 2: post photo', font = font18, fill = 255)
draw.text((2, 120), 'here only', font = font18, fill = 255)
draw.text((2, 160), 'button 3: retake', font = font18, fill = 255)
draw.text((2, 200), 'buttons 4 or 5:', font = font18, fill = 255)
draw.text((2, 240), 'exit photo mode', font = font18, fill = 255)
epd.display(epd.getbuffer(Limage))
#now just wait for them to press something
while button_flag == "none": while button_flag == "none":
buttonshim.set_pixel(0xFF, 0x00, 0x00) buttonshim.set_pixel(0xFF, 0x00, 0x00)
time.sleep(.2) time.sleep(.2)
@@ -248,11 +343,90 @@ while True:
#led to thinking mode #led to thinking mode
buttonshim.set_pixel(0x00, 0x00, 0xFF) buttonshim.set_pixel(0x00, 0x00, 0xFF)
#post to ssb
# if we're printing, generate image to print
if button_flag == "button_1" or button_flag == "button_2" or button_flag == "button_3":
#generate unique file_name
unique = uuid.uuid4()
unique = str(unique)
composite = imagesPath + unique + '.jpg'
# concatenate images and save concatenated image at composite (is filepath)
headerIsAt = imagesPath + 'header.jpg'
header = Image.open(headerIsAt)
im1 = Image.open(jpgpath1)
im2 = Image.open(jpgpath2)
im3 = Image.open(jpgpath3)
get_concat_v(header, im1).save(composite)
concaz = Image.open(composite)
get_concat_v(concaz, im2).save(composite)
concaz = Image.open(composite)
get_concat_v(concaz, im3).save(composite)
concaz = Image.open(composite)
#post to ssb and print
if button_flag == "button_1": if button_flag == "button_1":
button_flag == "null" button_flag == "null"
#add the photo to the db/ssb
addtoDB.addFile(bmpath,dbPath,0) #add the photo strip to ssb
key = addtoDB.addToSSB(composite,dbPath,0)
# Create qr code
#from https://ourcodeworld.com/articles/read/554/how-to-create-a-qr-code-image-or-svg-in-python
qr = qrcode.QRCode(
version = 1,
error_correction = qrcode.constants.ERROR_CORRECT_H,
box_size = 6,
border = 1,
)
# Add data
qr.add_data(key)
qr.make(fit=True)
# Create an image from the QR Code instance
img = qr.make_image()
whereToSaveQR = imagesPath + 'QR.jpg'
img.save(whereToSaveQR)
# generate full composite for printing
color=(255, 255, 255)
dst = Image.new('RGB', (600, 2833), color)
dst.paste(concaz, (0, 0))
whereQRinstructionsAre = imagesPath + 'ssbqrinstgurct.jpg'
qrInstruct = Image.open(whereQRinstructionsAre)
dst.paste(qrInstruct, (0,2575))
dst.paste(img, (342,2575))
# whereInstructionsPlusQRis = imagesPath + 'instructionsPlusQR.jpg'
# get_concat_h_blank(qrInstruct, img, (255, 255, 255)).save(whereInstructionsPlusQRis)
# instr = Image.open(whereInstructionsPlusQRis)
#generate unique file_name
unique = uuid.uuid4()
unique = str(unique)
FULLcomposite = imagesPath + unique + '.jpg'
# save the full composite image for printing
dst.save(FULLcomposite)
#add each photo to the db
addtoDB.addToDB(bmpath1,dbPath,FULLcomposite)
addtoDB.addToDB(bmpath2,dbPath,FULLcomposite)
addtoDB.addToDB(bmpath3,dbPath,FULLcomposite)
# concatenate existing composite image with the instructions+QR composite for full composite image for print
# get_concat_v(concaz, instr).save(FULLcomposite)
# print Fullcomposite
try:
result = subprocess.call('lp ' + FULLcomposite, shell=True)
except:
print('traceback.format_exc():\n%s' % traceback.format_exc())
exit()
#update dbCount #update dbCount
for item in db: for item in db:
dbCount = item.doc_id dbCount = item.doc_id
@@ -260,21 +434,39 @@ while True:
#display the image to clear the menu (also display text "posted") #display the image to clear the menu (also display text "posted")
font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24) font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24)
bmp = Image.open(bmpath) bmp = Image.open(bmpath1)
Limage.paste(bmp) Limage.paste(bmp)
draw = ImageDraw.Draw(Limage) draw = ImageDraw.Draw(Limage)
draw.text((2, 240), 'PHOTO POSTED', font = font18, fill = 255) draw.text((2, 240), 'photostrip posted', font = font18, fill = 255)
draw.text((2, 260), 'online!', font = font18, fill = 255) draw.text((2, 260), 'to SSB', font = font18, fill = 255)
epd.display(epd.getbuffer(Limage)) epd.display(epd.getbuffer(Limage))
# move dbIndex to current photo so that reprint works right
dbIndex = dbCount
#post only locally
#post only locally and print
if button_flag == "button_2": if button_flag == "button_2":
#led to thinking mode
buttonshim.set_pixel(0x00, 0x00, 0xFF)
button_flag == "null" button_flag == "null"
#add that file to the db. -1 tells addtoDB not to post to ssb.
addtoDB.addFile(bmpath,dbPath,-1)
#add each photo to the db
addtoDB.addToDB(bmpath1,dbPath,composite)
addtoDB.addToDB(bmpath2,dbPath,composite)
addtoDB.addToDB(bmpath3,dbPath,composite)
#update dbCount #update dbCount
for item in db: for item in db:
dbCount = item.doc_id dbCount = item.doc_id
# print concaz that we already generated
try:
result = subprocess.call('lp ' + composite, shell=True)
except:
print('traceback.format_exc():\n%s' % traceback.format_exc())
exit()
exitPhotoMode = True exitPhotoMode = True
#display the image to clear the menu (also display text "posted") #display the image to clear the menu (also display text "posted")
font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24) font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24)
@@ -284,18 +476,56 @@ while True:
draw.text((2, 240), 'PHOTO POSTED', font = font18, fill = 255) draw.text((2, 240), 'PHOTO POSTED', font = font18, fill = 255)
draw.text((2, 260), 'to this device only', font = font18, fill = 255) draw.text((2, 260), 'to this device only', font = font18, fill = 255)
epd.display(epd.getbuffer(Limage)) epd.display(epd.getbuffer(Limage))
# move dbIndex to current photo so that reprint works right
dbIndex = dbCount
#reshoot the picture
#just print
if button_flag == "button_3": if button_flag == "button_3":
#led to thinking mode
buttonshim.set_pixel(0x00, 0x00, 0xFF)
button_flag == "null" button_flag == "null"
#nothin! loop around... exitPhotoMode still false
#exit photomode, delete photo # print concaz that we already generated
if (button_flag == "button_4") or (button_flag == "button_5"): try:
button_flag == "null" result = subprocess.call('lp ' + composite, shell=True)
except:
print('traceback.format_exc():\n%s' % traceback.format_exc())
exit()
exitPhotoMode = True exitPhotoMode = True
os.remove(bmpath)
os.remove(jpgpath)
#reshoot
if (button_flag == "button_4"):
# delete images
os.remove(bmpath1)
os.remove(bmpath2)
os.remove(bmpath3)
os.remove(jpgpath1)
os.remove(jpgpath2)
os.remove(jpgpath3)
# reset buttonflag and loop around to take pic again
button_flag == "null"
#delete images and exit photo mode
if (button_flag == "button_5"):
button_flag == "null"
buttonshim.set_pixel(0x00, 0x00, 0xff)
exitPhotoMode = True
#delete the images we took
os.remove(bmpath1)
os.remove(bmpath2)
os.remove(bmpath3)
os.remove(jpgpath1)
os.remove(jpgpath2)
os.remove(jpgpath3)
# display next image
timeIndex = intervalTime
#led off #led off
buttonshim.set_pixel(0x00, 0x00, 0x00) buttonshim.set_pixel(0x00, 0x00, 0x00)
@@ -308,13 +538,15 @@ while True:
#move to the next image #move to the next image
elif button_flag == "button_2": elif button_flag == "button_2":
print ("next image") buttonshim.set_pixel(0x00, 0x00, 0xFF)
timeIndex = intervalTime print ("next image")
button_flag = "null" timeIndex = intervalTime
button_flag = "null"
#go back to the previous image #go back to the previous image
elif button_flag == "button_3": elif button_flag == "button_3":
buttonshim.set_pixel(0x00, 0x00, 0xFF)
print ("previous image") print ("previous image")
#we go back 2 because we have to account for calling timeIndex = intervalTime iterates forward by 1 #we go back 2 because we have to account for calling timeIndex = intervalTime iterates forward by 1
dbIndex-=2 dbIndex-=2
@@ -325,7 +557,8 @@ while True:
#delete current image #delete current image
elif button_flag == "button_4": elif button_flag == "button_5":
buttonshim.set_pixel(0x00, 0x00, 0xFF)
button_flag = "null" button_flag = "null"
#can't delete the default image #can't delete the default image
@@ -339,7 +572,7 @@ while True:
draw.text((2, 0), 'Are you sure', font = font18, fill = 255) draw.text((2, 0), 'Are you sure', font = font18, fill = 255)
draw.text((2, 40), 'you want to delete', font = font18, fill = 255) draw.text((2, 40), 'you want to delete', font = font18, fill = 255)
draw.text((2, 80), 'the current image?', font = font18, fill = 255) draw.text((2, 80), 'the current image?', font = font18, fill = 255)
draw.text((2, 120), 'Press button 4', font = font18, fill = 255) draw.text((2, 120), 'Press button 5', font = font18, fill = 255)
draw.text((2, 160), 'again to confirm.', font = font18, fill = 255) draw.text((2, 160), 'again to confirm.', font = font18, fill = 255)
draw.text((2, 200), 'Press any other', font = font18, fill = 255) draw.text((2, 200), 'Press any other', font = font18, fill = 255)
draw.text((2, 240), 'button for no.', font = font18, fill = 255) draw.text((2, 240), 'button for no.', font = font18, fill = 255)
@@ -354,7 +587,7 @@ while True:
time.sleep(.05) time.sleep(.05)
#sounds like delete time #sounds like delete time
if button_flag == "button_4": if button_flag == "button_5":
Fruit = Query() Fruit = Query()
#results = db.search(Fruit.path == flierPath) #results = db.search(Fruit.path == flierPath)
db.remove(Fruit.path == flierPath) db.remove(Fruit.path == flierPath)
@@ -371,37 +604,39 @@ while True:
button_flag = "null" button_flag = "null"
buttonshim.set_pixel(0x00, 0x00, 0xFF) buttonshim.set_pixel(0x00, 0x00, 0xFF)
#weather button! #reprint current set of pics
elif button_flag == "button_5": elif button_flag == "button_4":
button_flag = "null"
print ("button flag set to null...")
buttonshim.set_pixel(0x00, 0x00, 0xFF)
#ACTUALLY PARSE THE JSON DUH, THIS IS BROKEN #grab the entry at dbIndex, newFlier is a dict
print ("getting db at")
print (dbIndex)
newFlier = db.get(doc_id=dbIndex)
#get the weather #if that's an empty spot in the db we gotta keep lookin (probably wouldn't be in this case buuut whatever, this prevents errors)
#proc = subprocess.Popen(["wget", "http://wttr.in/btv_FnQT.png"], stdout=subprocess.PIPE) while newFlier == None:
proc = subprocess.Popen(["wget", "http://wttr.in/btv_FQT.png"], stdout=subprocess.PIPE) dbIndex+=1
(out, err) = proc.communicate() newFlier = db.get(doc_id=dbIndex)
#convert # get composite from db
size = 400, 300 flierPath = newFlier["composite"]
#too pixely
#im = Image.open("btv_FnQT.png")
#im = im.rotate(90, Image.NEAREST, "expand=1")
#sideways, no rotate if flierPath == None:
im = Image.open("btv_FQT.png") print ("no flier here...")
im.thumbnail(size, Image.BICUBIC) # print composite
im = im.convert("1") try:
im.save("btv.bmp") result = subprocess.call('lp ' + flierPath, shell=True)
print ("printing...")
except:
print('traceback.format_exc():\n%s' % traceback.format_exc())
exit()
#display the weather buttonshim.set_pixel(0x00, 0x00, 0x00)
epd.init() button_flag = "null"
Limage = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame
bmp = Image.open("btv.bmp") # chill for a bit, keep track of how long we're chilling
Limage.paste(bmp) time.sleep(2)
epd.display(epd.getbuffer(Limage)) print("time:", timeIndex, "/", intervalTime, "index", dbIndex, "/", dbCount, "sync time:", syncIndex, "/", syncTime)
time.sleep(3)
timeIndex+=2
epd.sleep()
button_flag = "null"
buttonshim.set_pixel(0x00, 0x00, 0x00)

View File

@@ -227,8 +227,8 @@ class EPD:
return 0 return 0
def getbuffer(self, image): def getbuffer(self, image):
# print "bufsiz = ",(self.width/8) * self.height print ("bufsiz = ",(self.width/8) * self.height)
buf = [0xFF] * ((self.width/8) * self.height) buf = [0xFF] * int(((self.width/8) * self.height))
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
@@ -247,25 +247,25 @@ class EPD:
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[(newx + newy*self.width) / 8] &= ~(0x80 >> (y % 8)) buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, image): def display(self, image):
self.send_command(DATA_START_TRANSMISSION_1) self.send_command(DATA_START_TRANSMISSION_1)
for i in range(0, self.width * self.height / 8): for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF) self.send_data(0xFF)
self.send_command(DATA_START_TRANSMISSION_2) self.send_command(DATA_START_TRANSMISSION_2)
for i in range(0, self.width * self.height / 8): for i in range(0, int(self.width * self.height / 8)):
self.send_data(image[i]) self.send_data(image[i])
self.send_command(DISPLAY_REFRESH) self.send_command(DISPLAY_REFRESH)
self.wait_until_idle() self.wait_until_idle()
def Clear(self, color): def Clear(self, color):
self.send_command(DATA_START_TRANSMISSION_1) self.send_command(DATA_START_TRANSMISSION_1)
for i in range(0, self.width * self.height / 8): for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF) self.send_data(0xFF)
self.send_command(DATA_START_TRANSMISSION_2) self.send_command(DATA_START_TRANSMISSION_2)
for i in range(0, self.width * self.height / 8): for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xFF) self.send_data(0xFF)
self.send_command(DISPLAY_REFRESH) self.send_command(DISPLAY_REFRESH)
self.wait_until_idle() self.wait_until_idle()

View File

@@ -3,7 +3,7 @@ Description=the EBB carousel
After=network.target After=network.target
[Service] [Service]
ExecStart=/usr/bin/python -u carousel.py ExecStart=/usr/bin/python3 -u carousel.py
WorkingDirectory=/home/pi/ebb WorkingDirectory=/home/pi/ebb
StandardOutput=inherit StandardOutput=inherit
StandardError=inherit StandardError=inherit

BIN
install/images/._header.jpg Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
install/images/header.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 527 KiB

View File

@@ -4,7 +4,7 @@ After=network.target
[Service] [Service]
ExecStart=/bin/bash run-ssb.sh ExecStart=/bin/bash run-ssb.sh
WorkingDirectory=/home/pi/bb WorkingDirectory=/home/pi/ebb
StandardOutput=inherit StandardOutput=inherit
StandardError=inherit StandardError=inherit
Restart=always Restart=always

View File

@@ -3,11 +3,26 @@
#ok so this script should take an argument of an image and posts it #ok so this script should take an argument of an image and posts it
#add blob #add blob
blobID=$(cat $1 | ssb-server blobs.add) blobID=$(cat $1 | ssb-server blobs.add) || exit 1
echo $blobID #echo $blobID
#publish blob #publish blob
#key=$(ssb-server publish --type post --text "![upload.bmp($blobID)]" #key=$(ssb-server publish --type post --text "![upload.bmp($blobID)]"
ssb-server publish --type post --text "![photo.bmp]($blobID)" --mentions.0.name photo.bmp --mentions.0.type image/bmp #ssb-server publish --type post --text "a new photo from #dweb-camp 2022! ![photo.bmp]($blobID)" --mentions.0.name photo.jpg --mentions.0.type image/bmp --mentions.0.link
ssb-server publish . <<EOF
{
"type":"post",
"text":"a new photo from #dweb-camp 2022! ![photo.jpg]($blobID)",
"mentions": [
{
"name": "photo.jpg",
"type": "image/jpeg",
"link": "$blobID"
},
{"link":"#dweb-camp"}
]
}
EOF