diff --git a/._README.md b/._README.md new file mode 100644 index 0000000..ba6ce21 Binary files /dev/null and b/._README.md differ diff --git a/._addtoDB.py b/._addtoDB.py new file mode 100644 index 0000000..b8d92e0 Binary files /dev/null and b/._addtoDB.py differ diff --git a/._carousel.py b/._carousel.py new file mode 100644 index 0000000..6718be4 Binary files /dev/null and b/._carousel.py differ diff --git a/._refreshdb.py b/._refreshdb.py new file mode 100644 index 0000000..f697dde Binary files /dev/null and b/._refreshdb.py differ diff --git a/._ssbpost.sh b/._ssbpost.sh new file mode 100644 index 0000000..876e3c3 Binary files /dev/null and b/._ssbpost.sh differ diff --git a/README.md b/README.md index 2f79606..ddde0da 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,8 @@ recommended hardware components: | micro-sd card | variable, $5.8 on amazon | | | 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)| -| 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. @@ -63,11 +64,14 @@ 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 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...) +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 + 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 diff --git a/addtoDB.py b/addtoDB.py index 249a4cd..529c777 100644 --- a/addtoDB.py +++ b/addtoDB.py @@ -4,6 +4,7 @@ #this script takes a file as an option and adds that file to the db and posts the file to scuttlebutt import optparse +import iterparse import traceback import os, sys import subprocess @@ -26,12 +27,12 @@ def main(): -def addFile(pathToImage, pathToDB, SSBidentify): +def addFile(pathToImage, pathToDB, SSBidentify, composite): #init db db = TinyDB(pathToDB) #add to db - db.insert({'path': pathToImage, 'date': 4, 'ssb': SSBidentify}) + db.insert({'path': pathToImage, 'date': 4, 'ssb': SSBidentify, 'composite': composite}) print("all done, added to db") #print("heres the whole db") #print(db.all()) @@ -45,7 +46,17 @@ def addFile(pathToImage, pathToDB, SSBidentify): print('traceback.format_exc():\n%s' % traceback.format_exc()) exit() - return pathToImage + + # get the ssb json from the bash command we just ran + newssb=result.stdout.read() + + # iterate through new ssb posts + for decoded in iterparse.parsy(newssb): + # get the key for the post we just made + key = decoded['key'] + + + return key if __name__ == '__main__': diff --git a/carousel.py b/carousel.py index cd94eb9..87b24f0 100755 --- a/carousel.py +++ b/carousel.py @@ -16,6 +16,8 @@ import buttonshim import addtoDB import refreshdb import configparser +import pyqrcode +import qrcode from tinydb import TinyDB, Query from PIL import Image,ImageDraw,ImageFont @@ -63,8 +65,8 @@ try: bmp = Image.open(str(flierPath)) Limage.paste(bmp) draw = ImageDraw.Draw(Limage) - draw.text((2, 280), 'EBB', font = font18, fill = 255) - draw.text((2, 300), 'version .02', font = font18, fill = 255) + # draw.text((2, 280), 'EBB', font = font18, fill = 255) + draw.text((2, 300), 'Scuttlebooth 2', font = font18, fill = 255) epd.display(epd.getbuffer(Limage)) time.sleep(2) epd.sleep() @@ -109,6 +111,19 @@ 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 + ## MAIN LOOP ## while True: # chill for a bit, keep track of how long we're chilling @@ -173,68 +188,102 @@ while True: #take pic if button_flag == "button_1": - #generate unique file_name - unique = uuid.uuid4() - unique = str(unique) - jpgpath = imagesPath + unique + '.jpg' + #generate 3 unique file_names + unique1 = uuid.uuid4() + unique1 = str(unique1) + 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 exitPhotoMode = False while exitPhotoMode == False: - #take photo + + #take fullsize photos try: - result = subprocess.call(['raspistill', '-o', jpgpath, '-vf', '-hf', '-w', '300', '-h', '400', '-t', '1000']) + result = subprocess.call(['raspistill', '-rot', '180', '-o', jpgpath1, '-vf', '-hf', '-w', '600', '-h', '800', '-t', '1000']) except: print('traceback.format_exc():\n%s' % traceback.format_exc()) exit() - - #convert to bmp - im = Image.open(jpgpath) - im = im.convert("1") - im.save(bmpath) - - #display the image + try: + result = subprocess.call(['raspistill', '-rot', '180', '-o', jpgpath2, '-vf', '-hf', '-w', '600', '-h', '800', '-t', '1000']) + except: + print('traceback.format_exc():\n%s' % traceback.format_exc()) + exit() + try: + result = subprocess.call(['raspistill', '-rot', '180', '-o', jpgpath3, '-vf', '-hf', '-w', '600', '-h', '800', '-t', '1000']) + except: + print('traceback.format_exc():\n%s' % traceback.format_exc()) + exit() + + #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 = half1.resize(newsize) + half3 = half1.resize(newsize) + half1 = half1.convert("1") + half1.save(bmpath1) + half2 = im2.convert("1") + half2.save(bmpath2) + half3 = im3.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() - bmp = Image.open(bmpath) - Limage.paste(bmp) 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" - - #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": buttonshim.set_pixel(0xFF, 0x00, 0x00) time.sleep(.2) @@ -247,12 +296,78 @@ while True: #led to thinking mode buttonshim.set_pixel(0x00, 0x00, 0xFF) + + + # 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) + header = Image.open(composite) + im1 = Image.open(jpgpath1) + im2 = Image.open(jpgpath2) + im3 = Image.open(jpgpath3) + + get_concat_v(header, im1).save(composite) + concaz = Image.open(conposite) + get_concat_v(concaz, im2).save(composite) + concaz = Image.open(conposite) + get_concat_v(concaz, im3).save(composite) + concaz = Image.open(conposite) + - #post to ssb + #post to ssb and print if button_flag == "button_1": button_flag == "null" + + #add the photo to the db/ssb - addtoDB.addFile(bmpath,dbPath,0) + key = addtoDB.addFile(bmpath,dbPath,0,composite) + + + + # 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 = 4, + border = 1, + ) + # Add data + qr.add_data(key) + qr.make(fit=True) + # Create an image from the QR Code instance + img = qr.make_image() + + + + # concatenate QR instructions with QR + whereQRinstructionsAre = imagesPath + 'ssbqrinstgurct.bmp' + qrInstruct = Image.open(whereQRinstructionsAre) + + + + # concatenate QR+instructions to full composite for print + + + #generate unique file_name + unique = uuid.uuid4() + unique = str(unique) + FULLcomposite = imagesPath + unique + '.jpg' + + get_concat_v(concaz, (get_concat_h(qrInstruct, img))).save(FULLcomposite) + + # bash lp of Fullcomposite + + + + + + #update dbCount for item in db: dbCount = item.doc_id @@ -267,7 +382,14 @@ while True: draw.text((2, 260), 'online!', font = font18, fill = 255) epd.display(epd.getbuffer(Limage)) - #post only locally + + + + + + + + #post only locally and print if button_flag == "button_2": button_flag == "null" #add that file to the db. -1 tells addtoDB not to post to ssb. @@ -285,17 +407,32 @@ while True: draw.text((2, 260), 'to this device only', font = font18, fill = 255) epd.display(epd.getbuffer(Limage)) - #reshoot the picture + #just print if button_flag == "button_3": button_flag == "null" #nothin! loop around... exitPhotoMode still false + + try: + result = subprocess.call(['raspistill', '-rot', '180', '-o', jpgpath3, '-vf', '-hf', '-w', '600', '-h', '800', '-t', '1000']) + except: + print('traceback.format_exc():\n%s' % traceback.format_exc()) + exit() + - #exit photomode, delete photo - if (button_flag == "button_4") or (button_flag == "button_5"): + #reshoot + if (button_flag == "button_4"): button_flag == "null" exitPhotoMode = True os.remove(bmpath) os.remove(jpgpath) + + #exit photo mode + if (button_flag == "button_5"): + button_flag == "null" + exitPhotoMode = True + os.remove(bmpath) + os.remove(jpgpath) + #led off buttonshim.set_pixel(0x00, 0x00, 0x00) diff --git a/install/images/._header.jpg b/install/images/._header.jpg new file mode 100644 index 0000000..3b960de Binary files /dev/null and b/install/images/._header.jpg differ diff --git a/install/images/._instructions.bmp b/install/images/._instructions.bmp new file mode 100644 index 0000000..d63a396 Binary files /dev/null and b/install/images/._instructions.bmp differ diff --git a/install/images/._ssbqrinstgurct.bmp b/install/images/._ssbqrinstgurct.bmp new file mode 100644 index 0000000..2896e24 Binary files /dev/null and b/install/images/._ssbqrinstgurct.bmp differ diff --git a/install/images/header.jpg b/install/images/header.jpg new file mode 100644 index 0000000..e15af12 Binary files /dev/null and b/install/images/header.jpg differ diff --git a/install/images/instructions.bmp b/install/images/instructions.bmp new file mode 100644 index 0000000..537556d Binary files /dev/null and b/install/images/instructions.bmp differ diff --git a/install/images/ssbqrinstgurct.bmp b/install/images/ssbqrinstgurct.bmp new file mode 100644 index 0000000..eac5d6c Binary files /dev/null and b/install/images/ssbqrinstgurct.bmp differ diff --git a/install/ssb.service b/install/ssb.service index 1cef77d..8052793 100755 --- a/install/ssb.service +++ b/install/ssb.service @@ -4,7 +4,7 @@ After=network.target [Service] ExecStart=/bin/bash run-ssb.sh -WorkingDirectory=/home/pi/bb +WorkingDirectory=/home/pi/ebb StandardOutput=inherit StandardError=inherit Restart=always