commit
96f99419a6
@ -180,5 +180,5 @@ EOF
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e "\e[1;36m"You can test if the programm works by running:"\e[0m"
|
echo -e "\e[1;36m"You can test if the programm works by running:"\e[0m"
|
||||||
echo -e "\e[1;36m"python3 /home/"$USER"/Inky-Calendar/Calendar/inkycal.py"\e[0m"
|
echo -e "\e[1;36m"python3 /home/"$USER"/Inky-Calendar/modules/inkycal.py"\e[0m"
|
||||||
fi
|
fi
|
||||||
|
478
modules/drivers/epd_4_in_2.py
Normal file
478
modules/drivers/epd_4_in_2.py
Normal file
@ -0,0 +1,478 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd4in2.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
from PIL import Image
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 400
|
||||||
|
EPD_HEIGHT = 300
|
||||||
|
|
||||||
|
GRAY1 = 0xff #white
|
||||||
|
GRAY2 = 0xC0
|
||||||
|
GRAY3 = 0x80 #gray
|
||||||
|
GRAY4 = 0x00 #Blackest
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
self.GRAY1 = GRAY1 #white
|
||||||
|
self.GRAY2 = GRAY2
|
||||||
|
self.GRAY3 = GRAY3 #gray
|
||||||
|
self.GRAY4 = GRAY4 #Blackest
|
||||||
|
|
||||||
|
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,
|
||||||
|
]
|
||||||
|
|
||||||
|
#******************************gray*********************************/
|
||||||
|
#0~3 gray
|
||||||
|
EPD_4IN2_4Gray_lut_vcom =[
|
||||||
|
0x00 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x60 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x00 ,0x14 ,0x00 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x00 ,0x13 ,0x0A ,0x01 ,0x00 ,0x01,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00
|
||||||
|
]
|
||||||
|
#R21
|
||||||
|
EPD_4IN2_4Gray_lut_ww =[
|
||||||
|
0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x10 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01,
|
||||||
|
0xA0 ,0x13 ,0x01 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
]
|
||||||
|
#R22H r
|
||||||
|
EPD_4IN2_4Gray_lut_bw =[
|
||||||
|
0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01,
|
||||||
|
0x99 ,0x0C ,0x01 ,0x03 ,0x04 ,0x01,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
]
|
||||||
|
#R23H w
|
||||||
|
EPD_4IN2_4Gray_lut_wb =[
|
||||||
|
0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01,
|
||||||
|
0x99 ,0x0B ,0x04 ,0x04 ,0x01 ,0x01,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00,
|
||||||
|
]
|
||||||
|
#R24H b
|
||||||
|
EPD_4IN2_4Gray_lut_bb =[
|
||||||
|
0x80 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01,
|
||||||
|
0x20 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01,
|
||||||
|
0x50 ,0x13 ,0x01 ,0x00 ,0x00 ,0x01,
|
||||||
|
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, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(10)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
self.send_command(0x71)
|
||||||
|
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
||||||
|
self.send_command(0x71)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
|
||||||
|
def set_lut(self):
|
||||||
|
self.send_command(0x20) # vcom
|
||||||
|
for count in range(0, 44):
|
||||||
|
self.send_data(self.lut_vcom0[count])
|
||||||
|
|
||||||
|
self.send_command(0x21) # ww --
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.lut_ww[count])
|
||||||
|
|
||||||
|
self.send_command(0x22) # bw r
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.lut_bw[count])
|
||||||
|
|
||||||
|
self.send_command(0x23) # wb w
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.lut_bb[count])
|
||||||
|
|
||||||
|
self.send_command(0x24) # bb b
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.lut_wb[count])
|
||||||
|
|
||||||
|
def Gray_SetLut(self):
|
||||||
|
self.send_command(0x20) #vcom
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.EPD_4IN2_4Gray_lut_vcom[count])
|
||||||
|
|
||||||
|
self.send_command(0x21) #red not use
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.EPD_4IN2_4Gray_lut_ww[count])
|
||||||
|
|
||||||
|
self.send_command(0x22) #bw r
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.EPD_4IN2_4Gray_lut_bw[count])
|
||||||
|
|
||||||
|
self.send_command(0x23) #wb w
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.EPD_4IN2_4Gray_lut_wb[count])
|
||||||
|
|
||||||
|
self.send_command(0x24) #bb b
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.EPD_4IN2_4Gray_lut_bb[count])
|
||||||
|
|
||||||
|
self.send_command(0x25) #vcom
|
||||||
|
for count in range(0, 42):
|
||||||
|
self.send_data(self.EPD_4IN2_4Gray_lut_ww[count])
|
||||||
|
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
# EPD hardware init start
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01) # 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(0x06) # boost soft start
|
||||||
|
self.send_data(0x17)
|
||||||
|
self.send_data(0x17)
|
||||||
|
self.send_data(0x17)
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER_ON
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x00) # panel setting
|
||||||
|
self.send_data(0xbf) # KW-BF KWR-AF BWROTP 0f
|
||||||
|
self.send_data(0x0d)
|
||||||
|
|
||||||
|
self.send_command(0x30) # PLL setting
|
||||||
|
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 Init_4Gray(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
# EPD hardware init start
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01) #POWER SETTING
|
||||||
|
self.send_data (0x03)
|
||||||
|
self.send_data (0x00) #VGH=20V,VGL=-20V
|
||||||
|
self.send_data (0x2b) #VDH=15V
|
||||||
|
self.send_data (0x2b) #VDL=-15V
|
||||||
|
self.send_data (0x13)
|
||||||
|
|
||||||
|
self.send_command(0x06) #booster soft start
|
||||||
|
self.send_data (0x17) #A
|
||||||
|
self.send_data (0x17) #B
|
||||||
|
self.send_data (0x17) #C
|
||||||
|
|
||||||
|
self.send_command(0x04)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x00) #panel setting
|
||||||
|
self.send_data(0x3f) #KW-3f KWR-2F BWROTP 0f BWOTP 1f
|
||||||
|
|
||||||
|
self.send_command(0x30) #PLL setting
|
||||||
|
self.send_data (0x3c) #100hz
|
||||||
|
|
||||||
|
self.send_command(0x61) #resolution setting
|
||||||
|
self.send_data (0x01) #400
|
||||||
|
self.send_data (0x90)
|
||||||
|
self.send_data (0x01) #300
|
||||||
|
self.send_data (0x2c)
|
||||||
|
|
||||||
|
self.send_command(0x82) #vcom_DC setting
|
||||||
|
self.send_data (0x12)
|
||||||
|
|
||||||
|
self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING
|
||||||
|
self.send_data(0x97)
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
# logging.debug("bufsiz = ",int(self.width/8) * self.height)
|
||||||
|
buf = [0xFF] * (int(self.width/8) * self.height)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
logging.debug("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[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
logging.debug("Vertical")
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] == 0:
|
||||||
|
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def getbuffer_4Gray(self, image):
|
||||||
|
# logging.debug("bufsiz = ",int(self.width/8) * self.height)
|
||||||
|
buf = [0xFF] * (int(self.width / 4) * self.height)
|
||||||
|
image_monocolor = image.convert('L')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
i=0
|
||||||
|
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
logging.debug("Vertical")
|
||||||
|
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] == 0xC0):
|
||||||
|
pixels[x, y] = 0x80
|
||||||
|
elif (pixels[x, y] == 0x80):
|
||||||
|
pixels[x, y] = 0x40
|
||||||
|
i= i+1
|
||||||
|
if(i%4 == 0):
|
||||||
|
buf[int((x + (y * self.width))/4)] = ((pixels[x-3, y]&0xc0) | (pixels[x-2, y]&0xc0)>>2 | (pixels[x-1, y]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6)
|
||||||
|
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
logging.debug("Horizontal")
|
||||||
|
for x in range(imwidth):
|
||||||
|
for y in range(imheight):
|
||||||
|
newx = y
|
||||||
|
newy = x
|
||||||
|
if(pixels[x, y] == 0xC0):
|
||||||
|
pixels[x, y] = 0x80
|
||||||
|
elif (pixels[x, y] == 0x80):
|
||||||
|
pixels[x, y] = 0x40
|
||||||
|
i= i+1
|
||||||
|
if(i%4 == 0):
|
||||||
|
buf[int((newx + (newy * self.width))/4)] = ((pixels[x, y-3]&0xc0) | (pixels[x, y-2]&0xc0)>>2 | (pixels[x, y-1]&0xc0)>>4 | (pixels[x, y]&0xc0)>>6)
|
||||||
|
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, image):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0xFF)
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(image[i])
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def display_4Gray(self, image):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, EPD_WIDTH * EPD_HEIGHT / 8): # EPD_WIDTH * EPD_HEIGHT / 4
|
||||||
|
temp3=0
|
||||||
|
for j in range(0, 2):
|
||||||
|
temp1 = image[i*2+j]
|
||||||
|
for k in range(0, 2):
|
||||||
|
temp2 = temp1&0xC0
|
||||||
|
if(temp2 == 0xC0):
|
||||||
|
temp3 |= 0x01#white
|
||||||
|
elif(temp2 == 0x00):
|
||||||
|
temp3 |= 0x00 #black
|
||||||
|
elif(temp2 == 0x80):
|
||||||
|
temp3 |= 0x01 #gray1
|
||||||
|
else: #0x40
|
||||||
|
temp3 |= 0x00 #gray2
|
||||||
|
temp3 <<= 1
|
||||||
|
|
||||||
|
temp1 <<= 2
|
||||||
|
temp2 = temp1&0xC0
|
||||||
|
if(temp2 == 0xC0): #white
|
||||||
|
temp3 |= 0x01
|
||||||
|
elif(temp2 == 0x00): #black
|
||||||
|
temp3 |= 0x00
|
||||||
|
elif(temp2 == 0x80):
|
||||||
|
temp3 |= 0x01 #gray1
|
||||||
|
else : #0x40
|
||||||
|
temp3 |= 0x00 #gray2
|
||||||
|
if(j!=1 or k!=1):
|
||||||
|
temp3 <<= 1
|
||||||
|
temp1 <<= 2
|
||||||
|
self.send_data(temp3)
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
|
||||||
|
for i in range(0, EPD_WIDTH * EPD_HEIGHT / 8): #5808*4 46464
|
||||||
|
temp3=0
|
||||||
|
for j in range(0, 2):
|
||||||
|
temp1 = image[i*2+j]
|
||||||
|
for k in range(0, 2):
|
||||||
|
temp2 = temp1&0xC0
|
||||||
|
if(temp2 == 0xC0):
|
||||||
|
temp3 |= 0x01#white
|
||||||
|
elif(temp2 == 0x00):
|
||||||
|
temp3 |= 0x00 #black
|
||||||
|
elif(temp2 == 0x80):
|
||||||
|
temp3 |= 0x00 #gray1
|
||||||
|
else: #0x40
|
||||||
|
temp3 |= 0x01 #gray2
|
||||||
|
temp3 <<= 1
|
||||||
|
|
||||||
|
temp1 <<= 2
|
||||||
|
temp2 = temp1&0xC0
|
||||||
|
if(temp2 == 0xC0): #white
|
||||||
|
temp3 |= 0x01
|
||||||
|
elif(temp2 == 0x00): #black
|
||||||
|
temp3 |= 0x00
|
||||||
|
elif(temp2 == 0x80):
|
||||||
|
temp3 |= 0x00 #gray1
|
||||||
|
else: #0x40
|
||||||
|
temp3 |= 0x01 #gray2
|
||||||
|
if(j!=1 or k!=1):
|
||||||
|
temp3 <<= 1
|
||||||
|
temp1 <<= 2
|
||||||
|
self.send_data(temp3)
|
||||||
|
|
||||||
|
self.Gray_SetLut()
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
self.ReadBusy()
|
||||||
|
# pass
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0xFF)
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0xFF)
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0XA5)
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
|
||||||
|
### END OF FILE ###
|
||||||
|
|
148
modules/drivers/epd_4_in_2_colour.py
Normal file
148
modules/drivers/epd_4_in_2_colour.py
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd4in2bc.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 400
|
||||||
|
EPD_HEIGHT = 300
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
# Hardware reset
|
||||||
|
def reset(self):
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(10)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
logging.debug("e-Paper busy")
|
||||||
|
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
logging.debug("e-Paper busy release")
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x06) # BOOSTER_SOFT_START
|
||||||
|
self.send_data (0x17)
|
||||||
|
self.send_data (0x17)
|
||||||
|
self.send_data (0x17) # 07 0f 17 1f 27 2F 37 2f
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER_ON
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x00) # PANEL_SETTING
|
||||||
|
self.send_data(0x0F) # LUT from OTP
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
# logging.debug("bufsiz = ",int(self.width/8) * self.height)
|
||||||
|
buf = [0xFF] * (int(self.width/8) * self.height)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
logging.debug("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[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
logging.debug("Vertical")
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] == 0:
|
||||||
|
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, imageblack, imagered):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(imageblack[i])
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(imagered[i])
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0xFF)
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0xFF)
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0xA5) # check code
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
### END OF FILE ###
|
||||||
|
|
200
modules/drivers/epd_5_in_83.py
Normal file
200
modules/drivers/epd_5_in_83.py
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd5in83.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 600
|
||||||
|
EPD_HEIGHT = 448
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
# Hardware reset
|
||||||
|
def reset(self):
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(10)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
logging.debug("e-Paper busy")
|
||||||
|
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
logging.debug("e-Paper busy release")
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
# EPD hardware init start
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01) # POWER_SETTING
|
||||||
|
self.send_data(0x37)
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x00) # PANEL_SETTING
|
||||||
|
self.send_data(0xCF)
|
||||||
|
self.send_data(0x08)
|
||||||
|
|
||||||
|
self.send_command(0x06) # BOOSTER_SOFT_START
|
||||||
|
self.send_data(0xc7)
|
||||||
|
self.send_data(0xcc)
|
||||||
|
self.send_data(0x28)
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER_ON
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x30) # PLL_CONTROL
|
||||||
|
self.send_data(0x3c)
|
||||||
|
|
||||||
|
self.send_command(0x41) # TEMPERATURE_CALIBRATION
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING
|
||||||
|
self.send_data(0x77)
|
||||||
|
|
||||||
|
self.send_command(0x60) # TCON_SETTING
|
||||||
|
self.send_data(0x22)
|
||||||
|
|
||||||
|
self.send_command(0x61) # TCON_RESOLUTION
|
||||||
|
self.send_data(0x02) # source 600
|
||||||
|
self.send_data(0x58)
|
||||||
|
self.send_data(0x01) # gate 448
|
||||||
|
self.send_data(0xC0)
|
||||||
|
|
||||||
|
self.send_command(0x82) # VCM_DC_SETTING
|
||||||
|
self.send_data(0x1E) # decide by LUT file
|
||||||
|
|
||||||
|
self.send_command(0xe5) # FLASH MODE
|
||||||
|
self.send_data(0x03)
|
||||||
|
|
||||||
|
# EPD hardware init end
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
buf = [0x00] * int(self.width * self.height / 4)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
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] < 64: # black
|
||||||
|
buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2))
|
||||||
|
elif pixels[x, y] < 192: # convert gray to red
|
||||||
|
buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2))
|
||||||
|
buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2)
|
||||||
|
else: # white
|
||||||
|
buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2)
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] < 64: # black
|
||||||
|
buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2))
|
||||||
|
elif pixels[x, y] < 192: # convert gray to red
|
||||||
|
buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2))
|
||||||
|
buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2)
|
||||||
|
else: # white
|
||||||
|
buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, image):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 4 * self.height)):
|
||||||
|
temp1 = image[i]
|
||||||
|
j = 0
|
||||||
|
while (j < 4):
|
||||||
|
if ((temp1 & 0xC0) == 0xC0):
|
||||||
|
temp2 = 0x03
|
||||||
|
elif ((temp1 & 0xC0) == 0x00):
|
||||||
|
temp2 = 0x00
|
||||||
|
else:
|
||||||
|
temp2 = 0x04
|
||||||
|
temp2 = (temp2 << 4) & 0xFF
|
||||||
|
temp1 = (temp1 << 2) & 0xFF
|
||||||
|
j += 1
|
||||||
|
if((temp1 & 0xC0) == 0xC0):
|
||||||
|
temp2 |= 0x03
|
||||||
|
elif ((temp1 & 0xC0) == 0x00):
|
||||||
|
temp2 |= 0x00
|
||||||
|
else:
|
||||||
|
temp2 |= 0x04
|
||||||
|
temp1 = (temp1 << 2) & 0xFF
|
||||||
|
self.send_data(temp2)
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 4 * self.height)):
|
||||||
|
for j in range(0, 4):
|
||||||
|
self.send_data(0x33)
|
||||||
|
self.send_command(0x12)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0XA5)
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
|
||||||
|
### END OF FILE ###
|
||||||
|
|
200
modules/drivers/epd_5_in_83_colour.py
Normal file
200
modules/drivers/epd_5_in_83_colour.py
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd5in83b.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 600
|
||||||
|
EPD_HEIGHT = 448
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
# Hardware reset
|
||||||
|
def reset(self):
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(10)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
logging.debug("e-Paper busy")
|
||||||
|
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
logging.debug("e-Paper busy release")
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01) # POWER_SETTING
|
||||||
|
self.send_data(0x37)
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x00) # PANEL_SETTING
|
||||||
|
self.send_data(0xCF)
|
||||||
|
self.send_data(0x08)
|
||||||
|
|
||||||
|
self.send_command(0x30) # PLL_CONTROL
|
||||||
|
self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A
|
||||||
|
self.send_command(0X82) # VCOM VOLTAGE SETTING
|
||||||
|
self.send_data(0x28) # all temperature range
|
||||||
|
|
||||||
|
self.send_command(0x06) # boost
|
||||||
|
self.send_data(0xc7)
|
||||||
|
self.send_data(0xcc)
|
||||||
|
self.send_data(0x15)
|
||||||
|
|
||||||
|
self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING
|
||||||
|
self.send_data(0x77)
|
||||||
|
|
||||||
|
self.send_command(0X60) # TCON SETTING
|
||||||
|
self.send_data(0x22)
|
||||||
|
|
||||||
|
self.send_command(0X65) # FLASH CONTROL
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x61) # tres
|
||||||
|
self.send_data(0x02) # source 600
|
||||||
|
self.send_data(0x58)
|
||||||
|
self.send_data(0x01) # gate 448
|
||||||
|
self.send_data(0xc0)
|
||||||
|
|
||||||
|
self.send_command(0xe5) # FLASH MODE
|
||||||
|
self.send_data(0x03)
|
||||||
|
self.send_data(0x03)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
# logging.debug("bufsiz = ",int(self.width/8) * self.height)
|
||||||
|
buf = [0xFF] * (int(self.width/8) * self.height)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
logging.debug("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[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
logging.debug("Vertical")
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] == 0:
|
||||||
|
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, imageblack, imagered):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 8 * self.height)):
|
||||||
|
temp1 = imageblack[i]
|
||||||
|
temp2 = imagered[i]
|
||||||
|
j = 0
|
||||||
|
while (j < 8):
|
||||||
|
if ((temp2 & 0x80) == 0x00):
|
||||||
|
temp3 = 0x04 #red
|
||||||
|
elif ((temp1 & 0x80) == 0x00):
|
||||||
|
temp3 = 0x00 #black
|
||||||
|
else:
|
||||||
|
temp3 = 0x03 #white
|
||||||
|
|
||||||
|
temp3 = (temp3 << 4) & 0xFF
|
||||||
|
temp1 = (temp1 << 1) & 0xFF
|
||||||
|
temp2 = (temp2 << 1) & 0xFF
|
||||||
|
j += 1
|
||||||
|
if((temp2 & 0x80) == 0x00):
|
||||||
|
temp3 |= 0x04 #red
|
||||||
|
elif ((temp1 & 0x80) == 0x00):
|
||||||
|
temp3 |= 0x00 #black
|
||||||
|
else:
|
||||||
|
temp3 |= 0x03 #white
|
||||||
|
temp1 = (temp1 << 1) & 0xFF
|
||||||
|
temp2 = (temp2 << 1) & 0xFF
|
||||||
|
self.send_data(temp3)
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER ON
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x12) # display refresh
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 8 * self.height)):
|
||||||
|
self.send_data(0x33)
|
||||||
|
self.send_data(0x33)
|
||||||
|
self.send_data(0x33)
|
||||||
|
self.send_data(0x33)
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER ON
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x12) # display refresh
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0xA5) # check code
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
### END OF FILE ###
|
||||||
|
|
202
modules/drivers/epd_7_in_5.py
Normal file
202
modules/drivers/epd_7_in_5.py
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd7in5.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 640
|
||||||
|
EPD_HEIGHT = 384
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
# Hardware reset
|
||||||
|
def reset(self):
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(10)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
logging.debug("e-Paper busy")
|
||||||
|
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
logging.debug("e-Paper busy release")
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
# EPD hardware init start
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01) # POWER_SETTING
|
||||||
|
self.send_data(0x37)
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x00) # PANEL_SETTING
|
||||||
|
self.send_data(0xCF)
|
||||||
|
self.send_data(0x08)
|
||||||
|
|
||||||
|
self.send_command(0x06) # BOOSTER_SOFT_START
|
||||||
|
self.send_data(0xc7)
|
||||||
|
self.send_data(0xcc)
|
||||||
|
self.send_data(0x28)
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER_ON
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x30) # PLL_CONTROL
|
||||||
|
self.send_data(0x3c)
|
||||||
|
|
||||||
|
self.send_command(0x41) # TEMPERATURE_CALIBRATION
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x50) # VCOM_AND_DATA_INTERVAL_SETTING
|
||||||
|
self.send_data(0x77)
|
||||||
|
|
||||||
|
self.send_command(0x60) # TCON_SETTING
|
||||||
|
self.send_data(0x22)
|
||||||
|
|
||||||
|
self.send_command(0x61) # TCON_RESOLUTION
|
||||||
|
self.send_data(EPD_WIDTH >> 8) #source 640
|
||||||
|
self.send_data(EPD_WIDTH & 0xff)
|
||||||
|
self.send_data(EPD_HEIGHT >> 8) #gate 384
|
||||||
|
self.send_data(EPD_HEIGHT & 0xff)
|
||||||
|
|
||||||
|
self.send_command(0x82) # VCM_DC_SETTING
|
||||||
|
self.send_data(0x1E) # decide by LUT file
|
||||||
|
|
||||||
|
self.send_command(0xe5) # FLASH MODE
|
||||||
|
self.send_data(0x03)
|
||||||
|
|
||||||
|
# EPD hardware init end
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
logging.debug("1234")
|
||||||
|
buf = [0x00] * int(self.width * self.height / 4)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
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] < 64: # black
|
||||||
|
buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2))
|
||||||
|
elif pixels[x, y] < 192: # convert gray to red
|
||||||
|
buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2))
|
||||||
|
buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2)
|
||||||
|
else: # white
|
||||||
|
buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2)
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] < 64: # black
|
||||||
|
buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2))
|
||||||
|
elif pixels[x, y] < 192: # convert gray to red
|
||||||
|
buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2))
|
||||||
|
buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2)
|
||||||
|
else: # white
|
||||||
|
buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, image):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 4 * self.height)):
|
||||||
|
temp1 = image[i]
|
||||||
|
j = 0
|
||||||
|
while (j < 4):
|
||||||
|
if ((temp1 & 0xC0) == 0xC0):
|
||||||
|
temp2 = 0x03
|
||||||
|
elif ((temp1 & 0xC0) == 0x00):
|
||||||
|
temp2 = 0x00
|
||||||
|
else:
|
||||||
|
temp2 = 0x04
|
||||||
|
temp2 = (temp2 << 4) & 0xFF
|
||||||
|
temp1 = (temp1 << 2) & 0xFF
|
||||||
|
j += 1
|
||||||
|
if((temp1 & 0xC0) == 0xC0):
|
||||||
|
temp2 |= 0x03
|
||||||
|
elif ((temp1 & 0xC0) == 0x00):
|
||||||
|
temp2 |= 0x00
|
||||||
|
else:
|
||||||
|
temp2 |= 0x04
|
||||||
|
temp1 = (temp1 << 2) & 0xFF
|
||||||
|
self.send_data(temp2)
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 4 * self.height)):
|
||||||
|
for j in range(0, 4):
|
||||||
|
self.send_data(0x33)
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0XA5)
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
### END OF FILE ###
|
||||||
|
|
201
modules/drivers/epd_7_in_5_colour.py
Normal file
201
modules/drivers/epd_7_in_5_colour.py
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd7in5bc.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 640
|
||||||
|
EPD_HEIGHT = 384
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
# Hardware reset
|
||||||
|
def reset(self):
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(10)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
logging.debug("e-Paper busy")
|
||||||
|
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
logging.debug("e-Paper busy release")
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01) # POWER_SETTING
|
||||||
|
self.send_data(0x37)
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x00) # PANEL_SETTING
|
||||||
|
self.send_data(0xCF)
|
||||||
|
self.send_data(0x08)
|
||||||
|
|
||||||
|
self.send_command(0x30) # PLL_CONTROL
|
||||||
|
self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A
|
||||||
|
|
||||||
|
self.send_command(0x82) # VCM_DC_SETTING
|
||||||
|
self.send_data(0x28) #all temperature range
|
||||||
|
|
||||||
|
self.send_command(0x06) # BOOSTER_SOFT_START
|
||||||
|
self.send_data(0xc7)
|
||||||
|
self.send_data(0xcc)
|
||||||
|
self.send_data(0x15)
|
||||||
|
|
||||||
|
self.send_command(0x50) # VCOM AND DATA INTERVAL SETTING
|
||||||
|
self.send_data(0x77)
|
||||||
|
|
||||||
|
self.send_command(0x60) # TCON_SETTING
|
||||||
|
self.send_data(0x22)
|
||||||
|
|
||||||
|
self.send_command(0x65) # FLASH CONTROL
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x61) # TCON_RESOLUTION
|
||||||
|
self.send_data(self.width >> 8) # source 640
|
||||||
|
self.send_data(self.width & 0xff)
|
||||||
|
self.send_data(self.height >> 8) # gate 384
|
||||||
|
self.send_data(self.height & 0xff)
|
||||||
|
|
||||||
|
self.send_command(0xe5) # FLASH MODE
|
||||||
|
self.send_data(0x03)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
# logging.debug("bufsiz = ",int(self.width/8) * self.height)
|
||||||
|
buf = [0xFF] * (int(self.width/8) * self.height)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
logging.debug("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[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
logging.debug("Vertical")
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] == 0:
|
||||||
|
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, imageblack, imagered):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 8 * self.height)):
|
||||||
|
temp1 = imageblack[i]
|
||||||
|
temp2 = imagered[i]
|
||||||
|
j = 0
|
||||||
|
while (j < 8):
|
||||||
|
if ((temp2 & 0x80) == 0x00):
|
||||||
|
temp3 = 0x04 #red
|
||||||
|
elif ((temp1 & 0x80) == 0x00):
|
||||||
|
temp3 = 0x00 #black
|
||||||
|
else:
|
||||||
|
temp3 = 0x03 #white
|
||||||
|
|
||||||
|
temp3 = (temp3 << 4) & 0xFF
|
||||||
|
temp1 = (temp1 << 1) & 0xFF
|
||||||
|
temp2 = (temp2 << 1) & 0xFF
|
||||||
|
j += 1
|
||||||
|
if((temp2 & 0x80) == 0x00):
|
||||||
|
temp3 |= 0x04 #red
|
||||||
|
elif ((temp1 & 0x80) == 0x00):
|
||||||
|
temp3 |= 0x00 #black
|
||||||
|
else:
|
||||||
|
temp3 |= 0x03 #white
|
||||||
|
temp1 = (temp1 << 1) & 0xFF
|
||||||
|
temp2 = (temp2 << 1) & 0xFF
|
||||||
|
self.send_data(temp3)
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER ON
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x12) # display refresh
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width / 8 * self.height)):
|
||||||
|
self.send_data(0x33)
|
||||||
|
self.send_data(0x33)
|
||||||
|
self.send_data(0x33)
|
||||||
|
self.send_data(0x33)
|
||||||
|
|
||||||
|
self.send_command(0x04) # POWER ON
|
||||||
|
self.ReadBusy()
|
||||||
|
self.send_command(0x12) # display refresh
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0XA5)
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
### END OF FILE ###
|
||||||
|
|
170
modules/drivers/epd_7_in_5_v2.py
Normal file
170
modules/drivers/epd_7_in_5_v2.py
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd7in5.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 800
|
||||||
|
EPD_HEIGHT = 480
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
# Hardware reset
|
||||||
|
def reset(self):
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(2)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
logging.debug("e-Paper busy")
|
||||||
|
self.send_command(0x71)
|
||||||
|
busy = epdconfig.digital_read(self.busy_pin)
|
||||||
|
while(busy == 0):
|
||||||
|
self.send_command(0x71)
|
||||||
|
busy = epdconfig.digital_read(self.busy_pin)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
# EPD hardware init start
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01) #POWER SETTING
|
||||||
|
self.send_data(0x07)
|
||||||
|
self.send_data(0x07) #VGH=20V,VGL=-20V
|
||||||
|
self.send_data(0x3f) #VDH=15V
|
||||||
|
self.send_data(0x3f) #VDL=-15V
|
||||||
|
|
||||||
|
self.send_command(0x04) #POWER ON
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0X00) #PANNEL SETTING
|
||||||
|
self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f
|
||||||
|
|
||||||
|
self.send_command(0x61) #tres
|
||||||
|
self.send_data(0x03) #source 800
|
||||||
|
self.send_data(0x20)
|
||||||
|
self.send_data(0x01) #gate 480
|
||||||
|
self.send_data(0xE0)
|
||||||
|
|
||||||
|
self.send_command(0X15)
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING
|
||||||
|
self.send_data(0x10)
|
||||||
|
self.send_data(0x07)
|
||||||
|
|
||||||
|
self.send_command(0X60) #TCON SETTING
|
||||||
|
self.send_data(0x22)
|
||||||
|
|
||||||
|
# EPD hardware init end
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
# logging.debug("bufsiz = ",int(self.width/8) * self.height)
|
||||||
|
buf = [0xFF] * (int(self.width/8) * self.height)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
logging.debug("Vertical")
|
||||||
|
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[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
logging.debug("Horizontal")
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] == 0:
|
||||||
|
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, image):
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(~image[i]);
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0XA5)
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
### END OF FILE ###
|
||||||
|
|
173
modules/drivers/epd_7_in_5_v2_colour.py
Normal file
173
modules/drivers/epd_7_in_5_v2_colour.py
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
# *****************************************************************************
|
||||||
|
# * | File : epd7in5bc.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Electronic paper driver
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V4.0
|
||||||
|
# * | Date : 2019-06-20
|
||||||
|
# # | Info : python demo
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# 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 logging
|
||||||
|
from . import epdconfig
|
||||||
|
|
||||||
|
# Display resolution
|
||||||
|
EPD_WIDTH = 800
|
||||||
|
EPD_HEIGHT = 480
|
||||||
|
|
||||||
|
class EPD:
|
||||||
|
def __init__(self):
|
||||||
|
self.reset_pin = epdconfig.RST_PIN
|
||||||
|
self.dc_pin = epdconfig.DC_PIN
|
||||||
|
self.busy_pin = epdconfig.BUSY_PIN
|
||||||
|
self.cs_pin = epdconfig.CS_PIN
|
||||||
|
self.width = EPD_WIDTH
|
||||||
|
self.height = EPD_HEIGHT
|
||||||
|
|
||||||
|
# Hardware reset
|
||||||
|
def reset(self):
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 0)
|
||||||
|
epdconfig.delay_ms(4)
|
||||||
|
epdconfig.digital_write(self.reset_pin, 1)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def send_command(self, command):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 0)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([command])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def send_data(self, data):
|
||||||
|
epdconfig.digital_write(self.dc_pin, 1)
|
||||||
|
epdconfig.digital_write(self.cs_pin, 0)
|
||||||
|
epdconfig.spi_writebyte([data])
|
||||||
|
epdconfig.digital_write(self.cs_pin, 1)
|
||||||
|
|
||||||
|
def ReadBusy(self):
|
||||||
|
logging.debug("e-Paper busy")
|
||||||
|
self.send_command(0x71)
|
||||||
|
busy = epdconfig.digital_read(self.busy_pin)
|
||||||
|
while(busy == 0):
|
||||||
|
self.send_command(0x71)
|
||||||
|
busy = epdconfig.digital_read(self.busy_pin)
|
||||||
|
epdconfig.delay_ms(200)
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
if (epdconfig.module_init() != 0):
|
||||||
|
return -1
|
||||||
|
|
||||||
|
self.reset()
|
||||||
|
|
||||||
|
self.send_command(0x01); #POWER SETTING
|
||||||
|
self.send_data(0x07);
|
||||||
|
self.send_data(0x07); #VGH=20V,VGL=-20V
|
||||||
|
self.send_data(0x3f); #VDH=15V
|
||||||
|
self.send_data(0x3f); #VDL=-15V
|
||||||
|
|
||||||
|
self.send_command(0x04); #POWER ON
|
||||||
|
epdconfig.delay_ms(100);
|
||||||
|
self.ReadBusy();
|
||||||
|
|
||||||
|
self.send_command(0X00); #PANNEL SETTING
|
||||||
|
self.send_data(0x0F); #KW-3f KWR-2F BWROTP 0f BWOTP 1f
|
||||||
|
|
||||||
|
self.send_command(0x61); #tres
|
||||||
|
self.send_data(0x03); #source 800
|
||||||
|
self.send_data(0x20);
|
||||||
|
self.send_data(0x01); #gate 480
|
||||||
|
self.send_data(0xE0);
|
||||||
|
|
||||||
|
self.send_command(0X15);
|
||||||
|
self.send_data(0x00);
|
||||||
|
|
||||||
|
self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING
|
||||||
|
self.send_data(0x11);
|
||||||
|
self.send_data(0x07);
|
||||||
|
|
||||||
|
self.send_command(0X60); #TCON SETTING
|
||||||
|
self.send_data(0x22);
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def getbuffer(self, image):
|
||||||
|
# logging.debug("bufsiz = ",int(self.width/8) * self.height)
|
||||||
|
buf = [0xFF] * (int(self.width/8) * self.height)
|
||||||
|
image_monocolor = image.convert('1')
|
||||||
|
imwidth, imheight = image_monocolor.size
|
||||||
|
pixels = image_monocolor.load()
|
||||||
|
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight)
|
||||||
|
if(imwidth == self.width and imheight == self.height):
|
||||||
|
logging.debug("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[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
|
||||||
|
elif(imwidth == self.height and imheight == self.width):
|
||||||
|
logging.debug("Vertical")
|
||||||
|
for y in range(imheight):
|
||||||
|
for x in range(imwidth):
|
||||||
|
newx = y
|
||||||
|
newy = self.height - x - 1
|
||||||
|
if pixels[x, y] == 0:
|
||||||
|
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8))
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def display(self, imageblack, imagered):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(imageblack[i]);
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(~imagered[i]);
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def Clear(self):
|
||||||
|
self.send_command(0x10)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0xff)
|
||||||
|
|
||||||
|
self.send_command(0x13)
|
||||||
|
for i in range(0, int(self.width * self.height / 8)):
|
||||||
|
self.send_data(0x00)
|
||||||
|
|
||||||
|
self.send_command(0x12)
|
||||||
|
epdconfig.delay_ms(100)
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
def sleep(self):
|
||||||
|
self.send_command(0x02) # POWER_OFF
|
||||||
|
self.ReadBusy()
|
||||||
|
|
||||||
|
self.send_command(0x07) # DEEP_SLEEP
|
||||||
|
self.send_data(0XA5)
|
||||||
|
|
||||||
|
epdconfig.module_exit()
|
||||||
|
### END OF FILE ###
|
||||||
|
|
154
modules/drivers/epdconfig.py
Normal file
154
modules/drivers/epdconfig.py
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# /*****************************************************************************
|
||||||
|
# * | File : epdconfig.py
|
||||||
|
# * | Author : Waveshare team
|
||||||
|
# * | Function : Hardware underlying interface
|
||||||
|
# * | Info :
|
||||||
|
# *----------------
|
||||||
|
# * | This version: V1.0
|
||||||
|
# * | Date : 2019-06-21
|
||||||
|
# * | Info :
|
||||||
|
# ******************************************************************************
|
||||||
|
# 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 os
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
class RaspberryPi:
|
||||||
|
# Pin definition
|
||||||
|
RST_PIN = 17
|
||||||
|
DC_PIN = 25
|
||||||
|
CS_PIN = 8
|
||||||
|
BUSY_PIN = 24
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import spidev
|
||||||
|
import RPi.GPIO
|
||||||
|
|
||||||
|
self.GPIO = RPi.GPIO
|
||||||
|
|
||||||
|
# SPI device, bus = 0, device = 0
|
||||||
|
self.SPI = spidev.SpiDev(0, 0)
|
||||||
|
|
||||||
|
def digital_write(self, pin, value):
|
||||||
|
self.GPIO.output(pin, value)
|
||||||
|
|
||||||
|
def digital_read(self, pin):
|
||||||
|
return self.GPIO.input(pin)
|
||||||
|
|
||||||
|
def delay_ms(self, delaytime):
|
||||||
|
time.sleep(delaytime / 1000.0)
|
||||||
|
|
||||||
|
def spi_writebyte(self, data):
|
||||||
|
self.SPI.writebytes(data)
|
||||||
|
|
||||||
|
def module_init(self):
|
||||||
|
self.GPIO.setmode(self.GPIO.BCM)
|
||||||
|
self.GPIO.setwarnings(False)
|
||||||
|
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.CS_PIN, self.GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
|
||||||
|
self.SPI.max_speed_hz = 4000000
|
||||||
|
self.SPI.mode = 0b00
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def module_exit(self):
|
||||||
|
logging.debug("spi end")
|
||||||
|
#self.SPI.close() #removed as it causes some problems
|
||||||
|
|
||||||
|
logging.debug("close 5V, Module enters 0 power consumption ...")
|
||||||
|
self.GPIO.output(self.RST_PIN, 0)
|
||||||
|
self.GPIO.output(self.DC_PIN, 0)
|
||||||
|
|
||||||
|
self.GPIO.cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
class JetsonNano:
|
||||||
|
# Pin definition
|
||||||
|
RST_PIN = 17
|
||||||
|
DC_PIN = 25
|
||||||
|
CS_PIN = 8
|
||||||
|
BUSY_PIN = 24
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
import ctypes
|
||||||
|
find_dirs = [
|
||||||
|
os.path.dirname(os.path.realpath(__file__)),
|
||||||
|
'/usr/local/lib',
|
||||||
|
'/usr/lib',
|
||||||
|
]
|
||||||
|
self.SPI = None
|
||||||
|
for find_dir in find_dirs:
|
||||||
|
so_filename = os.path.join(find_dir, 'sysfs_software_spi.so')
|
||||||
|
if os.path.exists(so_filename):
|
||||||
|
self.SPI = ctypes.cdll.LoadLibrary(so_filename)
|
||||||
|
break
|
||||||
|
if self.SPI is None:
|
||||||
|
raise RuntimeError('Cannot find sysfs_software_spi.so')
|
||||||
|
|
||||||
|
import Jetson.GPIO
|
||||||
|
self.GPIO = Jetson.GPIO
|
||||||
|
|
||||||
|
def digital_write(self, pin, value):
|
||||||
|
self.GPIO.output(pin, value)
|
||||||
|
|
||||||
|
def digital_read(self, pin):
|
||||||
|
return self.GPIO.input(self.BUSY_PIN)
|
||||||
|
|
||||||
|
def delay_ms(self, delaytime):
|
||||||
|
time.sleep(delaytime / 1000.0)
|
||||||
|
|
||||||
|
def spi_writebyte(self, data):
|
||||||
|
self.SPI.SYSFS_software_spi_transfer(data[0])
|
||||||
|
|
||||||
|
def module_init(self):
|
||||||
|
self.GPIO.setmode(self.GPIO.BCM)
|
||||||
|
self.GPIO.setwarnings(False)
|
||||||
|
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.CS_PIN, self.GPIO.OUT)
|
||||||
|
self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
|
||||||
|
self.SPI.SYSFS_software_spi_begin()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def module_exit(self):
|
||||||
|
logging.debug("spi end")
|
||||||
|
self.SPI.SYSFS_software_spi_end()
|
||||||
|
|
||||||
|
logging.debug("close 5V, Module enters 0 power consumption ...")
|
||||||
|
self.GPIO.output(self.RST_PIN, 0)
|
||||||
|
self.GPIO.output(self.DC_PIN, 0)
|
||||||
|
|
||||||
|
self.GPIO.cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
|
||||||
|
implementation = RaspberryPi()
|
||||||
|
else:
|
||||||
|
implementation = JetsonNano()
|
||||||
|
|
||||||
|
for func in [x for x in dir(implementation) if not x.startswith('_')]:
|
||||||
|
setattr(sys.modules[__name__], func, getattr(implementation, func))
|
||||||
|
|
||||||
|
|
||||||
|
### END OF FILE ###
|
1
modules/drivers/init.py
Normal file
1
modules/drivers/init.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
#nothing in here. What did you expect?
|
@ -1,28 +1,22 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Main script of Inky-Calendar software.
|
v1.7.1
|
||||||
|
|
||||||
|
Main file of Inky-Calendar software. Creates dynamic images for each section,
|
||||||
|
assembles them and sends it to the E-Paper
|
||||||
|
|
||||||
Copyright by aceisace
|
Copyright by aceisace
|
||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from configuration import *
|
from configuration import *
|
||||||
from settings import *
|
|
||||||
import arrow
|
import arrow
|
||||||
from time import sleep
|
from time import sleep
|
||||||
import gc
|
import gc
|
||||||
import inkycal_drivers as drivers
|
|
||||||
|
|
||||||
import inkycal_rss as rss
|
|
||||||
import inkycal_weather as weather
|
|
||||||
import inkycal_calendar as calendar
|
|
||||||
import inkycal_agenda as agenda
|
|
||||||
|
|
||||||
|
|
||||||
display = drivers.EPD()
|
|
||||||
skip_calibration = False
|
|
||||||
|
|
||||||
"""Perepare for execution of main programm"""
|
"""Perepare for execution of main programm"""
|
||||||
calibration_countdown = 'initial'
|
calibration_countdown = 'initial'
|
||||||
|
skip_calibration = False
|
||||||
image_cleanup()
|
image_cleanup()
|
||||||
|
|
||||||
"""Check time and calibrate display if time """
|
"""Check time and calibrate display if time """
|
||||||
@ -36,8 +30,6 @@ while True:
|
|||||||
'D MMM YYYY'), now.format('HH:mm')))
|
'D MMM YYYY'), now.format('HH:mm')))
|
||||||
print('-----------Main programm started now----------')
|
print('-----------Main programm started now----------')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
"""------------------Calibration check----------------"""
|
"""------------------Calibration check----------------"""
|
||||||
if skip_calibration != True:
|
if skip_calibration != True:
|
||||||
print('Calibration..', end = ' ')
|
print('Calibration..', end = ' ')
|
||||||
@ -45,10 +37,10 @@ while True:
|
|||||||
if calibration_countdown == 'initial':
|
if calibration_countdown == 'initial':
|
||||||
print('required. Performing calibration now.')
|
print('required. Performing calibration now.')
|
||||||
calibration_countdown = 0
|
calibration_countdown = 0
|
||||||
display.calibrate_display(3)
|
calibrate_display(3)
|
||||||
else:
|
else:
|
||||||
if calibration_countdown % (60 // int(update_interval)) == 0:
|
if calibration_countdown % (60 // int(update_interval)) == 0:
|
||||||
display.calibrate_display(3)
|
calibrate_display(3)
|
||||||
calibration_countdown = 0
|
calibration_countdown = 0
|
||||||
else:
|
else:
|
||||||
print('not required. Continuing...')
|
print('not required. Continuing...')
|
||||||
@ -56,43 +48,50 @@ while True:
|
|||||||
print('Calibration skipped!. Please note that not calibrating e-paper',
|
print('Calibration skipped!. Please note that not calibrating e-paper',
|
||||||
'displays causes ghosting')
|
'displays causes ghosting')
|
||||||
|
|
||||||
|
|
||||||
"""----------------Generating and assembling images------"""
|
"""----------------Generating and assembling images------"""
|
||||||
if top_section == 'Weather':
|
try:
|
||||||
try:
|
top_section_module = importlib.import_module(top_section)
|
||||||
weather.main()
|
top_section_image = Image.open(image_path + top_section+'.png')
|
||||||
weather_image = Image.open(image_path + 'weather.png')
|
image.paste(top_section_image, (0, 0))
|
||||||
image.paste(weather_image, (0, 0))
|
except:
|
||||||
except:
|
pass
|
||||||
pass
|
|
||||||
|
|
||||||
if middle_section == 'Calendar':
|
try:
|
||||||
try:
|
middle_section_module = importlib.import_module(middle_section)
|
||||||
calendar.main()
|
middle_section_image = Image.open(image_path + middle_section+'.png')
|
||||||
calendar_image = Image.open(image_path + 'calendar.png')
|
image.paste(middle_section_image, (0, middle_section_offset))
|
||||||
image.paste(calendar_image, (0, middle_section_offset))
|
except:
|
||||||
except:
|
pass
|
||||||
pass
|
|
||||||
|
|
||||||
if middle_section == 'Agenda':
|
try:
|
||||||
try:
|
bottom_section_module = importlib.import_module(bottom_section)
|
||||||
agenda.main()
|
bottom_section_image = Image.open(image_path + bottom_section+'.png')
|
||||||
agenda_image = Image.open(image_path + 'agenda.png')
|
image.paste(bottom_section_image, (0, bottom_section_offset))
|
||||||
image.paste(agenda_image, (0, middle_section_offset))
|
except:
|
||||||
except:
|
pass
|
||||||
pass
|
|
||||||
|
|
||||||
if bottom_section == 'RSS':
|
|
||||||
try:
|
|
||||||
rss.main()
|
|
||||||
rss_image = Image.open(image_path + 'rss.png')
|
|
||||||
image.paste(rss_image, (0, bottom_section_offset))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
image.save(image_path + 'canvas.png')
|
image.save(image_path + 'canvas.png')
|
||||||
|
|
||||||
"""---------Refreshing E-Paper with newly created image-----------"""
|
"""---------Refreshing E-Paper with newly created image-----------"""
|
||||||
display.show_image(image, reduce_colours= True)
|
epaper = driver.EPD()
|
||||||
|
print('Initialising E-Paper...', end = '')
|
||||||
|
epaper.init()
|
||||||
|
print('Done')
|
||||||
|
|
||||||
|
if three_colour_support == True:
|
||||||
|
print('Sending image data and refreshing display...', end='')
|
||||||
|
black_im, red_im = split_colours(image)
|
||||||
|
epaper.display(epaper.getbuffer(black_im), epaper.getbuffer(red_im))
|
||||||
|
print('Done')
|
||||||
|
else:
|
||||||
|
print('Sending image data and refreshing display...', end='')
|
||||||
|
epaper.display(epaper.getbuffer(image.convert('1', dither=True)))
|
||||||
|
print('Done')
|
||||||
|
|
||||||
|
print('Sending E-Paper to deep sleep...', end = '')
|
||||||
|
epaper.sleep()
|
||||||
|
print('Done')
|
||||||
|
|
||||||
"""--------------Post processing after main loop-----------------"""
|
"""--------------Post processing after main loop-----------------"""
|
||||||
"""Collect some garbage to free up some resources"""
|
"""Collect some garbage to free up some resources"""
|
||||||
@ -106,12 +105,15 @@ while True:
|
|||||||
"""Calculate duration until next display refresh"""
|
"""Calculate duration until next display refresh"""
|
||||||
for _ in range(1):
|
for _ in range(1):
|
||||||
update_timings = [(60 - int(update_interval)*updates) for updates in
|
update_timings = [(60 - int(update_interval)*updates) for updates in
|
||||||
range(60//int(update_interval))]
|
range(60//int(update_interval))][::-1]
|
||||||
|
|
||||||
minutes = [i - now.minute for i in update_timings if i >= now.minute]
|
for _ in update_timings:
|
||||||
refresh_countdown = minutes[0]*60 + (60 - now.second)
|
if now.minute <= _:
|
||||||
|
minutes = _ - now.minute
|
||||||
|
break
|
||||||
|
|
||||||
print('{0} Minutes left until next refresh'.format(minutes[0]))
|
refresh_countdown = minutes*60 + (60 - now.second)
|
||||||
|
print('{0} Minutes left until next refresh'.format(minutes))
|
||||||
|
|
||||||
del update_timings, minutes, image
|
del update_timings, minutes, image
|
||||||
sleep(refresh_countdown)
|
sleep(refresh_countdown)
|
||||||
|
@ -7,8 +7,6 @@ Copyright by aceisace
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from inkycal_icalendar import fetch_events
|
from inkycal_icalendar import fetch_events
|
||||||
from configuration import*
|
from configuration import*
|
||||||
from settings import *
|
|
||||||
import arrow
|
|
||||||
|
|
||||||
fontsize = 14
|
fontsize = 14
|
||||||
show_events = True
|
show_events = True
|
||||||
@ -45,100 +43,103 @@ else:
|
|||||||
line_pos = [(border_left, int(top_section_height + border_top + line * line_height))
|
line_pos = [(border_left, int(top_section_height + border_top + line * line_height))
|
||||||
for line in range(max_lines)]
|
for line in range(max_lines)]
|
||||||
|
|
||||||
def main():
|
def generate_image():
|
||||||
try:
|
if middle_section == 'inkycal_agenda' and internet_available() == True:
|
||||||
clear_image('middle_section')
|
try:
|
||||||
if not bottom_section:
|
clear_image('middle_section')
|
||||||
clear_image('bottom_section')
|
if not bottom_section:
|
||||||
|
clear_image('bottom_section')
|
||||||
|
|
||||||
print('Agenda module: Generating image...', end = '')
|
print('Agenda module: Generating image...', end = '')
|
||||||
now = arrow.now(get_tz())
|
now = arrow.now(get_tz())
|
||||||
today_start = arrow.get(now.year, now.month, now.day)
|
today_start = arrow.get(now.year, now.month, now.day)
|
||||||
|
|
||||||
"""Create a list of dictionaries containing dates of the next days"""
|
"""Create a list of dictionaries containing dates of the next days"""
|
||||||
agenda_events = [{'date':today_start.replace(days=+_),
|
agenda_events = [{'date':today_start.replace(days=+_),
|
||||||
'date_str': now.replace(days=+_).format('ddd D MMM',locale=language),
|
'date_str': now.replace(days=+_).format('ddd D MMM',locale=language),
|
||||||
'type':'date'} for _ in range(max_lines)]
|
'type':'date'} for _ in range(max_lines)]
|
||||||
|
|
||||||
"""Copy the list from the icalendar module with some conditions"""
|
"""Copy the list from the icalendar module with some conditions"""
|
||||||
upcoming_events = fetch_events()
|
upcoming_events = fetch_events()
|
||||||
filtered_events = [events for events in upcoming_events if
|
filtered_events = [events for events in upcoming_events if
|
||||||
events.end > now]
|
events.end > now]
|
||||||
|
|
||||||
"""Set print_events_to True to print all events in this month"""
|
"""Set print_events_to True to print all events in this month"""
|
||||||
if print_events == True and filtered_events:
|
if print_events == True and filtered_events:
|
||||||
auto_line_width = max(len(_.name) for _ in filtered_events)
|
auto_line_width = max(len(_.name) for _ in filtered_events)
|
||||||
|
for events in filtered_events:
|
||||||
|
print('{0} {1} | {2} | {3} | All day ='.format(events.name,
|
||||||
|
' '* (auto_line_width - len(events.name)), events.begin.format(style),
|
||||||
|
events.end.format(style)), events.all_day)
|
||||||
|
|
||||||
|
"""Convert the event-timings from utc to the specified locale's time
|
||||||
|
and create a ready-to-display list for the agenda view"""
|
||||||
for events in filtered_events:
|
for events in filtered_events:
|
||||||
print('{0} {1} | {2} | {3} | All day ='.format(events.name,
|
if not events.all_day:
|
||||||
' '* (auto_line_width - len(events.name)), events.begin.format(style),
|
agenda_events.append({'date': events.begin, 'time': events.begin.format(
|
||||||
events.end.format(style)), events.all_day)
|
'HH:mm' if hours == '24' else 'hh:mm a'), 'name':str(events.name),
|
||||||
|
'type':'timed_event'})
|
||||||
|
else:
|
||||||
|
if events.duration.days == 1:
|
||||||
|
agenda_events.append({'date': events.begin,'time': all_day_str,
|
||||||
|
'name': events.name,'type':'full_day_event'})
|
||||||
|
else:
|
||||||
|
for day in range(events.duration.days):
|
||||||
|
agenda_events.append({'date': events.begin.replace(days=+day),
|
||||||
|
'time': all_day_str,'name':events.name, 'type':'full_day_event'})
|
||||||
|
|
||||||
"""Convert the event-timings from utc to the specified locale's time
|
"""Sort events and dates in chronological order"""
|
||||||
and create a ready-to-display list for the agenda view"""
|
agenda_events = sorted(agenda_events, key = lambda event: event['date'])
|
||||||
for events in filtered_events:
|
|
||||||
if not events.all_day:
|
"""Crop the agenda_events in case it's too long"""
|
||||||
agenda_events.append({'date': events.begin, 'time': events.begin.format(
|
del agenda_events[max_lines:]
|
||||||
'HH:mm' if hours == '24' else 'hh:mm a'), 'name':str(events.name),
|
|
||||||
'type':'timed_event'})
|
"""Display all events, dates and times on the display"""
|
||||||
|
if show_events == True:
|
||||||
|
previous_date = None
|
||||||
|
for events in range(len(agenda_events)):
|
||||||
|
if agenda_events[events]['type'] == 'date':
|
||||||
|
if previous_date == None or previous_date != agenda_events[events][
|
||||||
|
'date']:
|
||||||
|
write_text(date_col_width, line_height,
|
||||||
|
agenda_events[events]['date_str'], line_pos[events], font = font)
|
||||||
|
|
||||||
|
previous_date = agenda_events[events]['date']
|
||||||
|
draw.line((date_col_start, line_pos[events][1],
|
||||||
|
line_width,line_pos[events][1]), fill = 'red' if three_colour_support == True' else 'black')
|
||||||
|
|
||||||
|
elif agenda_events[events]['type'] == 'timed_event':
|
||||||
|
write_text(time_col_width, line_height, agenda_events[events]['time'],
|
||||||
|
(time_col_start, line_pos[events][1]), font = font)
|
||||||
|
|
||||||
|
write_text(event_col_width, line_height, ('• '+agenda_events[events][
|
||||||
|
'name']), (event_col_start, line_pos[events][1]),
|
||||||
|
alignment = 'left', font = font)
|
||||||
|
|
||||||
|
else:
|
||||||
|
write_text(time_col_width, line_height, agenda_events[events]['time'],
|
||||||
|
(time_col_start, line_pos[events][1]), font = font)
|
||||||
|
|
||||||
|
write_text(event_col_width, line_height, ('• '+agenda_events[events]['name']),
|
||||||
|
(event_col_start, line_pos[events][1]), alignment = 'left', font = font)
|
||||||
|
|
||||||
|
"""Crop the image to show only the middle section"""
|
||||||
|
if bottom_section:
|
||||||
|
agenda_image = crop_image(image, 'middle_section')
|
||||||
else:
|
else:
|
||||||
if events.duration.days == 1:
|
agenda_image = image.crop((0,middle_section_offset,display_width, display_height))
|
||||||
agenda_events.append({'date': events.begin,'time': all_day_str,
|
|
||||||
'name': events.name,'type':'full_day_event'})
|
|
||||||
else:
|
|
||||||
for day in range(events.duration.days):
|
|
||||||
agenda_events.append({'date': events.begin.replace(days=+day),
|
|
||||||
'time': all_day_str,'name':events.name, 'type':'full_day_event'})
|
|
||||||
|
|
||||||
"""Sort events and dates in chronological order"""
|
agenda_image.save(image_path+'inkycal_agenda.png')
|
||||||
agenda_events = sorted(agenda_events, key = lambda event: event['date'])
|
print('Done')
|
||||||
|
|
||||||
"""Crop the agenda_events in case it's too long"""
|
except Exception as e:
|
||||||
del agenda_events[max_lines:]
|
"""If something went wrong, print a Error message on the Terminal"""
|
||||||
|
print('Failed!')
|
||||||
|
print('Error in Agenda module!')
|
||||||
|
print('Reason: ',e)
|
||||||
|
pass
|
||||||
|
|
||||||
"""Display all events, dates and times on the display"""
|
def main():
|
||||||
if show_events == True:
|
generate_image()
|
||||||
previous_date = None
|
|
||||||
for events in range(len(agenda_events)):
|
|
||||||
if agenda_events[events]['type'] == 'date':
|
|
||||||
if previous_date == None or previous_date != agenda_events[events][
|
|
||||||
'date']:
|
|
||||||
write_text(date_col_width, line_height,
|
|
||||||
agenda_events[events]['date_str'], line_pos[events], font = font)
|
|
||||||
|
|
||||||
previous_date = agenda_events[events]['date']
|
main()
|
||||||
draw.line((date_col_start, line_pos[events][1],
|
|
||||||
line_width,line_pos[events][1]), fill = 'red' if display_type == 'colour' else 'black')
|
|
||||||
|
|
||||||
elif agenda_events[events]['type'] == 'timed_event':
|
|
||||||
write_text(time_col_width, line_height, agenda_events[events]['time'],
|
|
||||||
(time_col_start, line_pos[events][1]), font = font)
|
|
||||||
|
|
||||||
write_text(event_col_width, line_height, ('• '+agenda_events[events][
|
|
||||||
'name']), (event_col_start, line_pos[events][1]),
|
|
||||||
alignment = 'left', font = font)
|
|
||||||
|
|
||||||
else:
|
|
||||||
write_text(time_col_width, line_height, agenda_events[events]['time'],
|
|
||||||
(time_col_start, line_pos[events][1]), font = font)
|
|
||||||
|
|
||||||
write_text(event_col_width, line_height, ('• '+agenda_events[events]['name']),
|
|
||||||
(event_col_start, line_pos[events][1]), alignment = 'left', font = font)
|
|
||||||
|
|
||||||
"""Crop the image to show only the middle section"""
|
|
||||||
if bottom_section:
|
|
||||||
agenda_image = crop_image(image, 'middle_section')
|
|
||||||
else:
|
|
||||||
agenda_image = image.crop((0,middle_section_offset,display_width, display_height))
|
|
||||||
|
|
||||||
agenda_image.save(image_path+'agenda.png')
|
|
||||||
print('Done')
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
"""If something went wrong, print a Error message on the Terminal"""
|
|
||||||
print('Failed!')
|
|
||||||
print('Error in Agenda module!')
|
|
||||||
print('Reason: ',e)
|
|
||||||
pass
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
@ -7,9 +7,6 @@ Copyright by aceisace
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import calendar
|
import calendar
|
||||||
from configuration import *
|
from configuration import *
|
||||||
from settings import *
|
|
||||||
import arrow
|
|
||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
print_events = False
|
print_events = False
|
||||||
show_events = True
|
show_events = True
|
||||||
@ -68,147 +65,149 @@ max_event_lines = (events_height - border_top) // (font.getsize('hg')[1]
|
|||||||
event_lines = [(border_left,(bottom_section_offset - events_height)+
|
event_lines = [(border_left,(bottom_section_offset - events_height)+
|
||||||
int(events_height/max_event_lines*_)) for _ in range(max_event_lines)]
|
int(events_height/max_event_lines*_)) for _ in range(max_event_lines)]
|
||||||
|
|
||||||
|
def generate_image():
|
||||||
|
if middle_section == "inkycal_calendar" and internet_available() == True:
|
||||||
|
try:
|
||||||
|
clear_image('middle_section')
|
||||||
|
print('Calendar module: Generating image...', end = '')
|
||||||
|
now = arrow.now(tz = get_tz())
|
||||||
|
|
||||||
|
"""Set up the Calendar template based on personal preferences"""
|
||||||
|
if week_starts_on == "Monday":
|
||||||
|
calendar.setfirstweekday(calendar.MONDAY)
|
||||||
|
weekstart = now.replace(days = - now.weekday())
|
||||||
|
else:
|
||||||
|
calendar.setfirstweekday(calendar.SUNDAY)
|
||||||
|
weekstart = now.replace(days = - now.isoweekday())
|
||||||
|
|
||||||
|
"""Write the name of the current month at the correct position"""
|
||||||
|
write_text(main_area_width, month_name_height,
|
||||||
|
str(now.format('MMMM',locale=language)), (border_left,
|
||||||
|
middle_section_offset), autofit = True)
|
||||||
|
|
||||||
|
"""Set up weeknames in local language and add to main section"""
|
||||||
|
weekday_names = [weekstart.replace(days=+_).format('ddd',locale=language)
|
||||||
|
for _ in range(7)]
|
||||||
|
|
||||||
|
for _ in range(len(weekday_pos)):
|
||||||
|
write_text(icon_width, weekdays_height, weekday_names[_],
|
||||||
|
weekday_pos[_], autofit = True)
|
||||||
|
|
||||||
|
"""Create a calendar template and flatten (remove nestings)"""
|
||||||
|
flatten = lambda z: [x for y in z for x in y]
|
||||||
|
calendar_flat = flatten(calendar.monthcalendar(now.year, now.month))
|
||||||
|
|
||||||
|
"""Add the numbers on the correct positions"""
|
||||||
|
for i in range(len(calendar_flat)):
|
||||||
|
if calendar_flat[i] != 0:
|
||||||
|
write_text(icon_width, icon_height, str(calendar_flat[i]), grid[i])
|
||||||
|
|
||||||
|
"""Draw a red/black circle with the current day of month in white"""
|
||||||
|
icon = Image.new('RGBA', (icon_width, icon_height))
|
||||||
|
current_day_pos = grid[calendar_flat.index(now.day)]
|
||||||
|
x_circle,y_circle = int(icon_width/2), int(icon_height/2)
|
||||||
|
radius = int(icon_width * 0.25)
|
||||||
|
text_width, text_height = default.getsize(str(now.day))
|
||||||
|
x_text = int((icon_width / 2) - (text_width / 2))
|
||||||
|
y_text = int((icon_height / 2) - (text_height / 1.7))
|
||||||
|
ImageDraw.Draw(icon).ellipse((x_circle-radius, y_circle-radius,
|
||||||
|
x_circle+radius, y_circle+radius), fill= 'red' if
|
||||||
|
three_colour_support == True else 'black', outline=None)
|
||||||
|
ImageDraw.Draw(icon).text((x_text, y_text), str(now.day), fill='white',
|
||||||
|
font=bold)
|
||||||
|
image.paste(icon, current_day_pos, icon)
|
||||||
|
|
||||||
|
"""Create some reference points for the current month"""
|
||||||
|
days_current_month = calendar.monthrange(now.year, now.month)[1]
|
||||||
|
month_start = now.floor('month')
|
||||||
|
month_end = now.ceil('month')
|
||||||
|
|
||||||
|
if show_events == True:
|
||||||
|
"""Filter events which begin before the end of this month"""
|
||||||
|
upcoming_events = fetch_events()
|
||||||
|
|
||||||
|
calendar_events = [events for events in upcoming_events if
|
||||||
|
month_start <= events.end <= month_end ]
|
||||||
|
|
||||||
|
"""Find days with events in the current month"""
|
||||||
|
days_with_events = []
|
||||||
|
for events in calendar_events:
|
||||||
|
if events.duration.days <= 1:
|
||||||
|
days_with_events.append(int(events.begin.format('D')))
|
||||||
|
else:
|
||||||
|
for day in range(events.duration.days):
|
||||||
|
days_with_events.append(
|
||||||
|
int(events.begin.replace(days=+i).format('D')))
|
||||||
|
days_with_events = set(days_with_events)
|
||||||
|
|
||||||
|
if event_icon == 'dot':
|
||||||
|
for days in days_with_events:
|
||||||
|
write_text(icon_width, int(icon_height * 0.2), '•',
|
||||||
|
(grid[calendar_flat.index(days)][0],
|
||||||
|
int(grid[calendar_flat.index(days)][1] + icon_height*0.8)))
|
||||||
|
|
||||||
|
if event_icon == 'square':
|
||||||
|
square_size = int(icon_width * 0.6)
|
||||||
|
center_x = int((icon_width - square_size) / 2)
|
||||||
|
center_y = int((icon_height - square_size) / 2)
|
||||||
|
for days in days_with_events:
|
||||||
|
draw_square((int(grid[calendar_flat.index(days)][0]+center_x),
|
||||||
|
int(grid[calendar_flat.index(days)][1] + center_y )),
|
||||||
|
8, square_size , square_size)
|
||||||
|
|
||||||
|
|
||||||
|
"""Add a small section showing events of today and tomorrow"""
|
||||||
|
event_list = ['{0} {1} {2} : {3}'.format(today_in_your_language,
|
||||||
|
at_in_your_language, event.begin.format('HH:mm' if hours == 24 else
|
||||||
|
'hh:mm'), event.name) for event in calendar_events if event.begin.day
|
||||||
|
== now.day and now < event.end]
|
||||||
|
|
||||||
|
event_list += ['{0} {1} {2} : {3}'.format(tomorrow_in_your_language,
|
||||||
|
at_in_your_language, event.begin.format('HH:mm' if hours == 24 else
|
||||||
|
'hh:mm'), event.name) for event in calendar_events if event.begin.day
|
||||||
|
== now.replace(days=1).day]
|
||||||
|
|
||||||
|
after_two_days = now.replace(days=2).floor('day')
|
||||||
|
|
||||||
|
event_list += ['{0} {1} {2} : {3}'.format(event.begin.format('D MMM'),
|
||||||
|
at_in_your_language, event.begin.format('HH:mm' if hours == 24 else
|
||||||
|
'hh:mm'), event.name) for event in upcoming_events if event.end >
|
||||||
|
after_two_days]
|
||||||
|
|
||||||
|
del event_list[max_event_lines:]
|
||||||
|
|
||||||
|
if event_list:
|
||||||
|
for lines in event_list:
|
||||||
|
write_text(main_area_width, int(events_height/max_event_lines), lines,
|
||||||
|
event_lines[event_list.index(lines)], alignment='left',
|
||||||
|
fill_height = 0.7)
|
||||||
|
else:
|
||||||
|
write_text(main_area_width, int(events_height/max_event_lines),
|
||||||
|
'No upcoming events.', event_lines[0], alignment='left',
|
||||||
|
fill_height = 0.7)
|
||||||
|
|
||||||
|
"""Set print_events_to True to print all events in this month"""
|
||||||
|
style = 'DD MMM YY HH:mm'
|
||||||
|
if print_events == True and calendar_events:
|
||||||
|
line_width = max(len(_.name) for _ in calendar_events)
|
||||||
|
for events in calendar_events:
|
||||||
|
print('{0} {1} | {2} | {3} | All day ='.format(events.name,
|
||||||
|
' ' * (line_width - len(events.name)), events.begin.format(style),
|
||||||
|
events.end.format(style)), events.all_day)
|
||||||
|
|
||||||
|
calendar_image = crop_image(image, 'middle_section')
|
||||||
|
calendar_image.save(image_path+'inkycal_calendar.png')
|
||||||
|
|
||||||
|
print('Done')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
"""If something went wrong, print a Error message on the Terminal"""
|
||||||
|
print('Failed!')
|
||||||
|
print('Error in Calendar module!')
|
||||||
|
print('Reason: ',e)
|
||||||
|
pass
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
generate_image()
|
||||||
clear_image('middle_section')
|
|
||||||
print('Calendar module: Generating image...', end = '')
|
|
||||||
now = arrow.now(tz = get_tz())
|
|
||||||
|
|
||||||
"""Set up the Calendar template based on personal preferences"""
|
main()
|
||||||
if week_starts_on == "Monday":
|
|
||||||
calendar.setfirstweekday(calendar.MONDAY)
|
|
||||||
weekstart = now.replace(days = - now.weekday())
|
|
||||||
else:
|
|
||||||
calendar.setfirstweekday(calendar.SUNDAY)
|
|
||||||
weekstart = now.replace(days = - now.isoweekday())
|
|
||||||
|
|
||||||
"""Write the name of the current month at the correct position"""
|
|
||||||
write_text(main_area_width, month_name_height,
|
|
||||||
str(now.format('MMMM',locale=language)), (border_left,
|
|
||||||
middle_section_offset), autofit = True)
|
|
||||||
|
|
||||||
"""Set up weeknames in local language and add to main section"""
|
|
||||||
weekday_names = [weekstart.replace(days=+_).format('ddd',locale=language)
|
|
||||||
for _ in range(7)]
|
|
||||||
|
|
||||||
for _ in range(len(weekday_pos)):
|
|
||||||
write_text(icon_width, weekdays_height, weekday_names[_],
|
|
||||||
weekday_pos[_], autofit = True)
|
|
||||||
|
|
||||||
"""Create a calendar template and flatten (remove nestings)"""
|
|
||||||
flatten = lambda z: [x for y in z for x in y]
|
|
||||||
calendar_flat = flatten(calendar.monthcalendar(now.year, now.month))
|
|
||||||
|
|
||||||
"""Add the numbers on the correct positions"""
|
|
||||||
for i in range(len(calendar_flat)):
|
|
||||||
if calendar_flat[i] != 0:
|
|
||||||
write_text(icon_width, icon_height, str(calendar_flat[i]), grid[i])
|
|
||||||
|
|
||||||
"""Draw a red/black circle with the current day of month in white"""
|
|
||||||
icon = Image.new('RGBA', (icon_width, icon_height))
|
|
||||||
current_day_pos = grid[calendar_flat.index(now.day)]
|
|
||||||
x_circle,y_circle = int(icon_width/2), int(icon_height/2)
|
|
||||||
radius = int(icon_width * 0.25)
|
|
||||||
text_width, text_height = default.getsize(str(now.day))
|
|
||||||
x_text = int((icon_width / 2) - (text_width / 2))
|
|
||||||
y_text = int((icon_height / 2) - (text_height / 1.7))
|
|
||||||
ImageDraw.Draw(icon).ellipse((x_circle-radius, y_circle-radius,
|
|
||||||
x_circle+radius, y_circle+radius), fill= 'red' if
|
|
||||||
display_type == 'colour' else 'black', outline=None)
|
|
||||||
ImageDraw.Draw(icon).text((x_text, y_text), str(now.day), fill='white',
|
|
||||||
font=bold)
|
|
||||||
image.paste(icon, current_day_pos, icon)
|
|
||||||
|
|
||||||
"""Create some reference points for the current month"""
|
|
||||||
days_current_month = calendar.monthrange(now.year, now.month)[1]
|
|
||||||
month_start = now.floor('month')
|
|
||||||
month_end = now.ceil('month')
|
|
||||||
|
|
||||||
if show_events == True:
|
|
||||||
"""Filter events which begin before the end of this month"""
|
|
||||||
upcoming_events = fetch_events()
|
|
||||||
|
|
||||||
calendar_events = [events for events in upcoming_events if
|
|
||||||
month_start <= events.end <= month_end ]
|
|
||||||
|
|
||||||
"""Find days with events in the current month"""
|
|
||||||
days_with_events = []
|
|
||||||
for events in calendar_events:
|
|
||||||
if events.duration.days <= 1:
|
|
||||||
days_with_events.append(int(events.begin.format('D')))
|
|
||||||
else:
|
|
||||||
for day in range(events.duration.days):
|
|
||||||
days_with_events.append(
|
|
||||||
int(events.begin.replace(days=+i).format('D')))
|
|
||||||
days_with_events = set(days_with_events)
|
|
||||||
|
|
||||||
if event_icon == 'dot':
|
|
||||||
for days in days_with_events:
|
|
||||||
write_text(icon_width, int(icon_height * 0.2), '•',
|
|
||||||
(grid[calendar_flat.index(days)][0],
|
|
||||||
int(grid[calendar_flat.index(days)][1] + icon_height*0.8)))
|
|
||||||
|
|
||||||
if event_icon == 'square':
|
|
||||||
square_size = int(icon_width *0.6)
|
|
||||||
center_x = int((icon_width - square_size) / 2)
|
|
||||||
center_y = int((icon_height - square_size) / 2)
|
|
||||||
for days in days_with_events:
|
|
||||||
draw_square((int(grid[calendar_flat.index(days)][0]+center_x),
|
|
||||||
int(grid[calendar_flat.index(days)][1] + center_y )),
|
|
||||||
8, square_size , square_size)
|
|
||||||
|
|
||||||
|
|
||||||
"""Add a small section showing events of today and tomorrow"""
|
|
||||||
event_list = ['{0} {1} {2} : {3}'.format(today_in_your_language,
|
|
||||||
at_in_your_language, event.begin.format('HH:mm' if hours == 24 else
|
|
||||||
'hh:mm'), event.name) for event in calendar_events if event.begin.day
|
|
||||||
== now.day and now < event.end]
|
|
||||||
|
|
||||||
event_list += ['{0} {1} {2} : {3}'.format(tomorrow_in_your_language,
|
|
||||||
at_in_your_language, event.begin.format('HH:mm' if hours == 24 else
|
|
||||||
'hh:mm'), event.name) for event in calendar_events if event.begin.day
|
|
||||||
== now.replace(days=1).day]
|
|
||||||
|
|
||||||
after_two_days = now.replace(days=2).floor('day')
|
|
||||||
|
|
||||||
event_list += ['{0} {1} {2} : {3}'.format(event.begin.format('D MMM'),
|
|
||||||
at_in_your_language, event.begin.format('HH:mm' if hours == 24 else
|
|
||||||
'hh:mm'), event.name) for event in upcoming_events if event.end >
|
|
||||||
after_two_days]
|
|
||||||
|
|
||||||
del event_list[max_event_lines:]
|
|
||||||
|
|
||||||
if event_list:
|
|
||||||
for lines in event_list:
|
|
||||||
write_text(main_area_width, int(events_height/max_event_lines), lines,
|
|
||||||
event_lines[event_list.index(lines)], alignment='left',
|
|
||||||
fill_height = 0.7)
|
|
||||||
else:
|
|
||||||
write_text(main_area_width, int(events_height/max_event_lines),
|
|
||||||
'No upcoming events.', event_lines[0], alignment='left',
|
|
||||||
fill_height = 0.7)
|
|
||||||
|
|
||||||
"""Set print_events_to True to print all events in this month"""
|
|
||||||
style = 'DD MMM YY HH:mm'
|
|
||||||
if print_events == True and calendar_events:
|
|
||||||
line_width = max(len(_.name) for _ in calendar_events)
|
|
||||||
for events in calendar_events:
|
|
||||||
print('{0} {1} | {2} | {3} | All day ='.format(events.name,
|
|
||||||
' ' * (line_width - len(events.name)), events.begin.format(style),
|
|
||||||
events.end.format(style)), events.all_day)
|
|
||||||
|
|
||||||
calendar_image = crop_image(image, 'middle_section')
|
|
||||||
calendar_image.save(image_path+'calendar.png')
|
|
||||||
|
|
||||||
print('Done')
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
"""If something went wrong, print a Error message on the Terminal"""
|
|
||||||
print('Failed!')
|
|
||||||
print('Error in Calendar module!')
|
|
||||||
print('Reason: ',e)
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
|
@ -1,344 +0,0 @@
|
|||||||
#!/usr/bin/python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
Drivers file for Inky-Calendar software.
|
|
||||||
Handles E-Paper display related tasks
|
|
||||||
"""
|
|
||||||
|
|
||||||
from PIL import Image
|
|
||||||
import RPi.GPIO as GPIO
|
|
||||||
from settings import display_type
|
|
||||||
import numpy
|
|
||||||
import spidev
|
|
||||||
import RPi.GPIO as GPIO
|
|
||||||
from time import sleep
|
|
||||||
|
|
||||||
RST_PIN = 17
|
|
||||||
DC_PIN = 25
|
|
||||||
CS_PIN = 8
|
|
||||||
BUSY_PIN = 24
|
|
||||||
|
|
||||||
EPD_WIDTH = 640
|
|
||||||
EPD_HEIGHT = 384
|
|
||||||
|
|
||||||
SPI = spidev.SpiDev(0, 0)
|
|
||||||
|
|
||||||
def epd_digital_write(pin, value):
|
|
||||||
GPIO.output(pin, value)
|
|
||||||
|
|
||||||
def epd_digital_read(pin):
|
|
||||||
return GPIO.input(BUSY_PIN)
|
|
||||||
|
|
||||||
def epd_delay_ms(delaytime):
|
|
||||||
sleep(delaytime / 1000.0)
|
|
||||||
|
|
||||||
def spi_transfer(data):
|
|
||||||
SPI.writebytes(data)
|
|
||||||
|
|
||||||
def epd_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 = 4000000
|
|
||||||
SPI.mode = 0b00
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
# EPD7IN5 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
|
|
||||||
IMAGE_PROCESS = 0x13
|
|
||||||
LUT_FOR_VCOM = 0x20
|
|
||||||
LUT_BLUE = 0x21
|
|
||||||
LUT_WHITE = 0x22
|
|
||||||
LUT_GRAY_1 = 0x23
|
|
||||||
LUT_GRAY_2 = 0x24
|
|
||||||
LUT_RED_0 = 0x25
|
|
||||||
LUT_RED_1 = 0x26
|
|
||||||
LUT_RED_2 = 0x27
|
|
||||||
LUT_RED_3 = 0x28
|
|
||||||
LUT_XON = 0x29
|
|
||||||
PLL_CONTROL = 0x30
|
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40
|
|
||||||
TEMPERATURE_CALIBRATION = 0x41
|
|
||||||
TEMPERATURE_SENSOR_WRITE = 0x42
|
|
||||||
TEMPERATURE_SENSOR_READ = 0x43
|
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50
|
|
||||||
LOW_POWER_DETECTION = 0x51
|
|
||||||
TCON_SETTING = 0x60
|
|
||||||
TCON_RESOLUTION = 0x61
|
|
||||||
SPI_FLASH_CONTROL = 0x65
|
|
||||||
REVISION = 0x70
|
|
||||||
GET_STATUS = 0x71
|
|
||||||
AUTO_MEASUREMENT_VCOM = 0x80
|
|
||||||
READ_VCOM_VALUE = 0x81
|
|
||||||
VCM_DC_SETTING = 0x82
|
|
||||||
|
|
||||||
class EPD:
|
|
||||||
def __init__(self):
|
|
||||||
self.reset_pin = RST_PIN
|
|
||||||
self.dc_pin = DC_PIN
|
|
||||||
self.busy_pin = BUSY_PIN
|
|
||||||
self.width = EPD_WIDTH
|
|
||||||
self.height = EPD_HEIGHT
|
|
||||||
|
|
||||||
def digital_write(self, pin, value):
|
|
||||||
epd_digital_write(pin, value)
|
|
||||||
|
|
||||||
def digital_read(self, pin):
|
|
||||||
return epd_digital_read(pin)
|
|
||||||
|
|
||||||
def delay_ms(self, delaytime):
|
|
||||||
epd_delay_ms(delaytime)
|
|
||||||
|
|
||||||
def send_command(self, command):
|
|
||||||
self.digital_write(self.dc_pin, GPIO.LOW)
|
|
||||||
spi_transfer([command])
|
|
||||||
|
|
||||||
def send_data(self, data):
|
|
||||||
self.digital_write(self.dc_pin, GPIO.HIGH)
|
|
||||||
spi_transfer([data])
|
|
||||||
|
|
||||||
def init(self):
|
|
||||||
if (epd_init() != 0):
|
|
||||||
return -1
|
|
||||||
self.reset()
|
|
||||||
self.send_command(POWER_SETTING)
|
|
||||||
self.send_data(0x37)
|
|
||||||
self.send_data(0x00)
|
|
||||||
self.send_command(PANEL_SETTING)
|
|
||||||
self.send_data(0xCF)
|
|
||||||
self.send_data(0x08)
|
|
||||||
self.send_command(BOOSTER_SOFT_START)
|
|
||||||
self.send_data(0xc7)
|
|
||||||
self.send_data(0xcc)
|
|
||||||
self.send_data(0x28)
|
|
||||||
self.send_command(POWER_ON)
|
|
||||||
self.wait_until_idle()
|
|
||||||
self.send_command(PLL_CONTROL)
|
|
||||||
self.send_data(0x3c)
|
|
||||||
self.send_command(TEMPERATURE_CALIBRATION)
|
|
||||||
self.send_data(0x00)
|
|
||||||
self.send_command(VCOM_AND_DATA_INTERVAL_SETTING)
|
|
||||||
self.send_data(0x77)
|
|
||||||
self.send_command(TCON_SETTING)
|
|
||||||
self.send_data(0x22)
|
|
||||||
self.send_command(TCON_RESOLUTION)
|
|
||||||
self.send_data(0x02) #source 640
|
|
||||||
self.send_data(0x80)
|
|
||||||
self.send_data(0x01) #gate 384
|
|
||||||
self.send_data(0x80)
|
|
||||||
self.send_command(VCM_DC_SETTING)
|
|
||||||
self.send_data(0x1E) #decide by LUT file
|
|
||||||
self.send_command(0xe5) #FLASH MODE
|
|
||||||
self.send_data(0x03)
|
|
||||||
|
|
||||||
def wait_until_idle(self):
|
|
||||||
while(self.digital_read(self.busy_pin) == 0): # 0: busy, 1: idle
|
|
||||||
self.delay_ms(100)
|
|
||||||
|
|
||||||
def reset(self):
|
|
||||||
self.digital_write(self.reset_pin, GPIO.LOW) # module reset
|
|
||||||
self.delay_ms(200)
|
|
||||||
self.digital_write(self.reset_pin, GPIO.HIGH)
|
|
||||||
self.delay_ms(200)
|
|
||||||
|
|
||||||
def calibrate_display(self, no_of_cycles):
|
|
||||||
"""Function for Calibration"""
|
|
||||||
|
|
||||||
if display_type == 'colour':
|
|
||||||
packets = int(self.width / 2 * self.height)
|
|
||||||
if display_type == 'black_and_white':
|
|
||||||
packets = int(self.width / 4 * self.height)
|
|
||||||
|
|
||||||
white, red, black = 0x33, 0x04, 0x00
|
|
||||||
|
|
||||||
self.init()
|
|
||||||
print('----------Started calibration of E-Paper display----------')
|
|
||||||
for _ in range(no_of_cycles):
|
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
|
||||||
print('Calibrating black...')
|
|
||||||
[self.send_data(black) for i in range(packets)]
|
|
||||||
self.send_command(DISPLAY_REFRESH)
|
|
||||||
self.wait_until_idle()
|
|
||||||
|
|
||||||
if display_type == 'colour':
|
|
||||||
print('Calibrating red...')
|
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
|
||||||
[self.send_data(red) for i in range(packets)]
|
|
||||||
self.send_command(DISPLAY_REFRESH)
|
|
||||||
self.wait_until_idle()
|
|
||||||
|
|
||||||
print('Calibrating white...')
|
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
|
||||||
[self.send_data(white) for i in range(packets)]
|
|
||||||
self.send_command(DISPLAY_REFRESH)
|
|
||||||
self.wait_until_idle()
|
|
||||||
|
|
||||||
print('Cycle {0} of {1} complete'.format(_+1, no_of_cycles))
|
|
||||||
|
|
||||||
print('-----------Calibration complete----------')
|
|
||||||
self.sleep()
|
|
||||||
|
|
||||||
def reduce_colours(self, image):
|
|
||||||
buffer = numpy.array(image)
|
|
||||||
r,g,b = buffer[:,:,0], buffer[:,:,1], buffer[:,:,2]
|
|
||||||
|
|
||||||
if display_type == "colour":
|
|
||||||
buffer[numpy.logical_and(r <= 180, r == g)] = [0,0,0] #black
|
|
||||||
buffer[numpy.logical_and(r >= 150, g >= 150)] = [255,255,255] #white
|
|
||||||
buffer[numpy.logical_and(r >= 150, g <= 90)] = [255,0,0] #red
|
|
||||||
|
|
||||||
image = Image.fromarray(buffer)
|
|
||||||
return image
|
|
||||||
|
|
||||||
def clear(self, colour='white'):
|
|
||||||
if display_type == 'colour':
|
|
||||||
packets = int(self.width / 2 * self.height)
|
|
||||||
if display_type == 'black_and_white':
|
|
||||||
packets = int(self.width / 4 * self.height)
|
|
||||||
|
|
||||||
if colour == 'white': data = 0x33
|
|
||||||
if colour == 'red': data = 0x04
|
|
||||||
if colour == 'black': data = 0x00
|
|
||||||
|
|
||||||
self.init()
|
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
|
||||||
[self.send_data(data) for _ in range(packets)]
|
|
||||||
self.send_command(DISPLAY_REFRESH)
|
|
||||||
print('waiting until E-Paper is not busy')
|
|
||||||
self.delay_ms(100)
|
|
||||||
self.wait_until_idle()
|
|
||||||
print('E-Paper free')
|
|
||||||
self.sleep()
|
|
||||||
|
|
||||||
def get_frame_buffer(self, image):
|
|
||||||
imwidth, imheight = image.size
|
|
||||||
if imwidth == self.height and imheight == self.width:
|
|
||||||
image = image.rotate(270, expand = True)
|
|
||||||
print('Rotated image by 270 degrees...', end= '')
|
|
||||||
elif imwidth != self.width or imheight != self.height:
|
|
||||||
raise ValueError('Image must be same dimensions as display \
|
|
||||||
({0}x{1}).' .format(self.width, self.height))
|
|
||||||
else:
|
|
||||||
print('Image size OK')
|
|
||||||
imwidth, imheight = image.size
|
|
||||||
|
|
||||||
if display_type == 'colour':
|
|
||||||
buf = [0x00] * int(self.width * self.height / 4)
|
|
||||||
image_grayscale = image.convert('L')
|
|
||||||
pixels = image_grayscale.load()
|
|
||||||
|
|
||||||
for y in range(self.height):
|
|
||||||
for x in range(self.width):
|
|
||||||
# Set the bits for the column of pixels at the current position.
|
|
||||||
if pixels[x, y] == 0: # black
|
|
||||||
buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2))
|
|
||||||
elif pixels[x, y] == 76: # convert gray to red
|
|
||||||
buf[int((x + y * self.width) / 4)] &= ~(0xC0 >> (x % 4 * 2))
|
|
||||||
buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2)
|
|
||||||
else: # white
|
|
||||||
buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2)
|
|
||||||
|
|
||||||
if display_type == 'black_and_white':
|
|
||||||
buf = [0x00] * int(self.width * self.height / 8)
|
|
||||||
image_monocolor = image.convert('1', dither = True)
|
|
||||||
|
|
||||||
pixels = image_monocolor.load()
|
|
||||||
for y in range(self.height):
|
|
||||||
for x in range(self.width):
|
|
||||||
# Set the bits for the column of pixels at the current position.
|
|
||||||
if pixels[x, y] != 0:
|
|
||||||
buf[int((x + y * self.width) / 8)] |= 0x80 >> (x % 8)
|
|
||||||
|
|
||||||
return buf
|
|
||||||
|
|
||||||
def display_frame(self, frame_buffer):
|
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
|
||||||
if display_type == 'colour':
|
|
||||||
for i in range(0, int(self.width / 4 * self.height)):
|
|
||||||
temp1 = frame_buffer[i]
|
|
||||||
j = 0
|
|
||||||
while (j < 4):
|
|
||||||
if ((temp1 & 0xC0) == 0xC0):
|
|
||||||
temp2 = 0x03 #white
|
|
||||||
elif ((temp1 & 0xC0) == 0x00):
|
|
||||||
temp2 = 0x00 #black
|
|
||||||
else:
|
|
||||||
temp2 = 0x04 #red
|
|
||||||
temp2 = (temp2 << 4) & 0xFF
|
|
||||||
temp1 = (temp1 << 2) & 0xFF
|
|
||||||
j += 1
|
|
||||||
if((temp1 & 0xC0) == 0xC0):
|
|
||||||
temp2 |= 0x03 #white
|
|
||||||
elif ((temp1 & 0xC0) == 0x00):
|
|
||||||
temp2 |= 0x00 #black
|
|
||||||
else:
|
|
||||||
temp2 |= 0x04 #red
|
|
||||||
temp1 = (temp1 << 2) & 0xFF
|
|
||||||
self.send_data(temp2)
|
|
||||||
j += 1
|
|
||||||
|
|
||||||
if display_type == 'black_and_white':
|
|
||||||
for i in range(0, 30720):
|
|
||||||
temp1 = frame_buffer[i]
|
|
||||||
j = 0
|
|
||||||
while (j < 8):
|
|
||||||
if(temp1 & 0x80):
|
|
||||||
temp2 = 0x03 #white
|
|
||||||
else:
|
|
||||||
temp2 = 0x00 #black
|
|
||||||
temp2 = (temp2 << 4) & 0xFF
|
|
||||||
temp1 = (temp1 << 1) & 0xFF
|
|
||||||
j += 1
|
|
||||||
if(temp1 & 0x80):
|
|
||||||
temp2 |= 0x03 #white
|
|
||||||
else:
|
|
||||||
temp2 |= 0x00 #black
|
|
||||||
temp1 = (temp1 << 1) & 0xFF
|
|
||||||
self.send_data(temp2)
|
|
||||||
j += 1
|
|
||||||
|
|
||||||
self.send_command(DISPLAY_REFRESH)
|
|
||||||
self.delay_ms(100)
|
|
||||||
self.wait_until_idle()
|
|
||||||
|
|
||||||
def show_image(self, image, reduce_colours = True):
|
|
||||||
print('Initialising E-Paper Display...', end='')
|
|
||||||
self.init()
|
|
||||||
sleep(5)
|
|
||||||
print('Done')
|
|
||||||
|
|
||||||
if reduce_colours == True:
|
|
||||||
print('Optimising Image for E-Paper displays...', end = '')
|
|
||||||
image = self.reduce_colours(image)
|
|
||||||
print('Done')
|
|
||||||
else:
|
|
||||||
print('No colour optimisation done on image')
|
|
||||||
|
|
||||||
print('Creating image buffer and sending it to E-Paper display...', end='')
|
|
||||||
data = self.get_frame_buffer(image)
|
|
||||||
print('Done')
|
|
||||||
print('Refreshing display...', end = '')
|
|
||||||
self.display_frame(data)
|
|
||||||
print('Done')
|
|
||||||
print('Sending E-Paper to deep sleep mode...',end='')
|
|
||||||
self.sleep()
|
|
||||||
print('Done')
|
|
||||||
|
|
||||||
def sleep(self):
|
|
||||||
self.send_command(POWER_OFF)
|
|
||||||
self.wait_until_idle()
|
|
||||||
self.send_command(DEEP_SLEEP)
|
|
||||||
self.send_data(0xa5)
|
|
@ -44,8 +44,8 @@ def fetch_events():
|
|||||||
if events.all_day and events.duration.days > 1:
|
if events.all_day and events.duration.days > 1:
|
||||||
events.end = events.end.replace(days=-2)
|
events.end = events.end.replace(days=-2)
|
||||||
else:
|
else:
|
||||||
events.begin = events.begin.to(timezone)
|
|
||||||
events.end = events.end.to(timezone)
|
events.end = events.end.to(timezone)
|
||||||
|
events.begin = events.begin.to(timezone)
|
||||||
try:
|
try:
|
||||||
rule = re.search('RRULE:(.+?)\n', event_str).group(0)[:-2]
|
rule = re.search('RRULE:(.+?)\n', event_str).group(0)[:-2]
|
||||||
if re.search('UNTIL=(.+?);', rule) and not re.search('UNTIL=(.+?)Z;', rule):
|
if re.search('UNTIL=(.+?);', rule) and not re.search('UNTIL=(.+?)Z;', rule):
|
||||||
@ -76,8 +76,8 @@ def fetch_events():
|
|||||||
events.end = events.end.replace(days=-2)
|
events.end = events.end.replace(days=-2)
|
||||||
|
|
||||||
if not events.all_day:
|
if not events.all_day:
|
||||||
events.begin = events.begin.to(timezone)
|
|
||||||
events.end = events.end.to(timezone)
|
events.end = events.end.to(timezone)
|
||||||
|
events.begin = events.begin.to(timezone)
|
||||||
|
|
||||||
""" The list upcoming_events should not be modified. If you need the data from
|
""" The list upcoming_events should not be modified. If you need the data from
|
||||||
this one, copy the list or the contents to another one."""
|
this one, copy the list or the contents to another one."""
|
||||||
|
@ -7,7 +7,6 @@ Copyright by aceisace
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import feedparser
|
import feedparser
|
||||||
from random import shuffle
|
from random import shuffle
|
||||||
from settings import *
|
|
||||||
from configuration import *
|
from configuration import *
|
||||||
|
|
||||||
fontsize = 14
|
fontsize = 14
|
||||||
@ -33,8 +32,8 @@ y_padding = int( (bottom_section_height % line_height) / 2 )
|
|||||||
line_positions = [(border_left, bottom_section_offset +
|
line_positions = [(border_left, bottom_section_offset +
|
||||||
border_top + y_padding + _*line_height ) for _ in range(max_lines)]
|
border_top + y_padding + _*line_height ) for _ in range(max_lines)]
|
||||||
|
|
||||||
def main():
|
def generate_image():
|
||||||
if bottom_section == "RSS" and rss_feeds != [] and internet_available() == True:
|
if bottom_section == "inkycal_rss" and rss_feeds != [] and internet_available() == True:
|
||||||
try:
|
try:
|
||||||
clear_image('bottom_section')
|
clear_image('bottom_section')
|
||||||
print('RSS module: Connectivity check passed. Generating image...',
|
print('RSS module: Connectivity check passed. Generating image...',
|
||||||
@ -71,7 +70,7 @@ def main():
|
|||||||
del filtered_feeds, parsed_feeds
|
del filtered_feeds, parsed_feeds
|
||||||
|
|
||||||
rss_image = crop_image(image, 'bottom_section')
|
rss_image = crop_image(image, 'bottom_section')
|
||||||
rss_image.save(image_path+'rss.png')
|
rss_image.save(image_path+'inkycal_rss.png')
|
||||||
print('Done')
|
print('Done')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -81,5 +80,7 @@ def main():
|
|||||||
print('Reason: ',e)
|
print('Reason: ',e)
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main():
|
||||||
main()
|
generate_image()
|
||||||
|
|
||||||
|
main()
|
||||||
|
@ -10,10 +10,7 @@ Copyright by aceisace
|
|||||||
"""
|
"""
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import pyowm
|
import pyowm
|
||||||
from settings import *
|
|
||||||
from configuration import *
|
from configuration import *
|
||||||
from PIL import Image, ImageDraw, ImageFont
|
|
||||||
import arrow
|
|
||||||
import math, decimal
|
import math, decimal
|
||||||
dec = decimal.Decimal
|
dec = decimal.Decimal
|
||||||
|
|
||||||
@ -130,7 +127,7 @@ def to_units(kelvin):
|
|||||||
return conversion
|
return conversion
|
||||||
|
|
||||||
def red_temp(negative_temperature):
|
def red_temp(negative_temperature):
|
||||||
if display_type == 'colour' and negative_temperature[0] == '-' and units == 'metric':
|
if three_colour_support == True and negative_temperature[0] == '-' and units == 'metric':
|
||||||
colour = 'red'
|
colour = 'red'
|
||||||
else:
|
else:
|
||||||
colour = 'black'
|
colour = 'black'
|
||||||
@ -160,9 +157,9 @@ while font.getsize('hg')[1] <= (row_height * fill_height):
|
|||||||
fontsize += 1
|
fontsize += 1
|
||||||
font = ImageFont.truetype(NotoSans+'.ttf', fontsize)
|
font = ImageFont.truetype(NotoSans+'.ttf', fontsize)
|
||||||
|
|
||||||
def main():
|
def generate_image():
|
||||||
"""Connect to Openweathermap API and fetch weather data"""
|
"""Connect to Openweathermap API and fetch weather data"""
|
||||||
if top_section == "Weather" and api_key != "" and owm.is_API_online() is True:
|
if top_section == "inkycal_weather" and api_key != "" and owm.is_API_online() is True:
|
||||||
try:
|
try:
|
||||||
clear_image('top_section')
|
clear_image('top_section')
|
||||||
print('Weather module: Connectivity check passed, Generating image...',
|
print('Weather module: Connectivity check passed, Generating image...',
|
||||||
@ -331,10 +328,10 @@ def main():
|
|||||||
draw.line((coloumn7, line_start_y, coloumn7, line_end_y), fill='black')
|
draw.line((coloumn7, line_start_y, coloumn7, line_end_y), fill='black')
|
||||||
draw.line((0, top_section_height-border_top, top_section_width-
|
draw.line((0, top_section_height-border_top, top_section_width-
|
||||||
border_left, top_section_height-border_top),
|
border_left, top_section_height-border_top),
|
||||||
fill='red' if display_type == 'colour' else 'black' , width=3)
|
fill='red' if three_colour_support == 'True' else 'black' , width=3)
|
||||||
|
|
||||||
weather_image = crop_image(image, 'top_section')
|
weather_image = crop_image(image, 'top_section')
|
||||||
weather_image.save(image_path+'weather.png')
|
weather_image.save(image_path+'inkycal_weather.png')
|
||||||
print('Done')
|
print('Done')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@ -348,8 +345,10 @@ def main():
|
|||||||
write_text(coloumn_width*6, row_height, message, humidity_icon_now_pos,
|
write_text(coloumn_width*6, row_height, message, humidity_icon_now_pos,
|
||||||
font = font)
|
font = font)
|
||||||
weather_image = crop_image(image, 'top_section')
|
weather_image = crop_image(image, 'top_section')
|
||||||
weather_image.save(image_path+'weather.png')
|
weather_image.save(image_path+'inkycal_weather.png')
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def main():
|
||||||
main()
|
generate_image()
|
||||||
|
|
||||||
|
main()
|
||||||
|
@ -9,18 +9,27 @@ Copyright by aceisace
|
|||||||
"""
|
"""
|
||||||
from PIL import Image, ImageDraw, ImageFont, ImageColor
|
from PIL import Image, ImageDraw, ImageFont, ImageColor
|
||||||
import numpy
|
import numpy
|
||||||
|
import arrow
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
from settings import language
|
from settings import *
|
||||||
from pytz import timezone
|
from pytz import timezone
|
||||||
import os
|
import os
|
||||||
from glob import glob
|
from glob import glob
|
||||||
|
import importlib
|
||||||
|
|
||||||
"""Set the image background colour and text colour"""
|
"""Set the image background colour and text colour"""
|
||||||
background_colour = 'white'
|
background_colour = 'white'
|
||||||
text_colour = 'black'
|
text_colour = 'black'
|
||||||
|
|
||||||
"""Set the display height and width (in pixels)"""
|
"""Set some display parameters"""
|
||||||
display_height, display_width = 640, 384
|
driver = importlib.import_module('drivers.'+model)
|
||||||
|
display_height, display_width = driver.EPD_WIDTH, driver.EPD_HEIGHT
|
||||||
|
|
||||||
|
"""Check if the display supports 3 colours"""
|
||||||
|
if 'colour' in model:
|
||||||
|
three_colour_support = True
|
||||||
|
else:
|
||||||
|
three_colour_support = False
|
||||||
|
|
||||||
"""Create 3 sections of the display, based on percentage"""
|
"""Create 3 sections of the display, based on percentage"""
|
||||||
top_section_width = middle_section_width = bottom_section_width = display_width
|
top_section_width = middle_section_width = bottom_section_width = display_width
|
||||||
@ -189,3 +198,50 @@ def image_cleanup():
|
|||||||
for temp_files in glob(image_path+'*'):
|
for temp_files in glob(image_path+'*'):
|
||||||
os.remove(temp_files)
|
os.remove(temp_files)
|
||||||
print('Done')
|
print('Done')
|
||||||
|
|
||||||
|
def split_colours(image):
|
||||||
|
if three_colour_support == True:
|
||||||
|
"""Split image into two, one for red pixels, the other for black pixels"""
|
||||||
|
buffer = numpy.array(image.convert('RGB'))
|
||||||
|
red, green = buffer[:, :, 0], buffer[:, :, 1]
|
||||||
|
buffer_red, buffer_black = numpy.array(image), numpy.array(image)
|
||||||
|
|
||||||
|
buffer_red[numpy.logical_and(red >= 200, green <= 90)] = [0,0,0] #red->black
|
||||||
|
red1 = buffer_red[:,:,0]
|
||||||
|
buffer_red[red1 != 0] = [255,255,255] #white
|
||||||
|
red_im = Image.fromarray(buffer_red).convert('1',dither=True).rotate(270,expand=True)
|
||||||
|
|
||||||
|
buffer_black[numpy.logical_and(red <= 180, red == green)] = [0,0,0] #black
|
||||||
|
red2 = buffer_black[:,:,0]
|
||||||
|
buffer_black[red2 != 0] = [255,255,255] # white
|
||||||
|
black_im = Image.fromarray(buffer_black).convert('1', dither=True).rotate(270,expand=True)
|
||||||
|
return black_im, red_im
|
||||||
|
|
||||||
|
def calibrate_display(no_of_cycles):
|
||||||
|
"""How many times should each colour be calibrated? Default is 3"""
|
||||||
|
epaper = driver.EPD()
|
||||||
|
epaper.init()
|
||||||
|
|
||||||
|
white = Image.new('1', (display_width, display_height), 'white')
|
||||||
|
black = Image.new('1', (display_width, display_height), 'black')
|
||||||
|
|
||||||
|
print('----------Started calibration of E-Paper display----------')
|
||||||
|
if 'colour' in model:
|
||||||
|
for _ in range(no_of_cycles):
|
||||||
|
print('Calibrating black...')
|
||||||
|
epaper.display(epaper.getbuffer(black), epaper.getbuffer(white))
|
||||||
|
print('Calibrating red/yellow...')
|
||||||
|
epaper.display(epaper.getbuffer(white), epaper.getbuffer(black))
|
||||||
|
print('Calibrating white...')
|
||||||
|
epaper.display(epaper.getbuffer(white), epaper.getbuffer(white))
|
||||||
|
print('Cycle {0} of {1} complete'.format(_+1, no_of_cycles))
|
||||||
|
else:
|
||||||
|
for _ in range(no_of_cycles):
|
||||||
|
print('Calibrating black...')
|
||||||
|
epaper.display(epaper.getbuffer(black))
|
||||||
|
print('Calibrating white...')
|
||||||
|
epaper.display(epaper.getbuffer(white)),
|
||||||
|
print('Cycle {0} of {1} complete'.format(_+1, no_of_cycles))
|
||||||
|
|
||||||
|
print('-----------Calibration complete----------')
|
||||||
|
epaper.sleep()
|
||||||
|
@ -43,6 +43,10 @@ body{
|
|||||||
<div class="field">
|
<div class="field">
|
||||||
<label>How often should the display be refreshed?</label>
|
<label>How often should the display be refreshed?</label>
|
||||||
<div class="ts checkboxes">
|
<div class="ts checkboxes">
|
||||||
|
<div class="ts radio checkbox">
|
||||||
|
<input id="update_10_mins" type="radio" name="aa">
|
||||||
|
<label for="update_10_mins">every 10 minutes. Not recommended for 3-colour E-Papers.</label>
|
||||||
|
</div>
|
||||||
<div class="ts radio checkbox">
|
<div class="ts radio checkbox">
|
||||||
<input id="update_15_mins" type="radio" name="aa">
|
<input id="update_15_mins" type="radio" name="aa">
|
||||||
<label for="update_15_mins">every 15 minutes</label>
|
<label for="update_15_mins">every 15 minutes</label>
|
||||||
@ -114,15 +118,39 @@ body{
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label>Which Colours does your E-Paper Display support?</label>
|
<label>Which E-Paper model are you using?</label>
|
||||||
<div class="ts checkboxes">
|
<div class="ts checkboxes">
|
||||||
<div class="ts radio checkbox">
|
<div class="ts radio checkbox">
|
||||||
<input id="colour" type="radio" name="dp" checked>
|
<input id="epd_7_in_5_v2_colour" type="radio" name="dp" checked>
|
||||||
<label for="colour">Coloured (3 colours)</label>
|
<label for="epd_7_in_5_v2_colour">7.5" v2 (800x400px) colour</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="ts radio checkbox">
|
<div class="ts radio checkbox">
|
||||||
<input id="black-and-white" type="radio" name="dp">
|
<input id="epd_7_in_5_v2" type="radio" name="dp">
|
||||||
<label for="black-and-white">Black and White</label>
|
<label for="epd_7_in_5_v2">7.5" v2 (800x400px) black-white</label>
|
||||||
|
</div>
|
||||||
|
<div class="ts radio checkbox">
|
||||||
|
<input id="epd_7_in_5_colour" type="radio" name="dp">
|
||||||
|
<label for="epd_7_in_5_colour">7.5" v1 (600x384px) colour</label>
|
||||||
|
</div>
|
||||||
|
<div class="ts radio checkbox">
|
||||||
|
<input id="epd_7_in_5" type="radio" name="dp">
|
||||||
|
<label for="epd_7_in_5">7.5" v1 (600x384px) black-white</label>
|
||||||
|
</div>
|
||||||
|
<div class="ts radio checkbox">
|
||||||
|
<input id="epd_5_in_83_colour" type="radio" name="dp">
|
||||||
|
<label for="epd_5_in_83_colour">5.83" colour</label>
|
||||||
|
</div>
|
||||||
|
<div class="ts radio checkbox">
|
||||||
|
<input id="epd_5_in_83" type="radio" name="dp">
|
||||||
|
<label for="epd_5_in_83">5.83" black-white</label>
|
||||||
|
</div>
|
||||||
|
<div class="ts radio checkbox">
|
||||||
|
<input id="epd_4_in_2_colour" type="radio" name="dp">
|
||||||
|
<label for="epd_4_in_2_colour">4.2" colour</label>
|
||||||
|
</div>
|
||||||
|
<div class="ts radio checkbox">
|
||||||
|
<input id="epd_4_in_2" type="radio" name="dp">
|
||||||
|
<label for="epd_4_in_2">4.2" black-white</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -305,7 +333,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var template = 'ical_urls = [{ical_urls}]\nrss_feeds = [{rss_urls}]\nupdate_interval = "{update_interval}"\napi_key = "{api_key}"\nlocation = "{location}"\nweek_starts_on = "{week_starts_on}"\ncalibration_hours = [{calibration_hours}]\ndisplay_type = "{display_colours}"\nlanguage = "{language}"\nunits = "{units}"\nhours = "{hours}"\ntop_section = "{top_section}"\nmiddle_section = "{middle_section}"\nbottom_section = "{bottom_section}"';
|
var template = 'ical_urls = [{ical_urls}]\nrss_feeds = [{rss_urls}]\nupdate_interval = "{update_interval}"\napi_key = "{api_key}"\nlocation = "{location}"\nweek_starts_on = "{week_starts_on}"\ncalibration_hours = [{calibration_hours}]\nmodel = "{model}"\nlanguage = "{language}"\nunits = "{units}"\nhours = "{hours}"\ntop_section = "{top_section}"\nmiddle_section = "{middle_section}"\nbottom_section = "{bottom_section}"';
|
||||||
|
|
||||||
function generate(){
|
function generate(){
|
||||||
var ical_urls = $("#ical_urls").val().trim();
|
var ical_urls = $("#ical_urls").val().trim();
|
||||||
@ -319,6 +347,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
}
|
}
|
||||||
|
|
||||||
var update_interval = "60";
|
var update_interval = "60";
|
||||||
|
if ($('#update_10_mins').is(':checked')){
|
||||||
|
update_interval = "10";
|
||||||
|
}
|
||||||
if ($('#update_15_mins').is(':checked')){
|
if ($('#update_15_mins').is(':checked')){
|
||||||
update_interval = "15";
|
update_interval = "15";
|
||||||
}
|
}
|
||||||
@ -352,9 +383,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
calibration_hours = $("#calibration_hours").attr("placeholder");
|
calibration_hours = $("#calibration_hours").attr("placeholder");
|
||||||
}
|
}
|
||||||
|
|
||||||
var display_colours = "black_and_white";
|
var model = "epd_7_in_5_v2_colour";
|
||||||
if ($('#colour').is(':checked')){
|
if ($('#epd_7_in_5_v2').is(':checked')){
|
||||||
display_colours = "colour";
|
model = "epd_7_in_5_v2";
|
||||||
|
}
|
||||||
|
if ($('#epd_7_in_5_colour').is(':checked')){
|
||||||
|
model = "epd_7_in_5_colour";
|
||||||
|
}
|
||||||
|
if ($('#epd_7_in_5').is(':checked')){
|
||||||
|
model = "epd_7_in_5";
|
||||||
|
}
|
||||||
|
if ($('#epd_5_in_83_colour').is(':checked')){
|
||||||
|
model = "epd_5_in_83_colour";
|
||||||
|
}
|
||||||
|
if ($('#epd_5_in_83').is(':checked')){
|
||||||
|
model = "epd_5_in_83";
|
||||||
|
}
|
||||||
|
if ($('#epd_4_in_2_colour').is(':checked')){
|
||||||
|
model = "epd_4_in_2_colour";
|
||||||
|
}
|
||||||
|
if ($('#epd_4_in_2').is(':checked')){
|
||||||
|
model = "epd_4_in_2";
|
||||||
}
|
}
|
||||||
|
|
||||||
var language = "en";
|
var language = "en";
|
||||||
@ -417,30 +466,27 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
hours = "12";
|
hours = "12";
|
||||||
}
|
}
|
||||||
|
|
||||||
var top_section = "Weather";
|
var top_section = "inkycal_weather";
|
||||||
if ($('#top_blank').is(':checked')){
|
if ($('#top_blank').is(':checked')){
|
||||||
top_section = "";
|
top_section = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
var middle_section = "Calendar";
|
var middle_section = "inkycal_calendar";
|
||||||
if ($('#Agenda').is(':checked')){
|
if ($('#Agenda').is(':checked')){
|
||||||
middle_section = "Agenda";
|
middle_section = "inkycal_agenda";
|
||||||
}
|
}
|
||||||
if ($('#middle_blank').is(':checked')){
|
if ($('#middle_blank').is(':checked')){
|
||||||
middle_section = "";
|
middle_section = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
var bottom_section = "RSS";
|
var bottom_section = "inkycal_rss";
|
||||||
if ($('#Events').is(':checked')){
|
|
||||||
bottom_section = "Events";
|
|
||||||
}
|
|
||||||
if ($('#bottom_blank').is(':checked')){
|
if ($('#bottom_blank').is(':checked')){
|
||||||
bottom_section = "";
|
bottom_section = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//console.log(ical_urls, rss_urls, update_interval, api_key, location, week_starts_on, calibration_hours, display_type, language, units, hours, top_section, middle_section, bottom_section);
|
//console.log(ical_urls, rss_urls, update_interval, api_key, location, week_starts_on, calibration_hours, model, language, units, hours, top_section, middle_section, bottom_section);
|
||||||
createPythonSetting(ical_urls, rss_urls, update_interval, api_key, location, week_starts_on, calibration_hours, display_colours, language, units, hours, top_section, middle_section, bottom_section);
|
createPythonSetting(ical_urls, rss_urls, update_interval, api_key, location, week_starts_on, calibration_hours, model, language, units, hours, top_section, middle_section, bottom_section);
|
||||||
}
|
}
|
||||||
|
|
||||||
function rk(content,key,value){
|
function rk(content,key,value){
|
||||||
@ -457,7 +503,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
|
|||||||
box = rk(box,"location",e);
|
box = rk(box,"location",e);
|
||||||
box = rk(box,"week_starts_on",f);
|
box = rk(box,"week_starts_on",f);
|
||||||
box = rk(box,"calibration_hours",g);
|
box = rk(box,"calibration_hours",g);
|
||||||
box = rk(box,"display_colours",h);
|
box = rk(box,"model",h);
|
||||||
box = rk(box,"language",i);
|
box = rk(box,"language",i);
|
||||||
box = rk(box,"units",j);
|
box = rk(box,"units",j);
|
||||||
box = rk(box,"hours",k);
|
box = rk(box,"hours",k);
|
||||||
|
@ -1,13 +1,12 @@
|
|||||||
ical_urls = ["https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics"]
|
ical_urls = ["https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics"]
|
||||||
rss_feeds = ["http://feeds.bbci.co.uk/news/world/rss.xml#"] # Use any RSS feed
|
rss_feeds = ["http://feeds.bbci.co.uk/news/world/rss.xml#"] # Use any RSS feed
|
||||||
|
|
||||||
|
|
||||||
update_interval = "60" # "15" # "30" # "60"
|
update_interval = "60" # "15" # "30" # "60"
|
||||||
api_key = "" # Your openweathermap API-KEY -> "api-key"
|
api_key = "" # Your openweathermap API-KEY -> "api-key"
|
||||||
location = "Stuttgart, DE" # "City name, Country code"
|
location = "Stuttgart, DE" # "City name, Country code"
|
||||||
week_starts_on = "Monday" # "Monday" # "Sunday"
|
week_starts_on = "Monday" # "Monday" # "Sunday"
|
||||||
calibration_hours = [0,12,18] # Do not change unless required
|
calibration_hours = [0,12,18] # Do not change unlesss you know what you are doing
|
||||||
display_type = "colour" # "colour" # "black_and_white"
|
model = "epd_7_in_5_v2_colour" # Choose the E-Paper model (see below)
|
||||||
language = "en" # "en" # "de" # "fr" # "jp" etc.
|
language = "en" # "en" # "de" # "fr" # "jp" etc.
|
||||||
units = "metric" # "metric" # "imperial"
|
units = "metric" # "metric" # "imperial"
|
||||||
hours = "24" # "24" # "12"
|
hours = "24" # "24" # "12"
|
||||||
@ -26,3 +25,12 @@ bottom_section = "RSS" # "RSS"
|
|||||||
# URLs should have this sign (") on both side -> "url1"
|
# URLs should have this sign (") on both side -> "url1"
|
||||||
# If more than one URL is used, separate each one with a comma -> "url1", "url2"
|
# If more than one URL is used, separate each one with a comma -> "url1", "url2"
|
||||||
|
|
||||||
|
"""Supported E-Paper models"""
|
||||||
|
# epd_7_in_5_v2_colour # 7.5" high-res black-white-red/yellow
|
||||||
|
# epd_7_in_5_v2 # 7.5" high-res black-white
|
||||||
|
# epd_7_in_5_colour # 7.5" black-white-red/yellow
|
||||||
|
# epd_7_in_5 # 7.5" black-white
|
||||||
|
# epd_5_in_83_colour # 5.83" black-white-red/yellow
|
||||||
|
# epd_5_in_83 # 5.83" black-white
|
||||||
|
# epd_4_in_2_colour # 4.2" black-white-red/yellow
|
||||||
|
# epd_4_in_2 # 4.2" black-white
|
||||||
|
Loading…
Reference in New Issue
Block a user