From d1d0ee2aef17615e1c7eede07761cd55d375b856 Mon Sep 17 00:00:00 2001 From: trav Date: Thu, 4 Feb 2021 22:43:55 -0500 Subject: [PATCH] textual version display on boot --- README.md | 72 ++--- addtoDB.py | 14 +- carousel.py | 167 +++++++++-- etc/examples and tests/100x100.bmp | Bin 0 -> 1662 bytes etc/examples and tests/4in2.bmp | Bin 0 -> 15662 bytes .../buttonshimexamplepihole.py | 99 +++++++ etc/examples and tests/epd4in2.py | 279 ++++++++++++++++++ etc/examples and tests/epdconfig.py | 73 +++++ etc/examples and tests/photodisplaytest.py | 58 ++++ etc/examples and tests/rainbow.py | 20 ++ etc/examples and tests/upload.bmp | Bin 0 -> 15662 bytes etc/examples and tests/wavesharedemo.py | 71 +++++ etc/sleep.py | 20 ++ install/ebb-carousel.service | 2 +- install/images/starter.bmp | Bin 16064 -> 360054 bytes push.sh | 4 + refreshdb.py | 7 + weather.py | 10 + 18 files changed, 814 insertions(+), 82 deletions(-) create mode 100644 etc/examples and tests/100x100.bmp create mode 100644 etc/examples and tests/4in2.bmp create mode 100644 etc/examples and tests/buttonshimexamplepihole.py create mode 100644 etc/examples and tests/epd4in2.py create mode 100644 etc/examples and tests/epdconfig.py create mode 100644 etc/examples and tests/photodisplaytest.py create mode 100644 etc/examples and tests/rainbow.py create mode 100644 etc/examples and tests/upload.bmp create mode 100644 etc/examples and tests/wavesharedemo.py create mode 100644 etc/sleep.py create mode 100644 push.sh create mode 100644 weather.py diff --git a/README.md b/README.md index fe696b1..2f79606 100644 --- a/README.md +++ b/README.md @@ -2,40 +2,21 @@ ![a photo of the device, made out of multi-colored legos, hanging on a wall](https://git.laboratoryb.org/trav/ebb/raw/branch/master/etc/welcomehome.jpg) -EBB is an e-paper bulletin board that syncs over [Scuttlebutt](https://scuttlebutt.nz) (SSB). This program is in alpha so proceed at your own risk :) +EBB is an e-paper bulletin board that syncs over [Scuttlebutt](https://scuttlebutt.nz) (SSB). EBB is a [Slow Web](https://www.are.na/morgan-sutherland/slow-web) device. As such it is not intended to be *fast*. Thus users must exercise great patience while operating EBB. ## Usage -EBB is a [Slow Web](https://www.are.na/morgan-sutherland/slow-web) device. As such it is not intended to be *fast*. Thus users must exercise great patience while operating EBB. +Check out the [operators manual (pdf)](http://teafry.me/ebb/operatorsmanual.pdf) -After you plug in the device, while the program is loading, the LED is purple, indicating you should wait before interacting with the device. Every couple hours the EBB db is synchronized with SSB and during this time the LED shines white (also wait to interact). - -The device will automatically rotate through images in the database after a set period of time. - -There are 5 buttons on the left side, they are numbered 1-5 from top to bottom: - -**button 1:** takes a photo. The LED will go green while the photo is being taken. The photo will be taken when the red light on the camera itself goes out. A soon-to-be-written feature will allow the user to decide whether they want to keep the photo just taken and whether to store it locally or to post it to SSB. - -**button 2:** advance to the next photo. LED will turn blue while this action is busy. - -**button 3:** currently this button goes to the previous photo in the database (LED will turn blue while this action is busy) but soon the plan is for it to provide a menu with the options: -* power down -* add friend (via QR) -* show my QR (take pic/read the QR, txt to friend) - -**button 4:** delete current photo. LED will go red and an alert with instructions is presented to the user on the e-paper screen. Press button 4 again to confirm delete or press any other button to cancel. The actual BMP wont be deleted, only the entry in the database (and of course it can't be deleted from SSB, so). - -**button 5:** display the weather (currently doesn't work; a planned feature :) - ----------- +
## Building one -There are *a lot* of steps here, this is not for the faint of heart. But if you're handy on the commandline it shouldn't be too bad. I intend to streamline setup greatly. +This program is in alpha so proceed at your own risk :) ### hardware -This would probably work with a variety of parts but here are the recommended hardware components: +recommended hardware components: | part | cost | link | | -------- | -------- | -------- | @@ -45,7 +26,6 @@ This would probably work with a variety of parts but here are the recommended ha | 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 | you'll also need a micro-usb cable, usb power supply and materials to build a case from. @@ -56,35 +36,39 @@ you'll also need a micro-usb cable, usb power supply and materials to build a ca 2. Then you just gotta plug in the camera and pop the e-paper hat on top of the headers. -3. build a case out of lego or something. Have fun with it :) +3. build a case out of lego or something. Have fun with it. I've found it handy to mount the camera to some articulating lego to more easily take pictures of more things. ### software -1. download [raspbian lite](https://www.raspberrypi.org/downloads/raspbian/)(or whatever basic raspbian image) +1. download [raspbian lite](https://www.raspberrypi.org/downloads/raspbian/) (or whatever basic raspbian image) 2. [write the image to your SD card](https://www.raspberrypi.org/documentation/installation/installing-images/) -3. follow [these instructions](https://desertbot.io/blog/ssh-into-pi-zero-over-usb) to get into it over usb. AND OR, put in wifi credentials onto the card. [This page](https://www.raspberrypi.org/documentation/configuration/wireless/wireless-cli.md) says how to do it. +3. [Put in wifi credentials into the WPA_supplicant.conf file](https://raspberrypi.stackexchange.com/questions/67649/raspberry-pi-zero-w-headless-using-wpa-supplicant-conf-not-working). +4. [enable SSH on the device](https://www.raspberrypi.org/documentation/remote-access/ssh/) 4. put the card in the pi and boot it up 5. ssh-in (or connect to monitor if you didn't do step 3, connect to monitor/keyboard...) -6. use `sudo raspi-config`[(howto)](https://www.raspberrypi.org/documentation/configuration/raspi-config.md) to change timezone, set a new hostname, enable ssh, change user password, enable SPI (for e-paper screen), enable I2C (for button shim), enable camera. +6. use `sudo raspi-config` [(howto)](https://www.raspberrypi.org/documentation/configuration/raspi-config.md) to adjust: + +- set a new hostname +- enable ssh (if you haven't already) +- change user password +- enable SPI (for e-paper screen) +- enable I2C (for button shim) +- enable camera. +- timezone config + + 7. run all this stuff: (this should all be scripted but for now we're setting all these parts up manually...) ``` -sudo apt update -sudo apt upgrade -sudo apt install unattended-upgrades -sudo apt install python-dev -sudo apt install python-pip -sudo apt install python-buttonshim -sudo apt install libjpeg-dev zlib1g-dev -sudo apt install git -pip install spidev -pip install tinydb -pip install pillow --no-cache-dir +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 ``` -need to install an ARMv6 compatible NPM. This should work: +(third line can take a while...) +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 tar -xzf node.tar.gz @@ -93,9 +77,11 @@ 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/). - +
#### clone the repo -`git clone https://git.laboratoryb.org/trav/ebb.git` ideally right in your home directory. +ideally right in your home directory. + +`git clone https://git.laboratoryb.org/trav/ebb.git` #### 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. diff --git a/addtoDB.py b/addtoDB.py index 101d789..1c3a5c8 100644 --- a/addtoDB.py +++ b/addtoDB.py @@ -36,12 +36,14 @@ def addFile(pathToImage, pathToDB, SSBidentify): #print("heres the whole db") #print(db.all()) - #SEND TO SSB! WOOOO - try: - result = subprocess.call('./ssbpost.sh ' + pathToImage, shell=True) - except: - print 'traceback.format_exc():\n%s' % traceback.format_exc() - exit() + #unless you say don't post to ssb, post to ssb + if SSBidentify != -1: + #SEND TO SSB! WOOOO + try: + result = subprocess.call('./ssbpost.sh ' + pathToImage, shell=True) + except: + print 'traceback.format_exc():\n%s' % traceback.format_exc() + exit() return pathToImage diff --git a/carousel.py b/carousel.py index 5b06cab..8faeee5 100644 --- a/carousel.py +++ b/carousel.py @@ -5,6 +5,7 @@ # # carousel iterates through all posts in posts.json +import os import epd4in2 import traceback import time @@ -29,9 +30,9 @@ buttonshim.set_pixel(0xFF, 0x00, 0xFF) intervalTime = 1800 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 -timeIndex = intervalTime +timeIndex = 1200 syncIndex = 0 -dbIndex = 0 +dbIndex = 1 flierPath = "noneyet" button_flag = "null" @@ -50,17 +51,27 @@ for item in db: dbCount = item.doc_id print dbCount -#initialize display -#PIL.Image.new(mode, size, color=0) +#initialize display and display boot image +#grab the entry at dbIndex, newFlier is a dict +newFlier = db.get(doc_id=dbIndex) +flierPath = newFlier["path"] Limage = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame try: + font36 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 36) epd = epd4in2.EPD() epd.init() + bmp = Image.open(flierPath) + Limage.paste(bmp) + draw = ImageDraw.Draw(Limage) + draw.text((2, 240), 'EBB', font = font18, fill = 255) + draw.text((2, 260), 'version .02', font = font18, fill = 255) + epd.display(epd.getbuffer(Limage)) + time.sleep(2) + epd.sleep() except: print 'traceback.format_exc():\n%s' % traceback.format_exc() exit() - ## button press contingencies ## @buttonshim.on_press(buttonshim.BUTTON_A) def button_a(button, pressed): @@ -140,10 +151,9 @@ while True: flierPath = newFlier["path"] - #display the images + #display the image try: epd.init() - #Limage = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame bmp = Image.open(flierPath) Limage.paste(bmp) epd.display(epd.getbuffer(Limage)) @@ -159,39 +169,132 @@ while True: #take pic if button_flag == "button_1": + #generate unique file_name unique = uuid.uuid4() unique = str(unique) jpgpath = imagesPath + unique + '.jpg' - #take photo - try: - result = subprocess.call(['raspistill', '-o', jpgpath, '-vf', '-w', '300', '-h', '400', '-t', '1000']) - except: - print 'traceback.format_exc():\n%s' % traceback.format_exc() - exit() - #generate unique bmp name - bmpath = imagesPath + str(unique) + '.bmp' + bmpath = imagesPath + unique + '.bmp' - #convert to bmp - im = Image.open(jpgpath) - im = im.convert("1") - im.save(bmpath) - #add that file to the db. 0 is because this isn't coming from SSB, it's local - addtoDB.addFile(bmpath,dbPath,0) - #update dbCount - for item in db: - dbCount = item.doc_id + #loop in case we wanna re-take it + exitPhotoMode = False + while exitPhotoMode == False: - #display the image - epd.init() - Limage2 = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame - bmp = Image.open(bmpath) - Limage.paste(bmp) - epd.display(epd.getbuffer(Limage)) - #ok green done + #take photo + try: + result = subprocess.call(['raspistill', '-o', jpgpath, '-vf', '-hf', '-w', '300', '-h', '400', '-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 + epd.init() + bmp = Image.open(bmpath) + Limage.paste(bmp) + epd.display(epd.getbuffer(Limage)) + + #wait for user decision on photo + waited = 0 + 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) + 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) + + #led to thinking mode + buttonshim.set_pixel(0x00, 0x00, 0xFF) + + #post to ssb + if button_flag == "button_1": + button_flag == "null" + #add the photo to the db/ssb + addtoDB.addFile(bmpath,dbPath,0) + #update dbCount + for item in db: + dbCount = item.doc_id + exitPhotoMode = True + + #display the image to clear the menu (also display text "posted") + font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24) + bmp = Image.open(bmpath) + Limage.paste(bmp) + draw = ImageDraw.Draw(Limage) + draw.text((2, 240), 'PHOTO POSTED', font = font18, fill = 255) + draw.text((2, 260), 'online!', font = font18, fill = 255) + epd.display(epd.getbuffer(Limage)) + + #post only locally + if button_flag == "button_2": + button_flag == "null" + #add that file to the db. -1 tells addtoDB not to post to ssb. + addtoDB.addFile(bmpath,dbPath,-1) + #update dbCount + for item in db: + dbCount = item.doc_id + exitPhotoMode = True + #display the image to clear the menu (also display text "posted") + font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24) + bmp = Image.open(bmpath) + Limage.paste(bmp) + draw = ImageDraw.Draw(Limage) + draw.text((2, 240), 'PHOTO POSTED', font = font18, fill = 255) + draw.text((2, 260), 'to this device only', font = font18, fill = 255) + epd.display(epd.getbuffer(Limage)) + + #reshoot the picture + if button_flag == "button_3": + button_flag == "null" + #nothin! loop around... exitPhotoMode still false + + #exit photomode, delete photo + if (button_flag == "button_4") or (button_flag == "button_5"): + button_flag == "null" + exitPhotoMode = True + os.remove(bmpath) + os.remove(jpgpath) + + #led off buttonshim.set_pixel(0x00, 0x00, 0x00) time.sleep(3) timeIndex+=2 @@ -290,7 +393,7 @@ while True: #display the weather epd.init() - Limage2 = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame + Limage = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame bmp = Image.open("btv.bmp") Limage.paste(bmp) epd.display(epd.getbuffer(Limage)) diff --git a/etc/examples and tests/100x100.bmp b/etc/examples and tests/100x100.bmp new file mode 100644 index 0000000000000000000000000000000000000000..8d0d675f5b95e12413bcd22e1f7fef33175593c0 GIT binary patch literal 1662 zcmZ?rtz%;V13Mt80mLa#%*en97Iy&33voj*SO7}=|NkGEOFUa1s1pbpU^?W%++oE3 k!N8B=zfu064i8{DL~-9Je>6Oh^Y3VSAUQq2igrRY08D+GTL1t6 literal 0 HcmV?d00001 diff --git a/etc/examples and tests/4in2.bmp b/etc/examples and tests/4in2.bmp new file mode 100644 index 0000000000000000000000000000000000000000..b380a1cbfc4d437e7eac77fa2e86631ef7cfbe32 GIT binary patch literal 15662 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 X?f?BQqd%uR8-V*=_I};}nFam>6LNdO literal 0 HcmV?d00001 diff --git a/etc/examples and tests/buttonshimexamplepihole.py b/etc/examples and tests/buttonshimexamplepihole.py new file mode 100644 index 0000000..fecf8e3 --- /dev/null +++ b/etc/examples and tests/buttonshimexamplepihole.py @@ -0,0 +1,99 @@ +#!/user/bin/env python + +import signal +import buttonshim +import time +import subprocess + +print(""" + Pi-Hole Button Control Running.... + + Press Ctrl+C to Exit. + """) + +#Cycle and clear LEDs on startup (visual indication the script is running) +buttonshim.set_pixel(255,0,0) +time.sleep(0.3) +buttonshim.set_pixel(0,255,0) +time.sleep(0.3) +buttonshim.set_pixel(0,0,255) +time.sleep(0.3) +buttonshim.set_pixel(0,0,0) +pressId = 0 + +while True: + def DisablePiholeTimer(numSecs): + global pressId + loopId = pressId + for i in range(0,numSecs): + if ( loopId != pressId): + print "Ending loop with ID: " + str(loopId) + return + print "Pi-Hole disabled for " + str(numSecs-i) + buttonshim.set_pixel(255,255,0) + time.sleep(0.5) + buttonshim.set_pixel(255,150,0) + time.sleep(0.5) + buttonshim.set_pixel(0,0,0) + print "Pi-Hole reenabled" + + def SuspendPihole(): + global pressId + loopId = pressId + print "Pi-Hole suspended" + while (loopId == pressId): + buttonshim.set_pixel(255,0,0) + time.sleep(0.5) + buttonshim.set_pixel(0,0,0) + time.sleep(0.5) + + def EnablePihole(): + global pressId + loopId = pressId + print "Pi-Hole enabled" + for i in range(0,2): + buttonshim.set_pixel(0,255,0) + time.sleep(0.3) + buttonshim.set_pixel(0,0,0) + time.sleep(0.3) + + + @buttonshim.on_press(buttonshim.BUTTON_A) + def button_a(button, pressed): + print "Disabling Pi-Hole for 300s" + global pressId + pressId += 1 + subprocess.call(['pihole','disable','300s']) + DisablePiholeTimer(int(300)) + + @buttonshim.on_press(buttonshim.BUTTON_B) + def button_b(button, pressed): + print "Disabling Pi-Hole for 1800s" + global pressId + pressId += 1 + subprocess.call(['pihole','disable','1800s']) + DisablePiholeTimer(int(1800)) + + @buttonshim.on_press(buttonshim.BUTTON_C) + def button_c(button, pressed): + print "This button, it does nothing" + + @buttonshim.on_press(buttonshim.BUTTON_D) + def button_d(button, pressed): + print "Suspending Pi-Hole" + global pressId + pressId += 1 + subprocess.call(['pihole','disable']) + SuspendPihole() + + @buttonshim.on_press(buttonshim.BUTTON_E) + def button_e(button, pressed): + print "Enabling Pi-Hole" + global pressId + pressId += 1 + subprocess.call(['pihole','enable']) + EnablePihole() + + + + signal.pause() diff --git a/etc/examples and tests/epd4in2.py b/etc/examples and tests/epd4in2.py new file mode 100644 index 0000000..567ae25 --- /dev/null +++ b/etc/examples and tests/epd4in2.py @@ -0,0 +1,279 @@ +# /***************************************************************************** +# * | File : EPD_1in54.py +# * | Author : Waveshare team +# * | Function : Electronic paper driver +# * | Info : +# *---------------- +# * | This version: V3.0 +# * | Date : 2018-11-06 +# * | Info : python2 demo +# * 1.Remove: +# digital_write(self, pin, value) +# digital_read(self, pin) +# delay_ms(self, delaytime) +# set_lut(self, lut) +# self.lut = self.lut_full_update +# * 2.Change: +# display_frame -> TurnOnDisplay +# set_memory_area -> SetWindow +# set_memory_pointer -> SetCursor +# get_frame_buffer -> getbuffer +# set_frame_memory -> display +# * 3.How to use +# epd = epd2in7.EPD() +# epd.init(epd.lut_full_update) +# image = Image.new('1', (epd1in54.EPD_WIDTH, epd1in54.EPD_HEIGHT), 255) +# ... +# drawing ...... +# ... +# epd.display(getbuffer(image)) +# ******************************************************************************/ +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import epdconfig +from PIL import Image +import RPi.GPIO as GPIO + +# Display resolution +EPD_WIDTH = 400 +EPD_HEIGHT = 300 + +# GDEW042T2 commands +PANEL_SETTING = 0x00 +POWER_SETTING = 0x01 +POWER_OFF = 0x02 +POWER_OFF_SEQUENCE_SETTING = 0x03 +POWER_ON = 0x04 +POWER_ON_MEASURE = 0x05 +BOOSTER_SOFT_START = 0x06 +DEEP_SLEEP = 0x07 +DATA_START_TRANSMISSION_1 = 0x10 +DATA_STOP = 0x11 +DISPLAY_REFRESH = 0x12 +DATA_START_TRANSMISSION_2 = 0x13 +LUT_FOR_VCOM = 0x20 +LUT_WHITE_TO_WHITE = 0x21 +LUT_BLACK_TO_WHITE = 0x22 +LUT_WHITE_TO_BLACK = 0x23 +LUT_BLACK_TO_BLACK = 0x24 +PLL_CONTROL = 0x30 +TEMPERATURE_SENSOR_COMMAND = 0x40 +TEMPERATURE_SENSOR_SELECTION = 0x41 +TEMPERATURE_SENSOR_WRITE = 0x42 +TEMPERATURE_SENSOR_READ = 0x43 +VCOM_AND_DATA_INTERVAL_SETTING = 0x50 +LOW_POWER_DETECTION = 0x51 +TCON_SETTING = 0x60 +RESOLUTION_SETTING = 0x61 +GSST_SETTING = 0x65 +GET_STATUS = 0x71 +AUTO_MEASUREMENT_VCOM = 0x80 +READ_VCOM_VALUE = 0x81 +VCM_DC_SETTING = 0x82 +PARTIAL_WINDOW = 0x90 +PARTIAL_IN = 0x91 +PARTIAL_OUT = 0x92 +PROGRAM_MODE = 0xA0 +ACTIVE_PROGRAMMING = 0xA1 +READ_OTP = 0xA2 +POWER_SAVING = 0xE3 +class EPD: + def __init__(self): + self.reset_pin = epdconfig.RST_PIN + self.dc_pin = epdconfig.DC_PIN + self.busy_pin = epdconfig.BUSY_PIN + self.width = EPD_WIDTH + self.height = EPD_HEIGHT + + lut_vcom0 = [ + 0x00, 0x17, 0x00, 0x00, 0x00, 0x02, + 0x00, 0x17, 0x17, 0x00, 0x00, 0x02, + 0x00, 0x0A, 0x01, 0x00, 0x00, 0x01, + 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_ww = [ + 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, + 0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, + 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_bw = [ + 0x40, 0x17, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, + 0x40, 0x0A, 0x01, 0x00, 0x00, 0x01, + 0xA0, 0x0E, 0x0E, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_wb = [ + 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, + 0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, + 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + lut_bb = [ + 0x80, 0x17, 0x00, 0x00, 0x00, 0x02, + 0x90, 0x17, 0x17, 0x00, 0x00, 0x02, + 0x80, 0x0A, 0x01, 0x00, 0x00, 0x01, + 0x50, 0x0E, 0x0E, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + + # Hardware reset + def reset(self): + epdconfig.digital_write(self.reset_pin, GPIO.HIGH) + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, GPIO.LOW) # module reset + epdconfig.delay_ms(200) + epdconfig.digital_write(self.reset_pin, GPIO.HIGH) + epdconfig.delay_ms(200) + + def send_command(self, command): + epdconfig.digital_write(self.dc_pin, GPIO.LOW) + epdconfig.spi_writebyte([command]) + + def send_data(self, data): + epdconfig.digital_write(self.dc_pin, GPIO.HIGH) + epdconfig.spi_writebyte([data]) + + def wait_until_idle(self): + while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy + epdconfig.delay_ms(100) + + def set_lut(self): + self.send_command(LUT_FOR_VCOM) # vcom + for count in range(0, 44): + self.send_data(self.lut_vcom0[count]) + self.send_command(LUT_WHITE_TO_WHITE) # ww -- + for count in range(0, 42): + self.send_data(self.lut_ww[count]) + self.send_command(LUT_BLACK_TO_WHITE) # bw r + for count in range(0, 42): + self.send_data(self.lut_bw[count]) + self.send_command(LUT_WHITE_TO_BLACK) # wb w + for count in range(0, 42): + self.send_data(self.lut_bb[count]) + self.send_command(LUT_BLACK_TO_BLACK) # bb b + for count in range(0, 42): + self.send_data(self.lut_wb[count]) + + def init(self): + if (epdconfig.module_init() != 0): + return -1 + # EPD hardware init start + self.reset() + + self.send_command(POWER_SETTING) + self.send_data(0x03) # VDS_EN, VDG_EN + self.send_data(0x00) # VCOM_HV, VGHL_LV[1], VGHL_LV[0] + self.send_data(0x2b) # VDH + self.send_data(0x2b) # VDL + self.send_command(BOOSTER_SOFT_START) + self.send_data(0x17) + self.send_data(0x17) + self.send_data(0x17) + self.send_command(POWER_ON) + self.wait_until_idle() + self.send_command(PANEL_SETTING) + self.send_data(0xbf) # KW-BF KWR-AF BWROTP 0f + self.send_data(0x0d) + self.send_command(PLL_CONTROL) + self.send_data(0x3c) # 3A 100HZ 29 150Hz 39 200HZ 31 171HZ + + self.send_command(0x61); # resolution setting + self.send_data(0x01); + self.send_data(0x90); # 128 + self.send_data(0x01); + self.send_data(0x2c); + + self.send_command(0x82); # vcom_DC setting + self.send_data(0x28); + + self.send_command(0X50); # VCOM AND DATA INTERVAL SETTING + self.send_data(0x97); # 97white border 77black border VBDF 17|D7 VBDW 97 VBDB 57 VBDF F7 VBDW 77 VBDB 37 VBDR B7 + + self.set_lut() + # EPD hardware init end + return 0 + + def getbuffer(self, image): + # print "bufsiz = ",(self.width/8) * self.height + buf = [0xFF] * ((self.width/8) * self.height) + image_monocolor = image.convert('1') + imwidth, imheight = image_monocolor.size + pixels = image_monocolor.load() + # print "imwidth = %d, imheight = %d",imwidth,imheight + if(imwidth == self.width and imheight == self.height): + print "Horizontal" + for y in range(imheight): + for x in range(imwidth): + # Set the bits for the column of pixels at the current position. + if pixels[x, y] == 0: + buf[(x + y * self.width) / 8] &= ~(0x80 >> (x % 8)) + elif(imwidth == self.height and imheight == self.width): + print "Vertical" + for y in range(imheight): + for x in range(imwidth): + newx = y + newy = self.height - x - 1 + if pixels[x, y] == 0: + buf[(newx + newy*self.width) / 8] &= ~(0x80 >> (y % 8)) + return buf + + def display(self, image): + self.send_command(DATA_START_TRANSMISSION_1) + for i in range(0, self.width * self.height / 8): + self.send_data(0xFF) + self.send_command(DATA_START_TRANSMISSION_2) + for i in range(0, self.width * self.height / 8): + self.send_data(image[i]) + self.send_command(DISPLAY_REFRESH) + self.wait_until_idle() + + def Clear(self, color): + self.send_command(DATA_START_TRANSMISSION_1) + for i in range(0, self.width * self.height / 8): + self.send_data(0xFF) + self.send_command(DATA_START_TRANSMISSION_2) + for i in range(0, self.width * self.height / 8): + self.send_data(0xFF) + self.send_command(DISPLAY_REFRESH) + self.wait_until_idle() + + def sleep(self): + self.send_command(POWER_OFF) + self.wait_until_idle() + self.send_command(DEEP_SLEEP) + self.send_data(0XA5) +### END OF FILE ### + diff --git a/etc/examples and tests/epdconfig.py b/etc/examples and tests/epdconfig.py new file mode 100644 index 0000000..78ff647 --- /dev/null +++ b/etc/examples and tests/epdconfig.py @@ -0,0 +1,73 @@ +# /***************************************************************************** +# * | File : EPD_1in54.py +# * | Author : Waveshare team +# * | Function : Hardware underlying interface +# * | Info : +# *---------------- +# * | This version: V2.0 +# * | Date : 2018-11-01 +# * | Info : +# * 1.Remove: +# digital_write(self, pin, value) +# digital_read(self, pin) +# delay_ms(self, delaytime) +# set_lut(self, lut) +# self.lut = self.lut_full_update +# ******************************************************************************/ +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documnetation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + + +import spidev +import RPi.GPIO as GPIO +import time + +# Pin definition +RST_PIN = 17 +DC_PIN = 25 +CS_PIN = 8 +BUSY_PIN = 24 + +# SPI device, bus = 0, device = 0 +SPI = spidev.SpiDev(0, 0) + +def digital_write(pin, value): + GPIO.output(pin, value) + +def digital_read(pin): + return GPIO.input(BUSY_PIN) + +def delay_ms(delaytime): + time.sleep(delaytime / 1000.0) + +def spi_writebyte(data): + SPI.writebytes(data) + +def module_init(): + GPIO.setmode(GPIO.BCM) + GPIO.setwarnings(False) + GPIO.setup(RST_PIN, GPIO.OUT) + GPIO.setup(DC_PIN, GPIO.OUT) + GPIO.setup(CS_PIN, GPIO.OUT) + GPIO.setup(BUSY_PIN, GPIO.IN) + SPI.max_speed_hz = 2000000 + SPI.mode = 0b00 + return 0; + +### END OF FILE ### diff --git a/etc/examples and tests/photodisplaytest.py b/etc/examples and tests/photodisplaytest.py new file mode 100644 index 0000000..ae150a2 --- /dev/null +++ b/etc/examples and tests/photodisplaytest.py @@ -0,0 +1,58 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +#this script takes a file as an option and adds that file to the db + +import optparse +import traceback +import os, sys +import time +import uuid +import subprocess +import epd4in2 +import traceback +from PIL import Image,ImageDraw,ImageFont + +#generate unique file_name +unique = uuid.uuid4() +unique = str(unique) +jpgpath = 'photos/' + unique + '.jpg' +bmppath = 'photos/' + unique + '.bmp' + +#take photo +try: + result = subprocess.call(['raspistill', '-o', jpgpath]) + print (result) + +except: + print 'traceback.format_exc():\n%s' % traceback.format_exc() + exit() + +time.sleep(3) + +#convert +size = 400, 300 +im = Image.open(jpgpath) +print("opening...") +print (jpgpath) +im = im.rotate(180, Image.NEAREST, "expand=1") +im.thumbnail(size, Image.BICUBIC) +im = im.convert("1") +im.save(bmppath) +print("saving to...") +print (bmppath) + +#print! +try: + epd = epd4in2.EPD() + epd.init() + Himage2 = Image.new('1', (epd4in2.EPD_WIDTH, epd4in2.EPD_HEIGHT), 255) # 255: clear the frame + bmp = Image.open(bmppath) + Himage.paste(bmp) + epd.display(epd.getbuffer(Himage)) + time.sleep(2) + epd.sleep() + +except: + print 'traceback.format_exc():\n%s' % traceback.format_exc() + exit() diff --git a/etc/examples and tests/rainbow.py b/etc/examples and tests/rainbow.py new file mode 100644 index 0000000..8c1dc97 --- /dev/null +++ b/etc/examples and tests/rainbow.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +import time +import buttonshim +print ("white") +buttonshim.set_pixel(0xFF, 0xFF, 0xFF) +time.sleep(3) +print ("blue") +buttonshim.set_pixel(0x00, 0x00, 0xff) +time.sleep(3) +print ("green") +buttonshim.set_pixel(0x00, 0xff, 0x00) +time.sleep(3) +print ("yellow?") +buttonshim.set_pixel(0xff, 0xff, 0x00) +time.sleep(3) +print ("red") +buttonshim.set_pixel(0xff, 0x00, 0x00) +time.sleep(3) diff --git a/etc/examples and tests/upload.bmp b/etc/examples and tests/upload.bmp new file mode 100644 index 0000000000000000000000000000000000000000..845f1fa361b99390340559b8494d819563b5a71b GIT binary patch literal 15662 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 a`syOUXA`T7kqG3G(*D(YSI2(&*Z&_d=`NE1 literal 0 HcmV?d00001 diff --git a/etc/examples and tests/wavesharedemo.py b/etc/examples and tests/wavesharedemo.py new file mode 100644 index 0000000..4195c3a --- /dev/null +++ b/etc/examples and tests/wavesharedemo.py @@ -0,0 +1,71 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +import epd4in2 +import time +from PIL import Image,ImageDraw,ImageFont +import traceback + +try: + epd = epd4in2.EPD() + epd.init() + epd.Clear(0xFF) + + # Drawing on the Horizontal image + Himage = Image.new('1', (epd4in2.EPD_WIDTH, epd4in2.EPD_HEIGHT), 255) # 255: clear the frame + # Drawing on the Vertical image + Limage = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame + + # Horizontal + print "Drawing" + draw = ImageDraw.Draw(Himage) + font24 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 24) + draw.text((10, 0), 'hello world', font = font24, fill = 0) + draw.text((10, 20), '2.9inch e-Paper', font = font24, fill = 0) + draw.text((150, 0), u'微雪电子', font = font24, fill = 0) + draw.line((20, 50, 70, 100), fill = 0) + draw.line((70, 50, 20, 100), fill = 0) + draw.rectangle((20, 50, 70, 100), outline = 0) + draw.line((165, 50, 165, 100), fill = 0) + draw.line((140, 75, 190, 75), fill = 0) + draw.arc((140, 50, 190, 100), 0, 360, fill = 0) + draw.rectangle((80, 50, 130, 100), fill = 0) + draw.chord((200, 50, 250, 100), 0, 360, fill = 0) + epd.display(epd.getbuffer(Himage)) + time.sleep(2) + + # Vertical + draw = ImageDraw.Draw(Limage) + font18 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 18) + draw.text((2, 0), 'hello world', font = font18, fill = 0) + draw.text((2, 20), '2.9inch epd', font = font18, fill = 0) + draw.text((20, 50), u'微雪电子', font = font18, fill = 0) + draw.line((10, 90, 60, 140), fill = 0) + draw.line((60, 90, 10, 140), fill = 0) + draw.rectangle((10, 90, 60, 140), outline = 0) + draw.line((95, 90, 95, 140), fill = 0) + draw.line((70, 115, 120, 115), fill = 0) + draw.arc((70, 90, 120, 140), 0, 360, fill = 0) + draw.rectangle((10, 150, 60, 200), fill = 0) + draw.chord((70, 150, 120, 200), 0, 360, fill = 0) + epd.display(epd.getbuffer(Limage)) + time.sleep(2) + + print "read bmp file" + Himage = Image.open('4in2.bmp') + epd.display(epd.getbuffer(Himage)) + time.sleep(2) + + print "read bmp file on window" + Himage2 = Image.new('1', (epd4in2.EPD_WIDTH, epd4in2.EPD_HEIGHT), 255) # 255: clear the frame + bmp = Image.open('100x100.bmp') + Himage2.paste(bmp, (50,10)) + epd.display(epd.getbuffer(Himage2)) + time.sleep(2) + + epd.sleep() + +except: + print 'traceback.format_exc():\n%s' % traceback.format_exc() + exit() + diff --git a/etc/sleep.py b/etc/sleep.py new file mode 100644 index 0000000..7bf466c --- /dev/null +++ b/etc/sleep.py @@ -0,0 +1,20 @@ +#!/usr/bin/python +# -*- coding:utf-8 -*- + +#this is a way to manually sleep the display if the code crashed before the epd.sleep() command + +import epd4in2 +import traceback +import time +import signal + +#initialize display +try: + epd = epd4in2.EPD() + epd.init() + time.sleep(2) + epd.sleep() + print ("the display sleeps ZZZzzzz....") +except: + print 'traceback.format_exc():\n%s' % traceback.format_exc() + exit() diff --git a/install/ebb-carousel.service b/install/ebb-carousel.service index d12bedd..48f26b7 100644 --- a/install/ebb-carousel.service +++ b/install/ebb-carousel.service @@ -4,7 +4,7 @@ After=network.target [Service] ExecStart=/usr/bin/python -u carousel.py -WorkingDirectory=/home/pi/bb +WorkingDirectory=/home/pi/ebb StandardOutput=inherit StandardError=inherit Restart=always diff --git a/install/images/starter.bmp b/install/images/starter.bmp index 09763e8dbee09b1f1c4515f6a8861b177f8aff81..86e507abac783e0eb8d20f59042c8e75578c2873 100644 GIT binary patch literal 360054 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