Browse Source

textual version display on boot

master
trav 3 months ago
parent
commit
d1d0ee2aef
  1. 72
      README.md
  2. 14
      addtoDB.py
  3. 167
      carousel.py
  4. BIN
      etc/examples and tests/100x100.bmp
  5. BIN
      etc/examples and tests/4in2.bmp
  6. 99
      etc/examples and tests/buttonshimexamplepihole.py
  7. 279
      etc/examples and tests/epd4in2.py
  8. 73
      etc/examples and tests/epdconfig.py
  9. 58
      etc/examples and tests/photodisplaytest.py
  10. 20
      etc/examples and tests/rainbow.py
  11. BIN
      etc/examples and tests/upload.bmp
  12. 71
      etc/examples and tests/wavesharedemo.py
  13. 20
      etc/sleep.py
  14. 2
      install/ebb-carousel.service
  15. BIN
      install/images/starter.bmp
  16. 4
      push.sh
  17. 7
      refreshdb.py
  18. 10
      weather.py

72
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 :)
----------
<br>
## 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/).
<br>
#### 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.

14
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

167
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))

BIN
etc/examples and tests/100x100.bmp

BIN
etc/examples and tests/4in2.bmp

99
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()

279
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 ###

73
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 ###

58
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()

20
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)

BIN
etc/examples and tests/upload.bmp

71
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()

20
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()

2
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

BIN
install/images/starter.bmp

4
push.sh

@ -0,0 +1,4 @@
#!/bin/bash
git add .
git commit -m "$1"
git push

7
refreshdb.py

@ -8,6 +8,7 @@ import json
import re
import subprocess
import datetime
import time
import traceback
import iterparse
import uuid
@ -33,6 +34,12 @@ def fresh():
root_entry = db.get(doc_id=1)
last_run = root_entry["date"]
#if last run is never ran then only look back 1 month (new installs don't need EVERY old post...)
if last_run==4:
whatever=time.time()
whaever-=2700000
last_run=int(whatever)
newssb="nada"
newssbcmd = 'ssb-server createLogStream --reverse 1 --gt ' + str(last_run)

10
weather.py

@ -0,0 +1,10 @@
proc = subprocess.Popen(["curl", "wttr.in"], stdout=subprocess.PIPE)
(out, err) = proc.communicate()
#display the weather
Limage = Image.new('1', (epd4in2.EPD_HEIGHT, epd4in2.EPD_WIDTH), 255) # 255: clear the frame
draw = ImageDraw.Draw(Limage)
font12 = ImageFont.truetype('/usr/share/fonts/truetype/wqy/wqy-microhei.ttc', 12)
draw.text((10, 0), out, font = font12, fill = 0)
epd.display(epd.getbuffer(Limage))
time.sleep(1)
epd.sleep()
Loading…
Cancel
Save