Folder restructuring

Reorganised folders and files
This commit is contained in:
Ace
2020-05-07 20:16:55 +02:00
parent 47a327cddc
commit fd9fcbcc8d
40 changed files with 625 additions and 1789 deletions

45
inkycal/Inkycal.py Normal file
View File

@@ -0,0 +1,45 @@
from importlib import import_module
from inkycal.configuration.settings_parser import inkycal_settings as settings
from inkycal.display.layout import inkycal_layout as layout
##modules = settings.which_modules()
##for module in modules:
## if module == 'inkycal_rss':
## module = import_module('inkycal.modules.'+module)
## #import_module('modules.'+module)
##print(module)
settings_file = '/home/pi/Desktop/settings.json'
class inkycal:
def __init__(self, settings_file_path):
"""Load settings file from path"""
# Load settings file
self.settings = settings(settings_file_path)
self.model = self.settings.model
def create_canvas(self):
"""Create a canvas with same size as the specified model"""
self.layout = layout(model=self.model)
def create_custom_canvas(self, width=None, height=None,
supports_colour=False):
"""Create a custom canvas by specifying height and width"""
self.layout = layout(model=model, width=width, height=height,
supports_colour=supports_colour)
def create_sections(self):
"""Create sections with default sizes"""
self.layout.create_sections()
def create_custom_sections(self, top_section=0.10, middle_section=0.65,
bottom_section=0.25):
"""Create custom-sized sections in the canvas"""
self.layout.create_sections(top_section=top_section,
middle_section=middle_section,
bottom_section=bottom_section)

0
inkycal/__init__.py Normal file
View File

View File

@@ -0,0 +1,2 @@
from .settings_parser import inkycal_settings
print('loaded settings')

View File

@@ -0,0 +1,42 @@
{
"language": "en",
"units": "metric",
"hours": 24,
"model": "epd_7_in_5_v2_colour",
"update_interval": 60,
"calibration_hours": [
0,
12,
18
],
"display_orientation": "normal",
"panels": [
{
"location": "top",
"type": "inkycal_weather",
"config": {
"api_key": "topsecret",
"location": "Stuttgart, DE"
}
},
{
"location": "middle",
"type": "inkycal_calendar",
"config": {
"week_starts_on": "Monday",
"ical_urls": [
"https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics"
]
}
},
{
"location": "bottom",
"type": "inkycal_rss",
"config": {
"rss_urls": [
"http://feeds.bbci.co.uk/news/world/rss.xml#"
]
}
}
]
}

View File

@@ -0,0 +1,137 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Json settings parser. Currently in alpha!
Copyright by aceisace
"""
import json
from os import chdir #Ad-hoc
# TODO:
# Check of jsmin can/should be used to parse jsonc settings file
# Remove check of fixed settings file location. Ask user to specify path
# to settings file
from os import path
class inkycal_settings:
"""Load and validate settings from the settings file"""
__supported_languages = ['en', 'de', 'ru', 'it', 'es', 'fr', 'el', 'sv', 'nl',
'pl', 'ua', 'nb', 'vi', 'zh_tw', 'zh-cn', 'ja', 'ko']
__supported_units = ['metric', 'imperial']
__supported_hours = [12, 24]
__supported_display_orientation = ['normal', 'upside_down']
__supported_models = [
'epd_7_in_5_v2_colour', 'epd_7_in_5_v2',
'epd_7_in_5_colour', 'epd_7_in_5',
'epd_5_in_83_colour','epd_5_in_83',
'epd_4_in_2_colour', 'epd_4_in_2'
]
def __init__(self, settings_file_path):
"""Load settings from path (folder or settings.json file)"""
try:
if settings_file_path.endswith('settings.json'):
folder = settings_file_path.split('/settings.json')[0]
else:
folder = settings_file_path
chdir(folder)
with open("settings.json") as file:
self.raw_settings = json.load(file)
except FileNotFoundError:
print('No settings file found in specified location')
try:
self.language = self.raw_settings['language']
if self.language not in self.__supported_languages or type(self.language) != str:
print('Unsupported language: {}!. Switching to english'.format(language))
self.language = 'en'
self.units = self.raw_settings['units']
if self.units not in self.__supported_units or type(self.units) != str:
print('Units ({}) not supported, using metric units.'.format(units))
self.units = 'metric'
self.hours = self.raw_settings['hours']
if self.hours not in self.__supported_hours or type(self.hours) != int:
print('Selected hours: {} not supported, using 24-hours'.format(hours))
self.hours = '24'
self.model = self.raw_settings['model']
if self.model not in self.__supported_models or type(self.model) != str:
print('Model: {} not supported. Please select a valid option'.format(model))
print('Switching to 7.5" ePaper black-white (v1) (fallback)')
self.model = 'epd_7_in_5'
self.calibration_hours = self.raw_settings['calibration_hours']
if not self.calibration_hours or type(self.calibration_hours) != list:
print('Invalid calibration hours: {}'.format(calibration_hours))
print('Using default option, 0am,12am,6pm')
self.calibration_hours = [0,12,18]
self.display_orientation = self.raw_settings['display_orientation']
if self.display_orientation not in self.__supported_display_orientation or type(
self.display_orientation) != str:
print('Invalid ({}) display orientation.'.format(display_orientation))
print('Switching to default orientation, normal-mode')
self.display_orientation = 'normal'
### Check if empty, If empty, set to none
for sections in self.raw_settings['panels']:
if sections['location'] == 'top':
self.top_section = sections['type']
self.top_section_config = sections['config']
elif sections['location'] == 'middle':
self.middle_section = sections['type']
self.middle_section_config = sections['config']
elif sections['location'] == 'bottom':
self.bottom_section = sections['type']
self.bottom_section_config = sections['config']
print('settings loaded')
except Exception as e:
print(e.reason)
def module_init(self, module_name):
"""Get all data from settings file by providing the module name"""
if module_name == self.top_section:
config = self.top_section_config
elif module_name == self.middle_section:
config = self.middle_section_config
elif module_name == self.bottom_section:
config = self.bottom_section_config
else:
print('Invalid module name!')
config = None
for module in self.raw_settings['panels']:
if module_name == module['type']:
location = module['location']
return config, location
def which_modules(self):
"""Returns a list of modules (from settings file) which should be loaded
on start"""
lst = [self.top_section, self.middle_section, self.bottom_section]
return lst
def main():
print('running settings parser as standalone...')
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,2 @@
from .layout import inkycal_layout
print('imported layout class')

View File

@@ -0,0 +1 @@
#nothing in here. What did you expect?

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

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

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

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

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

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

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

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

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

82
inkycal/display/layout.py Normal file
View File

@@ -0,0 +1,82 @@
class inkycal_layout:
"""Page layout handling"""
def __init__(self, model=None, width=None, height=None,
supports_colour=False):
"""Initialize parameters for specified epaper model
Use model parameter to specify display OR
Crate a custom display with given width and height"""
self.background_colour = 'white' # Move to inkycal_rendering
self.text_colour = 'black' # Move to inkycal_rendering
if (model != None) and (width == None) and (height == None):
display_dimensions = {
'epd_7_in_5_v2_colour': (800, 400),
'epd_7_in_5_v2': (800, 400),
'epd_7_in_5_colour': (640, 384),
'epd_7_in_5': (640, 384),
'epd_5_in_83_colour': (600, 448),
'epd_5_in_83': (600, 448),
'epd_4_in_2_colour': (400, 300),
'epd_4_in_2': (400, 300),
}
self.display_height, self.display_width = display_dimensions[model]
if 'colour' in model:
self.three_colour_support = True
elif width and height:
self.display_height = width
self.display_width = height
self.supports_colour = supports_colour
else:
print("Can't create a layout without given sizes")
raise
self.__top_section_width = self.display_width
self.__middle_section_width = self.display_width
self.__bottom_section_width = self.display_width
self.create_sections()
def create_sections(self, top_section=0.10, middle_section=0.65,
bottom_section=0.25):
"""Allocate fixed percentage height for top and middle section
e.g. 0.2 = 20% (Leave empty for default values)
Set top/bottom_section to 0 to allocate more space for the middle section
"""
scale = lambda percentage: round(percentage * self.display_height)
if top_section == 0 or bottom_section == 0:
if top_section == 0:
self.__top_section_height = 0
if bottom_section == 0:
self.__bottom_section_height = 0
self.__middle_section_height = scale(1 - top_section - bottom_section)
else:
if top_section + middle_section + bottom_section > 1.0:
print('All percentages should add up to max 100%, not more!')
raise
self.__top_section_height = scale(top_section)
self.__middle_section_height = scale(middle_section)
self.__bottom_section_height = (self.display_height -
self.__top_section_height - self.__middle_section_height)
def get_section_size(self, section):
"""Enter top/middle/bottom to get the size of the section as a tuple:
(width, height)"""
if section not in ['top','middle','bottom']:
print('Invalid section: ', section)
raise
else:
if section == 'top':
size = (self.__top_section_width, self.__top_section_height)
elif section == 'middle':
size = (self.__middle_section_width, self.__middle_section_height)
elif section == 'bottom':
size = (self.__bottom_section_width, self.__bottom_section_height)
return size

View File

View File

View File

@@ -0,0 +1,140 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
RSS module for Inky-Calendar Project
Copyright by aceisace
"""
from inkycal.render.functions import *
from random import shuffle
try:
import feedparser
except ImportError:
print('feedparser is not installed! Please install with:')
print('pipe install feedparser')
# Debug Data
size = (384, 160)
config = {'rss_urls': ['http://feeds.bbci.co.uk/news/world/rss.xml#']}
class inkycal_rss:
def __init__(self, section_size, section_config):
"""Initialize inkycal_rss module"""
self.name = os.path.basename(__file__).split('.py')[0]
self.config = section_config
self.width, self.height = section_size
self.background_colour = 'white'
self.font_colour = 'black'
self.fontsize = 12
self.font = ImageFont.truetype(
fonts['NotoSans-SemiCondensed'], size = self.fontsize)
self.padding_x = 0.02
self.padding_y = 0.05
print('{0} loaded'.format(self.name))
def set(self, **kwargs):
"""Manually set some parameters of this module"""
for key, value in kwargs.items():
if key in self.__dict__:
setattr(self, key, value)
else:
print('{0} does not exist'.format(key))
pass
def get(self, **kwargs):
"""Manually get some parameters of this module"""
for key, value in kwargs.items():
if key in self.__dict__:
getattr(self, key, value)
else:
print('{0} does not exist'.format(key))
pass
def get_options(self):
"""Get all options which can be changed"""
return self.__dict__
def generate_image(self):
"""Generate image for this module"""
# Define new image size with respect to padding
im_width = int(self.width - (self.width * 2 * self.padding_x))
im_height = int(self.height - (self.height * 2 * self.padding_y))
im_size = im_width, im_height
# Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size = im_size, color = self.background_colour)
im_colour = Image.new('RGB', size = im_size, color = 'white')
# Set some parameters for formatting rss feeds
line_spacing = 1
line_height = self.font.getsize('hg')[1] + line_spacing
line_width = im_width
max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing))
# Calculate padding from top so the lines look centralised
spacing_top = int( im_height % line_height / 2 )
# Calculate line_positions
line_positions = [
(0, spacing_top + _ * line_height ) for _ in range(max_lines)]
if internet_available() == True:
print('Connection test passed')
else:
# write 'No network available :('
raise Exception('Network could not be reached :(')
try:
# Create list containing all rss-feeds from all rss-feed urls
parsed_feeds = []
for feeds in self.config['rss_urls']:
text = feedparser.parse(feeds)
for posts in text.entries:
parsed_feeds.append('{0}: {1}'.format(posts.title, posts.summary))
# print(parsed_feeds)
# Shuffle the list to prevent showing the same content
shuffle(parsed_feeds)
# Trim down the list to the max number of lines
del parsed_feeds[max_lines:]
# Wrap long text from feeds (line-breaking)
flatten = lambda z: [x for y in z for x in y]
filtered_feeds, counter = [], 0
for posts in parsed_feeds:
wrapped = text_wrap(posts, font = self.font, max_width = line_width)
counter += len(filtered_feeds) + len(wrapped)
if counter < max_lines:
filtered_feeds.append(wrapped)
filtered_feeds = flatten(filtered_feeds)
# Write rss-feeds on image
"""Write the correctly formatted text on the display"""
for _ in range(len(filtered_feeds)):
write(im_black, line_positions[_], (line_width, line_height),
filtered_feeds[_], font = self.font, alignment= 'left')
# Cleanup
del filtered_feeds, parsed_feeds, wrapped, counter, text
except Exception as e:
print('Error in {0}'.format(self.name))
print('Reason: ',e)
write(im_black, (0,0), (im_width, im_height), str(e), font = self.font)
# Save image of black and colour channel in image-folder
im_black.save(images+self.name+'.png')
im_colour.save(images+self.name+'_colour.png')
if __name__ == '__main__':
print('running {0} in standalone mode'.format(
os.path.basename(__file__).split('.py')[0]))

View File

@@ -0,0 +1 @@
from .fonts import inkycal_fonts

165
inkycal/render/functions.py Normal file
View File

@@ -0,0 +1,165 @@
#!/usr/bin/python3
# -*- coding: utf-8 -*-
"""
Inky-Calendar custom-functions for ease-of-use
Copyright by aceisace
"""
from PIL import Image, ImageDraw, ImageFont, ImageColor
from urllib.request import urlopen
import os
import time
##from glob import glob
##import importlib
##import subprocess as subp
##import numpy
##import arrow
##from pytz import timezone
##"""Set some display parameters"""
##driver = importlib.import_module('drivers.'+model)
# Get the path to the Inky-Calendar folder
top_level = os.path.dirname(
os.path.abspath(os.path.dirname(__file__))).split('/inkycal')[0]
# Get path of 'fonts' and 'images' folders within Inky-Calendar folder
fonts_location = top_level + '/fonts/'
images = top_level + '/images/'
# Get available fonts within fonts folder
fonts = {}
for path,dirs,files in os.walk(fonts_location):
for filename in files:
if filename.endswith('.otf'):
name = filename.split('.otf')[0]
fonts[name] = os.path.join(path, filename)
if filename.endswith('.ttf'):
name = filename.split('.ttf')[0]
fonts[name] = os.path.join(path, filename)
del name, filename, files
available_fonts = [key for key,values in fonts.items()]
def get_fonts():
"""Print all available fonts by name"""
for fonts in available_fonts:
print(fonts)
def write(image, xy, box_size, text, font=None, **kwargs):
"""Write text on specified image
image = on which image should the text be added?
xy = xy-coordinates as tuple -> (x,y)
box_size = size of text-box -> (width,height)
text = string (what to write)
font = which font to use
"""
allowed_kwargs = ['alignment', 'autofit', 'colour', 'rotation'
'fill_width', 'fill_height']
alignment='center'
autofit = False
fill_width = 1.0
fill_height = 0.8
colour = 'black'
rotation = None
for key, value in kwargs.items():
if key in allowed_kwargs:
setattr(write, key, value)
else:
print('{0} does not exist'.format(key))
pass
x,y = xy
box_width, box_height = box_size
# Increase fontsize to fit specified height and width of text box
if autofit == True or fill_width != 1.0 or fill_height != 0.8:
size = 8
font = ImageFont.truetype(font, size)
text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1]
while (
text_width < int(box_width * fill_width)
) and (
text_height < int(box_height * fill_height)
):
size += 1
font = ImageFont.truetype(font, size)
text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1]
text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1]
# Truncate text if text is too long so it can fit inside the box
while (text_width, text_height) > (box_width, box_height):
text=text[0:-1]
text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1]
# Align text to desired position
if alignment == "" or "center" or None:
x = int((box_width / 2) - (text_width / 2))
elif alignment == 'left':
x = 0
elif alignment == 'right':
x = int(box_width - text_width)
y = int((box_height / 2) - (text_height / 2))
# Draw the text in the text-box
draw = ImageDraw.Draw(image)
space = Image.new('RGBA', (box_width, box_height))
ImageDraw.Draw(space).text((x, y), text, fill=colour, font=font)
if rotation != None:
space.rotate(rotation, expand = True)
# Update only region with text (add text with transparent background)
image.paste(space, xy, space)
def text_wrap(text, font=None, max_width = None):
"""Split long text (text-wrapping). Returns a list"""
lines = []
if font.getsize(text)[0] < max_width:
lines.append(text)
else:
words = text.split(' ')
i = 0
while i < len(words):
line = ''
while i < len(words) and font.getsize(line + words[i])[0] <= max_width:
line = line + words[i] + " "
i += 1
if not line:
line = words[i]
i += 1
lines.append(line)
return lines
def internet_available():
"""check if the internet is available"""
try:
urlopen('https://google.com',timeout=5)
return True
except URLError as err:
return False
def get_system_tz():
"""Get the timezone set by the system"""
try:
local_tz = time.tzname[1]
except:
print('System timezone could not be parsed!')
print('Please set timezone manually!. Setting timezone to None...')
local_tz = None
return local_tz