Improved formatting

This commit is contained in:
aceisace
2022-04-02 01:30:17 +02:00
parent 9bf4385b6b
commit 5b032d6231
42 changed files with 3644 additions and 3661 deletions

View File

@@ -1,4 +1,4 @@
# Display class (for dirving E-Paper displays) # Display class (for driving E-Paper displays)
from inkycal.display import Display from inkycal.display import Display
# Default modules # Default modules

View File

@@ -25,7 +25,7 @@ images = top_level + '/images/'
# Get available fonts within fonts folder # Get available fonts within fonts folder
fonts = {} fonts = {}
for path,dirs,files in os.walk(fonts_location): for path, dirs, files in os.walk(fonts_location):
for filename in files: for filename in files:
if filename.endswith('.otf'): if filename.endswith('.otf'):
name = filename.split('.otf')[0] name = filename.split('.otf')[0]
@@ -35,7 +35,8 @@ for path,dirs,files in os.walk(fonts_location):
name = filename.split('.ttf')[0] name = filename.split('.ttf')[0]
fonts[name] = os.path.join(path, filename) fonts[name] = os.path.join(path, filename)
available_fonts = [key for key,values in fonts.items()] available_fonts = [key for key, values in fonts.items()]
def get_fonts(): def get_fonts():
"""Print all available fonts by name. """Print all available fonts by name.
@@ -146,7 +147,7 @@ def write(image, xy, box_size, text, font=None, **kwargs):
colour = kwargs['colour'] if 'colour' in kwargs else 'black' colour = kwargs['colour'] if 'colour' in kwargs else 'black'
rotation = kwargs['rotation'] if 'rotation' in kwargs else None rotation = kwargs['rotation'] if 'rotation' in kwargs else None
x,y = xy x, y = xy
box_width, box_height = box_size box_width, box_height = box_size
# Increase fontsize to fit specified height and width of text box # Increase fontsize to fit specified height and width of text box
@@ -162,12 +163,11 @@ def write(image, xy, box_size, text, font=None, **kwargs):
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 # Truncate text if text is too long so it can fit inside the box
if (text_width, text_height) > (box_width, box_height): if (text_width, text_height) > (box_width, box_height):
logs.debug(('truncating {}'.format(text))) logs.debug(('truncating {}'.format(text)))
while (text_width, text_height) > (box_width, box_height): while (text_width, text_height) > (box_width, box_height):
text=text[0:-1] text = text[0:-1]
text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1] text_width, text_height = font.getsize(text)[0], font.getsize('hg')[1]
logs.debug((text)) logs.debug((text))
@@ -189,17 +189,17 @@ def write(image, xy, box_size, text, font=None, **kwargs):
# Uncomment following two lines, comment out above two lines to show # Uncomment following two lines, comment out above two lines to show
# red text-box with white text (debugging purposes) # red text-box with white text (debugging purposes)
#space = Image.new('RGBA', (box_width, box_height), color= 'red') # space = Image.new('RGBA', (box_width, box_height), color= 'red')
#ImageDraw.Draw(space).text((x, y), text, fill='white', font=font) # ImageDraw.Draw(space).text((x, y), text, fill='white', font=font)
if rotation != None: if rotation != None:
space.rotate(rotation, expand = True) space.rotate(rotation, expand=True)
# Update only region with text (add text with transparent background) # Update only region with text (add text with transparent background)
image.paste(space, xy, space) image.paste(space, xy, space)
def text_wrap(text, font=None, max_width = None): def text_wrap(text, font=None, max_width=None):
"""Splits a very long text into smaller parts """Splits a very long text into smaller parts
Splits a long text to smaller lines which can fit in a line with max_width. Splits a long text to smaller lines which can fit in a line with max_width.
@@ -248,13 +248,13 @@ def internet_available():
""" """
try: try:
urlopen('https://google.com',timeout=5) urlopen('https://google.com', timeout=5)
return True return True
except URLError as err: except:
return False return False
def draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1,0.1)): def draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1, 0.1)):
"""Draws a border at given coordinates. """Draws a border at given coordinates.
Args: Args:
@@ -276,39 +276,39 @@ def draw_border(image, xy, size, radius=5, thickness=1, shrinkage=(0.1,0.1)):
border by 20% border by 20%
""" """
colour='black' colour = 'black'
# size from function paramter # size from function paramter
width, height = int(size[0]*(1-shrinkage[0])), int(size[1]*(1-shrinkage[1])) width, height = int(size[0] * (1 - shrinkage[0])), int(size[1] * (1 - shrinkage[1]))
# shift cursor to move rectangle to center # shift cursor to move rectangle to center
offset_x, offset_y = int((size[0] - width)/2), int((size[1]- height)/2) offset_x, offset_y = int((size[0] - width) / 2), int((size[1] - height) / 2)
x, y, diameter = xy[0]+offset_x, xy[1]+offset_y, radius*2 x, y, diameter = xy[0] + offset_x, xy[1] + offset_y, radius * 2
# lenght of rectangle size # lenght of rectangle size
a,b = (width - diameter), (height-diameter) a, b = (width - diameter), (height - diameter)
# Set coordinates for staright lines # Set coordinates for staright lines
p1, p2 = (x+radius, y), (x+radius+a, y) p1, p2 = (x + radius, y), (x + radius + a, y)
p3, p4 = (x+width, y+radius), (x+width, y+radius+b) p3, p4 = (x + width, y + radius), (x + width, y + radius + b)
p5, p6 = (p2[0], y+height), (p1[0], y+height) p5, p6 = (p2[0], y + height), (p1[0], y + height)
p7, p8 = (x, p4[1]), (x,p3[1]) p7, p8 = (x, p4[1]), (x, p3[1])
if radius != 0: if radius != 0:
# Set coordinates for arcs # Set coordinates for arcs
c1, c2 = (x,y), (x+diameter, y+diameter) c1, c2 = (x, y), (x + diameter, y + diameter)
c3, c4 = ((x+width)-diameter, y), (x+width, y+diameter) c3, c4 = ((x + width) - diameter, y), (x + width, y + diameter)
c5, c6 = ((x+width)-diameter, (y+height)-diameter), (x+width, y+height) c5, c6 = ((x + width) - diameter, (y + height) - diameter), (x + width, y + height)
c7, c8 = (x, (y+height)-diameter), (x+diameter, y+height) c7, c8 = (x, (y + height) - diameter), (x + diameter, y + height)
# Draw lines and arcs, creating a square with round corners # Draw lines and arcs, creating a square with round corners
draw = ImageDraw.Draw(image) draw = ImageDraw.Draw(image)
draw.line( (p1, p2) , fill=colour, width = thickness) draw.line((p1, p2), fill=colour, width=thickness)
draw.line( (p3, p4) , fill=colour, width = thickness) draw.line((p3, p4), fill=colour, width=thickness)
draw.line( (p5, p6) , fill=colour, width = thickness) draw.line((p5, p6), fill=colour, width=thickness)
draw.line( (p7, p8) , fill=colour, width = thickness) draw.line((p7, p8), fill=colour, width=thickness)
if radius != 0: if radius != 0:
draw.arc( (c1, c2) , 180, 270, fill=colour, width=thickness) draw.arc((c1, c2), 180, 270, fill=colour, width=thickness)
draw.arc( (c3, c4) , 270, 360, fill=colour, width=thickness) draw.arc((c3, c4), 270, 360, fill=colour, width=thickness)
draw.arc( (c5, c6) , 0, 90, fill=colour, width=thickness) draw.arc((c5, c6), 0, 90, fill=colour, width=thickness)
draw.arc( (c7, c8) , 90, 180, fill=colour, width=thickness) draw.arc((c7, c8), 90, 180, fill=colour, width=thickness)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
9.7" driver class 9.7" driver class
Copyright by aceisace Copyright by aceisace
@@ -12,7 +12,8 @@ from PIL import Image
EPD_WIDTH = 1200 EPD_WIDTH = 1200
EPD_HEIGHT = 825 EPD_HEIGHT = 825
driver_dir = top_level+'/inkycal/display/drivers/9_in_7_drivers/' driver_dir = top_level + '/inkycal/display/drivers/9_in_7_drivers/'
class EPD: class EPD:
@@ -40,11 +41,10 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
"""ad-hoc""" """ad-hoc"""
image = image.rotate(90, expand=True) image = image.rotate(90, expand=True)
image.convert('RGB').save(images+'canvas.bmp', 'BMP') image.convert('RGB').save(images + 'canvas.bmp', 'BMP')
command = 'sudo {}IT8951/IT8951 0 0 {}'.format(driver_dir, images+'canvas.bmp') command = 'sudo {}IT8951/IT8951 0 0 {}'.format(driver_dir, images + 'canvas.bmp')
#print(command) # print(command)
return command return command
def sleep(self): def sleep(self):
pass pass

View File

@@ -37,10 +37,11 @@ import RPi.GPIO as GPIO
EPD_WIDTH = 400 EPD_WIDTH = 400
EPD_HEIGHT = 300 EPD_HEIGHT = 300
GRAY1 = 0xff #white GRAY1 = 0xff # white
GRAY2 = 0xC0 GRAY2 = 0xC0
GRAY3 = 0x80 #gray GRAY3 = 0x80 # gray
GRAY4 = 0x00 #Blackest GRAY4 = 0x00 # Blackest
class EPD: class EPD:
def __init__(self): def __init__(self):
@@ -50,10 +51,10 @@ class EPD:
self.cs_pin = epdconfig.CS_PIN self.cs_pin = epdconfig.CS_PIN
self.width = EPD_WIDTH self.width = EPD_WIDTH
self.height = EPD_HEIGHT self.height = EPD_HEIGHT
self.GRAY1 = GRAY1 #white self.GRAY1 = GRAY1 # white
self.GRAY2 = GRAY2 self.GRAY2 = GRAY2
self.GRAY3 = GRAY3 #gray self.GRAY3 = GRAY3 # gray
self.GRAY4 = GRAY4 #Blackest self.GRAY4 = GRAY4 # Blackest
lut_vcom0 = [ lut_vcom0 = [
0x00, 0x17, 0x00, 0x00, 0x00, 0x02, 0x00, 0x17, 0x00, 0x00, 0x00, 0x02,
@@ -101,56 +102,56 @@ class EPD:
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
] ]
#******************************gray*********************************/ # ******************************gray*********************************/
#0~3 gray # 0~3 gray
EPD_4IN2_4Gray_lut_vcom =[ EPD_4IN2_4Gray_lut_vcom = [
0x00 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, 0x00, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x60 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, 0x60, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00 ,0x14 ,0x00 ,0x00 ,0x00 ,0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01,
0x00 ,0x13 ,0x0A ,0x01 ,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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
] ]
#R21 # R21
EPD_4IN2_4Gray_lut_ww =[ EPD_4IN2_4Gray_lut_ww = [
0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x10 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, 0x10, 0x14, 0x0A, 0x00, 0x00, 0x01,
0xA0 ,0x13 ,0x01 ,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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
] ]
#R22H r # R22H r
EPD_4IN2_4Gray_lut_bw =[ EPD_4IN2_4Gray_lut_bw = [
0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99 ,0x0C ,0x01 ,0x03 ,0x04 ,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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
] ]
#R23H w # R23H w
EPD_4IN2_4Gray_lut_wb =[ EPD_4IN2_4Gray_lut_wb = [
0x40 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, 0x40, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x00 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, 0x00, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x99 ,0x0B ,0x04 ,0x04 ,0x01 ,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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
] ]
#R24H b # R24H b
EPD_4IN2_4Gray_lut_bb =[ EPD_4IN2_4Gray_lut_bb = [
0x80 ,0x0A ,0x00 ,0x00 ,0x00 ,0x01, 0x80, 0x0A, 0x00, 0x00, 0x00, 0x01,
0x90 ,0x14 ,0x14 ,0x00 ,0x00 ,0x01, 0x90, 0x14, 0x14, 0x00, 0x00, 0x01,
0x20 ,0x14 ,0x0A ,0x00 ,0x00 ,0x01, 0x20, 0x14, 0x0A, 0x00, 0x00, 0x01,
0x50 ,0x13 ,0x01 ,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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
] ]
# Hardware reset # Hardware reset
@@ -176,7 +177,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
self.send_command(0x71) self.send_command(0x71)
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy while (epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
self.send_command(0x71) self.send_command(0x71)
epdconfig.delay_ms(100) epdconfig.delay_ms(100)
@@ -202,31 +203,30 @@ class EPD:
self.send_data(self.lut_wb[count]) self.send_data(self.lut_wb[count])
def Gray_SetLut(self): def Gray_SetLut(self):
self.send_command(0x20) #vcom self.send_command(0x20) # vcom
for count in range(0, 42): for count in range(0, 42):
self.send_data(self.EPD_4IN2_4Gray_lut_vcom[count]) self.send_data(self.EPD_4IN2_4Gray_lut_vcom[count])
self.send_command(0x21) #red not use self.send_command(0x21) # red not use
for count in range(0, 42): for count in range(0, 42):
self.send_data(self.EPD_4IN2_4Gray_lut_ww[count]) self.send_data(self.EPD_4IN2_4Gray_lut_ww[count])
self.send_command(0x22) #bw r self.send_command(0x22) # bw r
for count in range(0, 42): for count in range(0, 42):
self.send_data(self.EPD_4IN2_4Gray_lut_bw[count]) self.send_data(self.EPD_4IN2_4Gray_lut_bw[count])
self.send_command(0x23) #wb w self.send_command(0x23) # wb w
for count in range(0, 42): for count in range(0, 42):
self.send_data(self.EPD_4IN2_4Gray_lut_wb[count]) self.send_data(self.EPD_4IN2_4Gray_lut_wb[count])
self.send_command(0x24) #bb b self.send_command(0x24) # bb b
for count in range(0, 42): for count in range(0, 42):
self.send_data(self.EPD_4IN2_4Gray_lut_bb[count]) self.send_data(self.EPD_4IN2_4Gray_lut_bb[count])
self.send_command(0x25) #vcom self.send_command(0x25) # vcom
for count in range(0, 42): for count in range(0, 42):
self.send_data(self.EPD_4IN2_4Gray_lut_ww[count]) self.send_data(self.EPD_4IN2_4Gray_lut_ww[count])
def init(self): def init(self):
if (epdconfig.module_init() != 0): if (epdconfig.module_init() != 0):
return -1 return -1
@@ -264,7 +264,8 @@ class EPD:
self.send_data(0x28) self.send_data(0x28)
self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING 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.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() self.set_lut()
# EPD hardware init end # EPD hardware init end
@@ -276,61 +277,61 @@ class EPD:
# EPD hardware init start # EPD hardware init start
self.reset() self.reset()
self.send_command(0x01) #POWER SETTING self.send_command(0x01) # POWER SETTING
self.send_data (0x03) self.send_data(0x03)
self.send_data (0x00) #VGH=20V,VGL=-20V self.send_data(0x00) # VGH=20V,VGL=-20V
self.send_data (0x2b) #VDH=15V self.send_data(0x2b) # VDH=15V
self.send_data (0x2b) #VDL=-15V self.send_data(0x2b) # VDL=-15V
self.send_data (0x13) self.send_data(0x13)
self.send_command(0x06) #booster soft start self.send_command(0x06) # booster soft start
self.send_data (0x17) #A self.send_data(0x17) # A
self.send_data (0x17) #B self.send_data(0x17) # B
self.send_data (0x17) #C self.send_data(0x17) # C
self.send_command(0x04) self.send_command(0x04)
self.ReadBusy() self.ReadBusy()
self.send_command(0x00) #panel setting self.send_command(0x00) # panel setting
self.send_data(0x3f) #KW-3f KWR-2F BWROTP 0f BWOTP 1f self.send_data(0x3f) # KW-3f KWR-2F BWROTP 0f BWOTP 1f
self.send_command(0x30) #PLL setting self.send_command(0x30) # PLL setting
self.send_data (0x3c) #100hz self.send_data(0x3c) # 100hz
self.send_command(0x61) #resolution setting self.send_command(0x61) # resolution setting
self.send_data (0x01) #400 self.send_data(0x01) # 400
self.send_data (0x90) self.send_data(0x90)
self.send_data (0x01) #300 self.send_data(0x01) # 300
self.send_data (0x2c) self.send_data(0x2c)
self.send_command(0x82) #vcom_DC setting self.send_command(0x82) # vcom_DC setting
self.send_data (0x12) self.send_data(0x12)
self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING
self.send_data(0x97) self.send_data(0x97)
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def getbuffer_4Gray(self, image): def getbuffer_4Gray(self, image):
@@ -339,34 +340,38 @@ class EPD:
image_monocolor = image.convert('L') image_monocolor = image.convert('L')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
i=0 i = 0
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if(pixels[x, y] == 0xC0): if (pixels[x, y] == 0xC0):
pixels[x, y] = 0x80 pixels[x, y] = 0x80
elif (pixels[x, y] == 0x80): elif (pixels[x, y] == 0x80):
pixels[x, y] = 0x40 pixels[x, y] = 0x40
i= i+1 i = i + 1
if(i%4 == 0): 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) 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): elif (imwidth == self.height and imheight == self.width):
logging.debug("Horizontal") logging.debug("Horizontal")
for x in range(imwidth): for x in range(imwidth):
for y in range(imheight): for y in range(imheight):
newx = y newx = y
newy = x newy = x
if(pixels[x, y] == 0xC0): if (pixels[x, y] == 0xC0):
pixels[x, y] = 0x80 pixels[x, y] = 0x80
elif (pixels[x, y] == 0x80): elif (pixels[x, y] == 0x80):
pixels[x, y] = 0x40 pixels[x, y] = 0x40
i= i+1 i = i + 1
if(i%4 == 0): 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) 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 return buf
@@ -385,65 +390,65 @@ class EPD:
def display_4Gray(self, image): def display_4Gray(self, image):
self.send_command(0x10) self.send_command(0x10)
for i in range(0, EPD_WIDTH * EPD_HEIGHT / 8): # EPD_WIDTH * EPD_HEIGHT / 4 for i in range(0, EPD_WIDTH * EPD_HEIGHT / 8): # EPD_WIDTH * EPD_HEIGHT / 4
temp3=0 temp3 = 0
for j in range(0, 2): for j in range(0, 2):
temp1 = image[i*2+j] temp1 = image[i * 2 + j]
for k in range(0, 2): for k in range(0, 2):
temp2 = temp1&0xC0 temp2 = temp1 & 0xC0
if(temp2 == 0xC0): if (temp2 == 0xC0):
temp3 |= 0x01#white temp3 |= 0x01 # white
elif(temp2 == 0x00): elif (temp2 == 0x00):
temp3 |= 0x00 #black temp3 |= 0x00 # black
elif(temp2 == 0x80): elif (temp2 == 0x80):
temp3 |= 0x01 #gray1 temp3 |= 0x01 # gray1
else: #0x40 else: # 0x40
temp3 |= 0x00 #gray2 temp3 |= 0x00 # gray2
temp3 <<= 1 temp3 <<= 1
temp1 <<= 2 temp1 <<= 2
temp2 = temp1&0xC0 temp2 = temp1 & 0xC0
if(temp2 == 0xC0): #white if (temp2 == 0xC0): # white
temp3 |= 0x01 temp3 |= 0x01
elif(temp2 == 0x00): #black elif (temp2 == 0x00): # black
temp3 |= 0x00 temp3 |= 0x00
elif(temp2 == 0x80): elif (temp2 == 0x80):
temp3 |= 0x01 #gray1 temp3 |= 0x01 # gray1
else : #0x40 else: # 0x40
temp3 |= 0x00 #gray2 temp3 |= 0x00 # gray2
if(j!=1 or k!=1): if (j != 1 or k != 1):
temp3 <<= 1 temp3 <<= 1
temp1 <<= 2 temp1 <<= 2
self.send_data(temp3) self.send_data(temp3)
self.send_command(0x13) self.send_command(0x13)
for i in range(0, EPD_WIDTH * EPD_HEIGHT / 8): #5808*4 46464 for i in range(0, EPD_WIDTH * EPD_HEIGHT / 8): # 5808*4 46464
temp3=0 temp3 = 0
for j in range(0, 2): for j in range(0, 2):
temp1 = image[i*2+j] temp1 = image[i * 2 + j]
for k in range(0, 2): for k in range(0, 2):
temp2 = temp1&0xC0 temp2 = temp1 & 0xC0
if(temp2 == 0xC0): if (temp2 == 0xC0):
temp3 |= 0x01#white temp3 |= 0x01 # white
elif(temp2 == 0x00): elif (temp2 == 0x00):
temp3 |= 0x00 #black temp3 |= 0x00 # black
elif(temp2 == 0x80): elif (temp2 == 0x80):
temp3 |= 0x00 #gray1 temp3 |= 0x00 # gray1
else: #0x40 else: # 0x40
temp3 |= 0x01 #gray2 temp3 |= 0x01 # gray2
temp3 <<= 1 temp3 <<= 1
temp1 <<= 2 temp1 <<= 2
temp2 = temp1&0xC0 temp2 = temp1 & 0xC0
if(temp2 == 0xC0): #white if (temp2 == 0xC0): # white
temp3 |= 0x01 temp3 |= 0x01
elif(temp2 == 0x00): #black elif (temp2 == 0x00): # black
temp3 |= 0x00 temp3 |= 0x00
elif(temp2 == 0x80): elif (temp2 == 0x80):
temp3 |= 0x00 #gray1 temp3 |= 0x00 # gray1
else: #0x40 else: # 0x40
temp3 |= 0x01 #gray2 temp3 |= 0x01 # gray2
if(j!=1 or k!=1): if (j != 1 or k != 1):
temp3 <<= 1 temp3 <<= 1
temp1 <<= 2 temp1 <<= 2
self.send_data(temp3) self.send_data(temp3)
@@ -475,4 +480,3 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -34,6 +34,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 400 EPD_WIDTH = 400
EPD_HEIGHT = 300 EPD_HEIGHT = 300
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -48,7 +49,8 @@ class EPD:
epdconfig.digital_write(self.reset_pin, 1) epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200) epdconfig.delay_ms(200)
epdconfig.digital_write(self.reset_pin, 0) epdconfig.digital_write(self.reset_pin, 0)
epdconfig.delay_ms(5) # support v2 displays in favor of v1 displays.Change this to 10 for legacy v1 display support epdconfig.delay_ms(
5) # support v2 displays in favor of v1 displays.Change this to 10 for legacy v1 display support
epdconfig.digital_write(self.reset_pin, 1) epdconfig.digital_write(self.reset_pin, 1)
epdconfig.delay_ms(200) epdconfig.delay_ms(200)
@@ -66,7 +68,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy while (epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100) epdconfig.delay_ms(100)
logging.debug("e-Paper busy release") logging.debug("e-Paper busy release")
@@ -77,9 +79,9 @@ class EPD:
self.reset() self.reset()
self.send_command(0x06) # BOOSTER_SOFT_START self.send_command(0x06) # BOOSTER_SOFT_START
self.send_data (0x17) self.send_data(0x17)
self.send_data (0x17) self.send_data(0x17)
self.send_data (0x17) # 07 0f 17 1f 27 2F 37 2f self.send_data(0x17) # 07 0f 17 1f 27 2F 37 2f
self.send_command(0x04) # POWER_ON self.send_command(0x04) # POWER_ON
self.ReadBusy() self.ReadBusy()
@@ -91,26 +93,26 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, imageblack, imagered): def display(self, imageblack, imagered):
@@ -145,4 +147,3 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -35,6 +35,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 600 EPD_WIDTH = 600
EPD_HEIGHT = 448 EPD_HEIGHT = 448
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -67,7 +68,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy while (epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100) epdconfig.delay_ms(100)
logging.debug("e-Paper busy release") logging.debug("e-Paper busy release")
@@ -125,8 +126,8 @@ class EPD:
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) logging.debug('imwidth = %d imheight = %d ', imwidth, imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
@@ -137,18 +138,18 @@ class EPD:
buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2)
else: # white else: # white
buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2)
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] < 64: # black if pixels[x, y] < 64: # black
buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) buf[int((newx + newy * self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2))
elif pixels[x, y] < 192: # convert gray to red 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)] &= ~(0xC0 >> (y % 4 * 2))
buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2) buf[int((newx + newy * self.width) / 4)] |= 0x40 >> (y % 4 * 2)
else: # white else: # white
buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2) buf[int((newx + newy * self.width) / 4)] |= 0xC0 >> (y % 4 * 2)
return buf return buf
def display(self, image): def display(self, image):
@@ -166,7 +167,7 @@ class EPD:
temp2 = (temp2 << 4) & 0xFF temp2 = (temp2 << 4) & 0xFF
temp1 = (temp1 << 2) & 0xFF temp1 = (temp1 << 2) & 0xFF
j += 1 j += 1
if((temp1 & 0xC0) == 0xC0): if ((temp1 & 0xC0) == 0xC0):
temp2 |= 0x03 temp2 |= 0x03
elif ((temp1 & 0xC0) == 0x00): elif ((temp1 & 0xC0) == 0x00):
temp2 |= 0x00 temp2 |= 0x00
@@ -196,5 +197,4 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -35,6 +35,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 600 EPD_WIDTH = 600
EPD_HEIGHT = 448 EPD_HEIGHT = 448
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -67,7 +68,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy while (epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100) epdconfig.delay_ms(100)
logging.debug("e-Paper busy release") logging.debug("e-Paper busy release")
@@ -118,26 +119,26 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) logging.debug('imwidth = %d imheight = %d ', imwidth, imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, imageblack, imagered): def display(self, imageblack, imagered):
@@ -148,22 +149,22 @@ class EPD:
j = 0 j = 0
while (j < 8): while (j < 8):
if ((temp2 & 0x80) == 0x00): if ((temp2 & 0x80) == 0x00):
temp3 = 0x04 #red temp3 = 0x04 # red
elif ((temp1 & 0x80) == 0x00): elif ((temp1 & 0x80) == 0x00):
temp3 = 0x00 #black temp3 = 0x00 # black
else: else:
temp3 = 0x03 #white temp3 = 0x03 # white
temp3 = (temp3 << 4) & 0xFF temp3 = (temp3 << 4) & 0xFF
temp1 = (temp1 << 1) & 0xFF temp1 = (temp1 << 1) & 0xFF
temp2 = (temp2 << 1) & 0xFF temp2 = (temp2 << 1) & 0xFF
j += 1 j += 1
if((temp2 & 0x80) == 0x00): if ((temp2 & 0x80) == 0x00):
temp3 |= 0x04 #red temp3 |= 0x04 # red
elif ((temp1 & 0x80) == 0x00): elif ((temp1 & 0x80) == 0x00):
temp3 |= 0x00 #black temp3 |= 0x00 # black
else: else:
temp3 |= 0x03 #white temp3 |= 0x03 # white
temp1 = (temp1 << 1) & 0xFF temp1 = (temp1 << 1) & 0xFF
temp2 = (temp2 << 1) & 0xFF temp2 = (temp2 << 1) & 0xFF
self.send_data(temp3) self.send_data(temp3)
@@ -197,4 +198,3 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -35,6 +35,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 640 EPD_WIDTH = 640
EPD_HEIGHT = 384 EPD_HEIGHT = 384
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -67,7 +68,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy while (epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100) epdconfig.delay_ms(100)
logging.debug("e-Paper busy release") logging.debug("e-Paper busy release")
@@ -106,9 +107,9 @@ class EPD:
self.send_data(0x22) self.send_data(0x22)
self.send_command(0x61) # TCON_RESOLUTION self.send_command(0x61) # TCON_RESOLUTION
self.send_data(EPD_WIDTH >> 8) #source 640 self.send_data(EPD_WIDTH >> 8) # source 640
self.send_data(EPD_WIDTH & 0xff) self.send_data(EPD_WIDTH & 0xff)
self.send_data(EPD_HEIGHT >> 8) #gate 384 self.send_data(EPD_HEIGHT >> 8) # gate 384
self.send_data(EPD_HEIGHT & 0xff) self.send_data(EPD_HEIGHT & 0xff)
self.send_command(0x82) # VCM_DC_SETTING self.send_command(0x82) # VCM_DC_SETTING
@@ -126,8 +127,8 @@ class EPD:
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) logging.debug('imwidth = %d imheight = %d ', imwidth, imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
@@ -138,18 +139,18 @@ class EPD:
buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2) buf[int((x + y * self.width) / 4)] |= 0x40 >> (x % 4 * 2)
else: # white else: # white
buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2) buf[int((x + y * self.width) / 4)] |= 0xC0 >> (x % 4 * 2)
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] < 64: # black if pixels[x, y] < 64: # black
buf[int((newx + newy*self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2)) buf[int((newx + newy * self.width) / 4)] &= ~(0xC0 >> (y % 4 * 2))
elif pixels[x, y] < 192: # convert gray to red 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)] &= ~(0xC0 >> (y % 4 * 2))
buf[int((newx + newy*self.width) / 4)] |= 0x40 >> (y % 4 * 2) buf[int((newx + newy * self.width) / 4)] |= 0x40 >> (y % 4 * 2)
else: # white else: # white
buf[int((newx + newy*self.width) / 4)] |= 0xC0 >> (y % 4 * 2) buf[int((newx + newy * self.width) / 4)] |= 0xC0 >> (y % 4 * 2)
return buf return buf
def display(self, image): def display(self, image):
@@ -167,7 +168,7 @@ class EPD:
temp2 = (temp2 << 4) & 0xFF temp2 = (temp2 << 4) & 0xFF
temp1 = (temp1 << 2) & 0xFF temp1 = (temp1 << 2) & 0xFF
j += 1 j += 1
if((temp1 & 0xC0) == 0xC0): if ((temp1 & 0xC0) == 0xC0):
temp2 |= 0x03 temp2 |= 0x03
elif ((temp1 & 0xC0) == 0x00): elif ((temp1 & 0xC0) == 0x00):
temp2 |= 0x00 temp2 |= 0x00
@@ -199,4 +200,3 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -35,6 +35,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 640 EPD_WIDTH = 640
EPD_HEIGHT = 384 EPD_HEIGHT = 384
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -67,7 +68,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy while (epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
epdconfig.delay_ms(100) epdconfig.delay_ms(100)
logging.debug("e-Paper busy release") logging.debug("e-Paper busy release")
@@ -89,7 +90,7 @@ class EPD:
self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A
self.send_command(0x82) # VCM_DC_SETTING self.send_command(0x82) # VCM_DC_SETTING
self.send_data(0x28) #all temperature range self.send_data(0x28) # all temperature range
self.send_command(0x06) # BOOSTER_SOFT_START self.send_command(0x06) # BOOSTER_SOFT_START
self.send_data(0xc7) self.send_data(0xc7)
@@ -118,26 +119,26 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) logging.debug('imwidth = %d imheight = %d ', imwidth, imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, imageblack, imagered): def display(self, imageblack, imagered):
@@ -148,22 +149,22 @@ class EPD:
j = 0 j = 0
while (j < 8): while (j < 8):
if ((temp2 & 0x80) == 0x00): if ((temp2 & 0x80) == 0x00):
temp3 = 0x04 #red temp3 = 0x04 # red
elif ((temp1 & 0x80) == 0x00): elif ((temp1 & 0x80) == 0x00):
temp3 = 0x00 #black temp3 = 0x00 # black
else: else:
temp3 = 0x03 #white temp3 = 0x03 # white
temp3 = (temp3 << 4) & 0xFF temp3 = (temp3 << 4) & 0xFF
temp1 = (temp1 << 1) & 0xFF temp1 = (temp1 << 1) & 0xFF
temp2 = (temp2 << 1) & 0xFF temp2 = (temp2 << 1) & 0xFF
j += 1 j += 1
if((temp2 & 0x80) == 0x00): if ((temp2 & 0x80) == 0x00):
temp3 |= 0x04 #red temp3 |= 0x04 # red
elif ((temp1 & 0x80) == 0x00): elif ((temp1 & 0x80) == 0x00):
temp3 |= 0x00 #black temp3 |= 0x00 # black
else: else:
temp3 |= 0x03 #white temp3 |= 0x03 # white
temp1 = (temp1 << 1) & 0xFF temp1 = (temp1 << 1) & 0xFF
temp2 = (temp2 << 1) & 0xFF temp2 = (temp2 << 1) & 0xFF
self.send_data(temp3) self.send_data(temp3)
@@ -198,4 +199,3 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -35,6 +35,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 800 EPD_WIDTH = 800
EPD_HEIGHT = 480 EPD_HEIGHT = 480
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -69,7 +70,7 @@ class EPD:
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
self.send_command(0x71) self.send_command(0x71)
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
while(busy == 0): while (busy == 0):
self.send_command(0x71) self.send_command(0x71)
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
epdconfig.delay_ms(200) epdconfig.delay_ms(200)
@@ -80,33 +81,33 @@ class EPD:
# EPD hardware init start # EPD hardware init start
self.reset() self.reset()
self.send_command(0x01) #POWER SETTING self.send_command(0x01) # POWER SETTING
self.send_data(0x07) self.send_data(0x07)
self.send_data(0x07) #VGH=20V,VGL=-20V self.send_data(0x07) # VGH=20V,VGL=-20V
self.send_data(0x3f) #VDH=15V self.send_data(0x3f) # VDH=15V
self.send_data(0x3f) #VDL=-15V self.send_data(0x3f) # VDL=-15V
self.send_command(0x04) #POWER ON self.send_command(0x04) # POWER ON
epdconfig.delay_ms(100) epdconfig.delay_ms(100)
self.ReadBusy() self.ReadBusy()
self.send_command(0X00) #PANNEL SETTING self.send_command(0X00) # PANNEL SETTING
self.send_data(0x1F) #KW-3f KWR-2F BWROTP 0f BWOTP 1f self.send_data(0x1F) # KW-3f KWR-2F BWROTP 0f BWOTP 1f
self.send_command(0x61) #tres self.send_command(0x61) # tres
self.send_data(0x03) #source 800 self.send_data(0x03) # source 800
self.send_data(0x20) self.send_data(0x20)
self.send_data(0x01) #gate 480 self.send_data(0x01) # gate 480
self.send_data(0xE0) self.send_data(0xE0)
self.send_command(0X15) self.send_command(0X15)
self.send_data(0x00) self.send_data(0x00)
self.send_command(0X50) #VCOM AND DATA INTERVAL SETTING self.send_command(0X50) # VCOM AND DATA INTERVAL SETTING
self.send_data(0x10) self.send_data(0x10)
self.send_data(0x07) self.send_data(0x07)
self.send_command(0X60) #TCON SETTING self.send_command(0X60) # TCON SETTING
self.send_data(0x22) self.send_data(0x22)
# EPD hardware init end # EPD hardware init end
@@ -114,26 +115,26 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, image): def display(self, image):
@@ -167,4 +168,3 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -35,6 +35,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 800 EPD_WIDTH = 800
EPD_HEIGHT = 480 EPD_HEIGHT = 480
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -69,7 +70,7 @@ class EPD:
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
self.send_command(0x71) self.send_command(0x71)
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
while(busy == 0): while (busy == 0):
self.send_command(0x71) self.send_command(0x71)
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
epdconfig.delay_ms(200) epdconfig.delay_ms(200)
@@ -80,59 +81,59 @@ class EPD:
self.reset() self.reset()
self.send_command(0x01); #POWER SETTING self.send_command(0x01); # POWER SETTING
self.send_data(0x07); self.send_data(0x07);
self.send_data(0x07); #VGH=20V,VGL=-20V self.send_data(0x07); # VGH=20V,VGL=-20V
self.send_data(0x3f); #VDH=15V self.send_data(0x3f); # VDH=15V
self.send_data(0x3f); #VDL=-15V self.send_data(0x3f); # VDL=-15V
self.send_command(0x04); #POWER ON self.send_command(0x04); # POWER ON
epdconfig.delay_ms(100); epdconfig.delay_ms(100);
self.ReadBusy(); self.ReadBusy();
self.send_command(0X00); #PANNEL SETTING self.send_command(0X00); # PANNEL SETTING
self.send_data(0x0F); #KW-3f KWR-2F BWROTP 0f BWOTP 1f self.send_data(0x0F); # KW-3f KWR-2F BWROTP 0f BWOTP 1f
self.send_command(0x61); #tres self.send_command(0x61); # tres
self.send_data(0x03); #source 800 self.send_data(0x03); # source 800
self.send_data(0x20); self.send_data(0x20);
self.send_data(0x01); #gate 480 self.send_data(0x01); # gate 480
self.send_data(0xE0); self.send_data(0xE0);
self.send_command(0X15); self.send_command(0X15);
self.send_data(0x00); self.send_data(0x00);
self.send_command(0X50); #VCOM AND DATA INTERVAL SETTING self.send_command(0X50); # VCOM AND DATA INTERVAL SETTING
self.send_data(0x11); self.send_data(0x11);
self.send_data(0x07); self.send_data(0x07);
self.send_command(0X60); #TCON SETTING self.send_command(0X60); # TCON SETTING
self.send_data(0x22); self.send_data(0x22);
return 0 return 0
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) logging.debug('imwidth = %d imheight = %d ', imwidth, imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, imageblack, imagered): def display(self, imageblack, imagered):
@@ -170,4 +171,3 @@ class EPD:
epdconfig.module_exit() epdconfig.module_exit()
### END OF FILE ### ### END OF FILE ###

View File

@@ -35,6 +35,7 @@ from . import epdconfig
EPD_WIDTH = 880 EPD_WIDTH = 880
EPD_HEIGHT = 528 EPD_HEIGHT = 528
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -68,7 +69,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
while(busy == 1): while (busy == 1):
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
epdconfig.delay_ms(200) epdconfig.delay_ms(200)
@@ -79,7 +80,7 @@ class EPD:
self.reset() self.reset()
self.ReadBusy(); self.ReadBusy();
self.send_command(0x12); #SWRESET self.send_command(0x12); # SWRESET
self.ReadBusy(); self.ReadBusy();
self.send_command(0x46); # Auto Write Red RAM self.send_command(0x46); # Auto Write Red RAM
@@ -96,11 +97,10 @@ class EPD:
self.send_data(0xC0); self.send_data(0xC0);
self.send_data(0x40); self.send_data(0x40);
self.send_command(0x01); # Set MUX as 527 self.send_command(0x01); # Set MUX as 527
self.send_data(0xAF); self.send_data(0xAF);
self.send_data(0x02); self.send_data(0x02);
self.send_data(0x01);#0x01 self.send_data(0x01); # 0x01
self.send_command(0x11); # Data entry mode self.send_command(0x11); # Data entry mode
self.send_data(0x01); self.send_data(0x01);
@@ -122,9 +122,8 @@ class EPD:
self.send_command(0x18); self.send_command(0x18);
self.send_data(0X80); self.send_data(0X80);
self.send_command(0x22); self.send_command(0x22);
self.send_data(0XB1); #Load Temperature and waveform setting. self.send_data(0XB1); # Load Temperature and waveform setting.
self.send_command(0x20); self.send_command(0x20);
self.ReadBusy(); self.ReadBusy();
@@ -139,26 +138,26 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
# logging.debug("imwidth = %d, imheight = %d",imwidth,imheight) # logging.debug("imwidth = %d, imheight = %d",imwidth,imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, image): def display(self, image):
@@ -170,7 +169,7 @@ class EPD:
self.send_data(image[i]); self.send_data(image[i]);
self.send_command(0x22); self.send_command(0x22);
self.send_data(0xF7);#Load LUT from MCU(0x32) self.send_data(0xF7); # Load LUT from MCU(0x32)
self.send_command(0x20); self.send_command(0x20);
epdconfig.delay_ms(10); epdconfig.delay_ms(10);
self.ReadBusy(); self.ReadBusy();
@@ -188,7 +187,7 @@ class EPD:
self.send_data(0xff) self.send_data(0xff)
self.send_command(0x22); self.send_command(0x22);
self.send_data(0xF7);#Load LUT from MCU(0x32) self.send_data(0xF7); # Load LUT from MCU(0x32)
self.send_command(0x20); self.send_command(0x20);
epdconfig.delay_ms(10); epdconfig.delay_ms(10);
self.ReadBusy(); self.ReadBusy();

View File

@@ -35,6 +35,7 @@ from inkycal.display.drivers import epdconfig
EPD_WIDTH = 880 EPD_WIDTH = 880
EPD_HEIGHT = 528 EPD_HEIGHT = 528
class EPD: class EPD:
def __init__(self): def __init__(self):
self.reset_pin = epdconfig.RST_PIN self.reset_pin = epdconfig.RST_PIN
@@ -68,7 +69,7 @@ class EPD:
def ReadBusy(self): def ReadBusy(self):
logging.debug("e-Paper busy") logging.debug("e-Paper busy")
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
while(busy == 1): while (busy == 1):
busy = epdconfig.digital_read(self.busy_pin) busy = epdconfig.digital_read(self.busy_pin)
epdconfig.delay_ms(200) epdconfig.delay_ms(200)
@@ -78,16 +79,16 @@ class EPD:
self.reset() self.reset()
self.send_command(0x12); #SWRESET self.send_command(0x12); # SWRESET
self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x46); # Auto Write RAM self.send_command(0x46); # Auto Write RAM
self.send_data(0xF7); self.send_data(0xF7);
self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x47); # Auto Write RAM self.send_command(0x47); # Auto Write RAM
self.send_data(0xF7); self.send_data(0xF7);
self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x0C); # Soft start setting self.send_command(0x0C); # Soft start setting
self.send_data(0xAE); self.send_data(0xAE);
@@ -121,9 +122,9 @@ class EPD:
self.send_command(0x18); self.send_command(0x18);
self.send_data(0X80); self.send_data(0X80);
self.send_command(0x22); self.send_command(0x22);
self.send_data(0XB1); #Load Temperature and waveform setting. self.send_data(0XB1); # Load Temperature and waveform setting.
self.send_command(0x20); self.send_command(0x20);
self.ReadBusy(); #waiting for the electronic paper IC to release the idle signal self.ReadBusy(); # waiting for the electronic paper IC to release the idle signal
self.send_command(0x4E); self.send_command(0x4E);
self.send_data(0x00); self.send_data(0x00);
@@ -136,26 +137,26 @@ class EPD:
def getbuffer(self, image): def getbuffer(self, image):
# logging.debug("bufsiz = ",int(self.width/8) * self.height) # logging.debug("bufsiz = ",int(self.width/8) * self.height)
buf = [0xFF] * (int(self.width/8) * self.height) buf = [0xFF] * (int(self.width / 8) * self.height)
image_monocolor = image.convert('1') image_monocolor = image.convert('1')
imwidth, imheight = image_monocolor.size imwidth, imheight = image_monocolor.size
pixels = image_monocolor.load() pixels = image_monocolor.load()
logging.debug('imwidth = %d imheight = %d ',imwidth, imheight) logging.debug('imwidth = %d imheight = %d ', imwidth, imheight)
if(imwidth == self.width and imheight == self.height): if (imwidth == self.width and imheight == self.height):
logging.debug("Horizontal") logging.debug("Horizontal")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
# Set the bits for the column of pixels at the current position. # Set the bits for the column of pixels at the current position.
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8)) buf[int((x + y * self.width) / 8)] &= ~(0x80 >> (x % 8))
elif(imwidth == self.height and imheight == self.width): elif (imwidth == self.height and imheight == self.width):
logging.debug("Vertical") logging.debug("Vertical")
for y in range(imheight): for y in range(imheight):
for x in range(imwidth): for x in range(imwidth):
newx = y newx = y
newy = self.height - x - 1 newy = self.height - x - 1
if pixels[x, y] == 0: if pixels[x, y] == 0:
buf[int((newx + newy*self.width) / 8)] &= ~(0x80 >> (y % 8)) buf[int((newx + newy * self.width) / 8)] &= ~(0x80 >> (y % 8))
return buf return buf
def display(self, imageblack, imagered): def display(self, imageblack, imagered):
@@ -166,15 +167,14 @@ class EPD:
for i in range(0, int(self.width * self.height / 8)): for i in range(0, int(self.width * self.height / 8)):
self.send_data(imageblack[i]); self.send_data(imageblack[i]);
self.send_command(0x26) self.send_command(0x26)
for i in range(0, int(self.width * self.height / 8)): for i in range(0, int(self.width * self.height / 8)):
self.send_data(~imagered[i]); self.send_data(~imagered[i]);
self.send_command(0x22); self.send_command(0x22);
self.send_data(0xC7); #Load LUT from MCU(0x32) self.send_data(0xC7); # Load LUT from MCU(0x32)
self.send_command(0x20); self.send_command(0x20);
epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! epdconfig.delay_ms(200); # !!!The delay here is necessary, 200uS at least!!!
self.ReadBusy(); self.ReadBusy();
def Clear(self): def Clear(self):
@@ -185,19 +185,18 @@ class EPD:
for i in range(0, int(self.width * self.height / 8)): for i in range(0, int(self.width * self.height / 8)):
self.send_data(0xff); self.send_data(0xff);
self.send_command(0x26) self.send_command(0x26)
for i in range(0, int(self.width * self.height / 8)): for i in range(0, int(self.width * self.height / 8)):
self.send_data(0x00); self.send_data(0x00);
self.send_command(0x22); self.send_command(0x22);
self.send_data(0xC7); #Load LUT from MCU(0x32) self.send_data(0xC7); # Load LUT from MCU(0x32)
self.send_command(0x20); self.send_command(0x20);
epdconfig.delay_ms(200); #!!!The delay here is necessary, 200uS at least!!! epdconfig.delay_ms(200); # !!!The delay here is necessary, 200uS at least!!!
self.ReadBusy(); self.ReadBusy();
def sleep(self): def sleep(self):
self.send_command(0x10); #deep sleep self.send_command(0x10); # deep sleep
self.send_data(0x01); self.send_data(0x01);
epdconfig.module_exit() epdconfig.module_exit()

View File

@@ -35,6 +35,7 @@ import time
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class RaspberryPi: class RaspberryPi:
# Pin definition # Pin definition
RST_PIN = 17 RST_PIN = 17
@@ -76,7 +77,7 @@ class RaspberryPi:
def module_exit(self): def module_exit(self):
logger.debug("spi end") logger.debug("spi end")
#self.SPI.close() #removed as it causes some problems # self.SPI.close() #removed as it causes some problems
logger.debug("close 5V, Module enters 0 power consumption ...") logger.debug("close 5V, Module enters 0 power consumption ...")
self.GPIO.output(self.RST_PIN, 0) self.GPIO.output(self.RST_PIN, 0)
@@ -152,5 +153,4 @@ else:
for func in [x for x in dir(implementation) if not x.startswith('_')]: for func in [x for x in dir(implementation) if not x.startswith('_')]:
setattr(sys.modules[__name__], func, getattr(implementation, func)) setattr(sys.modules[__name__], func, getattr(implementation, func))
### END OF FILE ### ### END OF FILE ###

View File

@@ -7,4 +7,4 @@ from .inkycal_image import Inkyimage
from .inkycal_jokes import Jokes from .inkycal_jokes import Jokes
from .inkycal_stocks import Stocks from .inkycal_stocks import Stocks
from .inkycal_slideshow import Slideshow from .inkycal_slideshow import Slideshow
#from .inkycal_server import Inkyserver # from .inkycal_server import Inkyserver

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Third party module template (inkycal-compatible module) Third party module template (inkycal-compatible module)
@@ -13,7 +13,6 @@ Copyright by aceisace
from inkycal.modules.template import inkycal_module from inkycal.modules.template import inkycal_module
from inkycal.custom import * from inkycal.custom import *
############################################################################# #############################################################################
# Built-in library imports (change as desired) # Built-in library imports (change as desired)
############################################################################# #############################################################################
@@ -21,7 +20,6 @@ from inkycal.custom import *
# Built-in libraries go here # Built-in libraries go here
from random import shuffle from random import shuffle
############################################################################# #############################################################################
# External library imports (always use try-except) # External library imports (always use try-except)
############################################################################# #############################################################################
@@ -35,7 +33,6 @@ except ImportError:
print('feedparser is not installed! Please install with:') print('feedparser is not installed! Please install with:')
print('pip3 install feedparser') print('pip3 install feedparser')
############################################################################# #############################################################################
# Filename + logging (do not remove) # Filename + logging (do not remove)
############################################################################# #############################################################################
@@ -44,6 +41,7 @@ except ImportError:
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
############################################################################# #############################################################################
# Class setup # Class setup
############################################################################# #############################################################################
@@ -65,7 +63,7 @@ class Simple(inkycal_module):
# to run correctly, e.g. if your module needs an 'api-key' and a 'name': # to run correctly, e.g. if your module needs an 'api-key' and a 'name':
requires = { requires = {
# A simple text input; users can choose what to enter by keyboard # A simple text input; users can choose what to enter by keyboard
'api_key': {"label" : "Please enter your api-key from some-website"}, 'api_key': {"label": "Please enter your api-key from some-website"},
# A simple text input; users can choose what to enter by keyboard # A simple text input; users can choose what to enter by keyboard
'username': {"label": "Please enter a username"}, 'username': {"label": "Please enter a username"},
@@ -102,6 +100,7 @@ class Simple(inkycal_module):
"default": True, "default": True,
}, },
} }
######################################################################## ########################################################################
# Initialise the class (do not remove) # Initialise the class (do not remove)
@@ -130,26 +129,26 @@ class Simple(inkycal_module):
self.api_key = config['api_key'] self.api_key = config['api_key']
# if you need a integer (number) input, you have to convert this to a int # if you need a integer (number) input, you have to convert this to a int
#-----------------------------------------------------------------------# # -----------------------------------------------------------------------#
# bad example :/ # bad example :/
self.age = int( config["age"] ) self.age = int(config["age"])
# Remember age was a optional parameter? What if no age was entered # Remember age was a optional parameter? What if no age was entered
# and there is no fallback value? Then the age would be None. # and there is no fallback value? Then the age would be None.
# This would cause crashing right here # This would cause crashing right here
# good example :) # good example :)
if config["age"] and isinstance(config["age"], str): if config["age"] and isinstance(config["age"], str):
self.age = int( config["age"] ) self.age = int(config["age"])
else: else:
self.age = 10 # just a joke, no offense self.age = 10 # just a joke, no offense
# -> Check if age was entered and if it's a string (entered via web-UI) # -> Check if age was entered and if it's a string (entered via web-UI)
# If something was entered for age, convert it to a number # If something was entered for age, convert it to a number
# The else statement is executed when nothing was entered for age # The else statement is executed when nothing was entered for age
# You could assign a custom value now or print something. # You could assign a custom value now or print something.
#-----------------------------------------------------------------------# # -----------------------------------------------------------------------#
# if you need a list of words, you have to convert the string to a list # if you need a list of words, you have to convert the string to a list
#-----------------------------------------------------------------------# # -----------------------------------------------------------------------#
# good example :) # good example :)
if config["hobbies"] and isinstance(config["hobbies"], str): if config["hobbies"] and isinstance(config["hobbies"], str):
self.hobbies = config["age"].split(",") self.hobbies = config["age"].split(",")
@@ -157,14 +156,14 @@ class Simple(inkycal_module):
# even if a single value was entered, it will be converted to a list # even if a single value was entered, it will be converted to a list
else: else:
self.hobbies = [] # empty list if nothing was entered by user self.hobbies = [] # empty list if nothing was entered by user
#-----------------------------------------------------------------------# # -----------------------------------------------------------------------#
# give an OK message # give an OK message
print(f'{filename} loaded') print(f'{filename} loaded')
############################################################################# #############################################################################
# Validation of module specific parameters (optional) # # Validation of module specific parameters (optional) #
############################################################################# #############################################################################
def _validate(self): def _validate(self):
"""Validate module-specific parameters""" """Validate module-specific parameters"""
@@ -175,10 +174,9 @@ class Simple(inkycal_module):
if not isinstance(self.age, int): if not isinstance(self.age, int):
print(f"age has to be a number, but given value is {self.age}") print(f"age has to be a number, but given value is {self.age}")
#############################################################################
############################################################################# # Generating the image #
# Generating the image # #############################################################################
#############################################################################
def generate_image(self): def generate_image(self):
"""Generate image for this module""" """Generate image for this module"""
@@ -194,8 +192,8 @@ class Simple(inkycal_module):
logger.info('image size: {} x {} px'.format(im_width, im_height)) logger.info('image size: {} x {} px'.format(im_width, im_height))
# Create an image for black pixels and one for coloured pixels (required) # Create an image for black pixels and one for coloured pixels (required)
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
################################################################# #################################################################
@@ -215,7 +213,6 @@ class Simple(inkycal_module):
# If these aren't enough, take a look at python Pillow (imaging library)'s # If these aren't enough, take a look at python Pillow (imaging library)'s
# documentation. # documentation.
################################################################# #################################################################
# return the images ready for the display # return the images ready for the display
@@ -225,9 +222,6 @@ class Simple(inkycal_module):
if __name__ == '__main__': if __name__ == '__main__':
print('running {0} in standalone mode'.format(filename)) print('running {0} in standalone mode'.format(filename))
################################################################################ ################################################################################
# Last steps # Last steps
# Wow, you made your own module for the inkycal project! Amazing :D # Wow, you made your own module for the inkycal project! Amazing :D
@@ -248,4 +242,3 @@ if __name__ == '__main__':
# How do I now import my module? # How do I now import my module?
# from inkycal.modules import Class # from inkycal.modules import Class
# Where Class is the name of the class inside your module (e.g. Simple) # Where Class is the name of the class inside your module (e.g. Simple)

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
iCalendar (parsing) module for Inky-Calendar Project iCalendar (parsing) module for Inky-Calendar Project
Copyright by aceisace Copyright by aceisace
@@ -31,10 +31,10 @@ except ModuleNotFoundError:
print('icalendar library could not be found. Please install this with:') print('icalendar library could not be found. Please install this with:')
print('pip3 install icalendar') print('pip3 install icalendar')
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class iCalendar: class iCalendar:
"""iCalendar parsing moudule for inkycal. """iCalendar parsing moudule for inkycal.
Parses events from given iCalendar URLs / paths""" Parses events from given iCalendar URLs / paths"""
@@ -61,8 +61,7 @@ class iCalendar:
else: else:
ical = [auth_ical(url, username, password)] ical = [auth_ical(url, username, password)]
else: else:
raise Exception (f"Input: '{url}' is not a string or list!") raise Exception(f"Input: '{url}' is not a string or list!")
def auth_ical(url, uname, passwd): def auth_ical(url, uname, passwd):
"""Authorisation helper for protected ical files""" """Authorisation helper for protected ical files"""
@@ -95,7 +94,7 @@ class iCalendar:
ical = (Calendar.from_ical(ical_file.read())) ical = (Calendar.from_ical(ical_file.read()))
self.icalendars += ical self.icalendars += ical
else: else:
raise Exception (f"Input: '{filepath}' is not a string or list!") raise Exception(f"Input: '{filepath}' is not a string or list!")
logger.info('loaded iCalendars from filepaths') logger.info('loaded iCalendars from filepaths')
@@ -137,13 +136,12 @@ class iCalendar:
arrow.get(events.get('dtstart').dt).format('HH:mm') != '00:00') arrow.get(events.get('dtstart').dt).format('HH:mm') != '00:00')
else arrow.get(events.get('DTSTART').dt).replace(tzinfo=timezone), else arrow.get(events.get('DTSTART').dt).replace(tzinfo=timezone),
'end':arrow.get(events.get("DTEND").dt).to(timezone) if ( 'end': arrow.get(events.get("DTEND").dt).to(timezone) if (
arrow.get(events.get('dtstart').dt).format('HH:mm') != '00:00') arrow.get(events.get('dtstart').dt).format('HH:mm') != '00:00')
else arrow.get(events.get('DTEND').dt).replace(tzinfo=timezone) else arrow.get(events.get('DTEND').dt).replace(tzinfo=timezone)
} for ical in recurring_events for events in ical) } for ical in recurring_events for events in ical)
# if any recurring events were found, add them to parsed_events # if any recurring events were found, add them to parsed_events
if events: self.parsed_events += list(events) if events: self.parsed_events += list(events)
@@ -161,7 +159,6 @@ class iCalendar:
by_date = lambda event: event['begin'] by_date = lambda event: event['begin']
self.parsed_events.sort(key=by_date) self.parsed_events.sort(key=by_date)
def clear_events(self): def clear_events(self):
"""clear previously parsed events""" """clear previously parsed events"""

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Custom image class for Inkycal Project Custom image class for Inkycal Project
@@ -18,6 +18,7 @@ import logging
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Inkyimage: class Inkyimage:
"""Custom Imge class written for commonly used image operations. """Custom Imge class written for commonly used image operations.
""" """
@@ -63,7 +64,7 @@ class Inkyimage:
logger.info(f'width: {image.width}, height: {image.height}') logger.info(f'width: {image.width}, height: {image.height}')
image.convert(mode='RGBA') #convert to a more suitable format image.convert(mode='RGBA') # convert to a more suitable format
self.image = image self.image = image
logger.info('loaded Image') logger.info('loaded Image')
@@ -77,18 +78,18 @@ class Inkyimage:
"""Preview the image on gpicview (only works on Rapsbian with Desktop)""" """Preview the image on gpicview (only works on Rapsbian with Desktop)"""
if self._image_loaded(): if self._image_loaded():
path = '/home/pi/Desktop/' path = '/home/pi/Desktop/'
self.image.save(path+'temp.png') self.image.save(path + 'temp.png')
os.system("gpicview "+path+'temp.png') os.system("gpicview " + path + 'temp.png')
os.system('rm '+path+'temp.png') os.system('rm ' + path + 'temp.png')
@staticmethod @staticmethod
def preview(image): def preview(image):
""""Previews an image on gpicview (only works on Rapsbian with Desktop). """"Previews an image on gpicview (only works on Rapsbian with Desktop).
""" """
path = '/home/pi/Desktop/' path = '/home/pi/Desktop/'
image.save(path+'temp.png') image.save(path + 'temp.png')
os.system("gpicview "+path+'temp.png') os.system("gpicview " + path + 'temp.png')
os.system('rm '+path+'temp.png') os.system('rm ' + path + 'temp.png')
def _image_loaded(self): def _image_loaded(self):
"""returns True if image was loaded""" """returns True if image was loaded"""
@@ -111,7 +112,7 @@ class Inkyimage:
logger.error('Angle must be a multiple of 90') logger.error('Angle must be a multiple of 90')
return return
image = image.rotate(angle, expand = True) image = image.rotate(angle, expand=True)
self.image = image self.image = image
logger.info(f'flipped image by {angle} degrees') logger.info(f'flipped image by {angle} degrees')
@@ -160,7 +161,7 @@ class Inkyimage:
bg = Image.new('RGBA', (image.width, image.height), 'white') bg = Image.new('RGBA', (image.width, image.height), 'white')
im = Image.alpha_composite(bg, image) im = Image.alpha_composite(bg, image)
self.image.paste(im, (0,0)) self.image.paste(im, (0, 0))
logger.info('removed transparency') logger.info('removed transparency')
def resize(self, width=None, height=None): def resize(self, width=None, height=None):
@@ -175,8 +176,8 @@ class Inkyimage:
if width: if width:
initial_width = image.width initial_width = image.width
wpercent = (width/float(image.width)) wpercent = (width / float(image.width))
hsize = int((float(image.height)*float(wpercent))) hsize = int((float(image.height) * float(wpercent)))
image = image.resize((width, hsize), Image.ANTIALIAS) image = image.resize((width, hsize), Image.ANTIALIAS)
logger.info(f"resized image from {initial_width} to {image.width}") logger.info(f"resized image from {initial_width} to {image.width}")
self.image = image self.image = image
@@ -211,12 +212,11 @@ class Inkyimage:
return Image.fromarray(x) return Image.fromarray(x)
image2 = clear_white(image2) image2 = clear_white(image2)
image1.paste(image2, (0,0), image2) image1.paste(image2, (0, 0), image2)
logger.info('merged given images into one') logger.info('merged given images into one')
return image1 return image1
def to_palette(self, palette, dither=True): def to_palette(self, palette, dither=True):
"""Maps an image to a given colour palette. """Maps an image to a given colour palette.
@@ -246,11 +246,11 @@ class Inkyimage:
if palette == 'bwr': if palette == 'bwr':
# black-white-red palette # black-white-red palette
pal = [255,255,255, 0,0,0, 255,0,0] pal = [255, 255, 255, 0, 0, 0, 255, 0, 0]
elif palette == 'bwy': elif palette == 'bwy':
# black-white-yellow palette # black-white-yellow palette
pal = [255,255,255, 0,0,0, 255,255,0] pal = [255, 255, 255, 0, 0, 0, 255, 255, 0]
elif palette == 'bw': elif palette == 'bw':
pal = None pal = None
@@ -263,41 +263,41 @@ class Inkyimage:
# The palette needs to have 256 colors, for this, the black-colour # The palette needs to have 256 colors, for this, the black-colour
# is added until the # is added until the
colours = len(pal) // 3 colours = len(pal) // 3
#print(f'The palette has {colours} colours') # print(f'The palette has {colours} colours')
if 256 % colours != 0: if 256 % colours != 0:
#print('Filling palette with black') # print('Filling palette with black')
pal += (256 % colours) * [0,0,0] pal += (256 % colours) * [0, 0, 0]
#print(pal) # print(pal)
colours = len(pal) // 3 colours = len(pal) // 3
#print(f'The palette now has {colours} colours') # print(f'The palette now has {colours} colours')
# Create a dummy image to be used as a palette # Create a dummy image to be used as a palette
palette_im = Image.new('P', (1,1)) palette_im = Image.new('P', (1, 1))
# Attach the created palette. The palette should have 256 colours # Attach the created palette. The palette should have 256 colours
# equivalent to 768 integers # equivalent to 768 integers
palette_im.putpalette(pal* (256//colours)) palette_im.putpalette(pal * (256 // colours))
# Quantize the image to given palette # Quantize the image to given palette
quantized_im = image.quantize(palette=palette_im, dither=dither) quantized_im = image.quantize(palette=palette_im, dither=dither)
quantized_im = quantized_im.convert('RGB') quantized_im = quantized_im.convert('RGB')
# get rgb of the non-black-white colour from the palette # get rgb of the non-black-white colour from the palette
rgb = [pal[x:x+3] for x in range(0, len(pal),3)] rgb = [pal[x:x + 3] for x in range(0, len(pal), 3)]
rgb = [col for col in rgb if col != [0,0,0] and col != [255,255,255]][0] rgb = [col for col in rgb if col != [0, 0, 0] and col != [255, 255, 255]][0]
r_col, g_col, b_col = rgb r_col, g_col, b_col = rgb
#print(f'r:{r_col} g:{g_col} b:{b_col}') # print(f'r:{r_col} g:{g_col} b:{b_col}')
# Create an image buffer for black pixels # Create an image buffer for black pixels
buffer1 = numpy.array(quantized_im) buffer1 = numpy.array(quantized_im)
# Get RGB values of each pixel # Get RGB values of each pixel
r,g,b = buffer1[:, :, 0], buffer1[:, :, 1], buffer1[:, :, 2] r, g, b = buffer1[:, :, 0], buffer1[:, :, 1], buffer1[:, :, 2]
# convert coloured pixels to white # convert coloured pixels to white
buffer1[numpy.logical_and(r==r_col, g==g_col)] = [255,255,255] buffer1[numpy.logical_and(r == r_col, g == g_col)] = [255, 255, 255]
# reconstruct image for black-band # reconstruct image for black-band
im_black = Image.fromarray(buffer1) im_black = Image.fromarray(buffer1)
@@ -306,19 +306,19 @@ class Inkyimage:
buffer2 = numpy.array(quantized_im) buffer2 = numpy.array(quantized_im)
# Get RGB values of each pixel # Get RGB values of each pixel
r,g,b = buffer2[:, :, 0], buffer2[:, :, 1], buffer2[:, :, 2] r, g, b = buffer2[:, :, 0], buffer2[:, :, 1], buffer2[:, :, 2]
# convert black pixels to white # convert black pixels to white
buffer2[numpy.logical_and(r==0, g==0)] = [255,255,255] buffer2[numpy.logical_and(r == 0, g == 0)] = [255, 255, 255]
# convert non-white pixels to black # convert non-white pixels to black
buffer2[numpy.logical_and(g==g_col, b==0)] = [0,0,0] buffer2[numpy.logical_and(g == g_col, b == 0)] = [0, 0, 0]
# reconstruct image for colour-band # reconstruct image for colour-band
im_colour = Image.fromarray(buffer2) im_colour = Image.fromarray(buffer2)
#self.preview(im_black) # self.preview(im_black)
#self.preview(im_colour) # self.preview(im_colour)
else: else:
im_black = image.convert('1', dither=dither) im_black = image.convert('1', dither=dither)
@@ -331,4 +331,3 @@ class Inkyimage:
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode') print(f'running {filename} in standalone/debug mode')

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Agenda module for Inky-Calendar Project Agenda module for Inky-Calendar Project
Copyright by aceisace Copyright by aceisace
@@ -15,6 +15,7 @@ import arrow
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Agenda(inkycal_module): class Agenda(inkycal_module):
"""Agenda class """Agenda class
Create agenda and show events from given icalendars Create agenda and show events from given icalendars
@@ -23,30 +24,29 @@ class Agenda(inkycal_module):
name = "Agenda - Display upcoming events from given iCalendars" name = "Agenda - Display upcoming events from given iCalendars"
requires = { requires = {
"ical_urls" : { "ical_urls": {
"label":"iCalendar URL/s, separate multiple ones with a comma", "label": "iCalendar URL/s, separate multiple ones with a comma",
}, },
} }
optional = { optional = {
"ical_files" : { "ical_files": {
"label":"iCalendar filepaths, separated with a comma", "label": "iCalendar filepaths, separated with a comma",
}, },
"date_format":{ "date_format": {
"label":"Use an arrow-supported token for custom date formatting "+ "label": "Use an arrow-supported token for custom date formatting " +
"see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. ddd D MMM", "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. ddd D MMM",
"default": "ddd D MMM", "default": "ddd D MMM",
}, },
"time_format":{ "time_format": {
"label":"Use an arrow-supported token for custom time formatting "+ "label": "Use an arrow-supported token for custom time formatting " +
"see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm", "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm",
"default":"HH:mm", "default": "HH:mm",
}, },
} }
def __init__(self, config): def __init__(self, config):
@@ -96,8 +96,8 @@ class Agenda(inkycal_module):
logger.info(f'Image size: {im_size}') logger.info(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels # Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
# Calculate the max number of lines that can fit on the image # Calculate the max number of lines that can fit on the image
line_spacing = 1 line_spacing = 1
@@ -112,9 +112,9 @@ class Agenda(inkycal_module):
# Create a list of dates for the next days # Create a list of dates for the next days
agenda_events = [ agenda_events = [
{'begin':today.shift(days=+_), {'begin': today.shift(days=+_),
'title': today.shift(days=+_).format( 'title': today.shift(days=+_).format(
self.date_format,locale=self.language)} self.date_format, locale=self.language)}
for _ in range(max_lines)] for _ in range(max_lines)]
# Load icalendar from config # Load icalendar from config
@@ -133,7 +133,7 @@ class Agenda(inkycal_module):
# Sort events by beginning time # Sort events by beginning time
parser.sort() parser.sort()
#parser.show_events() # parser.show_events()
# Set the width for date, time and event titles # Set the width for date, time and event titles
date_width = int(max([self.font.getsize( date_width = int(max([self.font.getsize(
@@ -172,7 +172,7 @@ class Agenda(inkycal_module):
# Sort the combined list in chronological order of dates # Sort the combined list in chronological order of dates
by_date = lambda event: event['begin'] by_date = lambda event: event['begin']
agenda_events.sort(key = by_date) agenda_events.sort(key=by_date)
# Delete more entries than can be displayed (max lines) # Delete more entries than can be displayed (max lines)
del agenda_events[max_lines:] del agenda_events[max_lines:]
@@ -187,10 +187,10 @@ class Agenda(inkycal_module):
if not 'end' in _: if not 'end' in _:
ImageDraw.Draw(im_colour).line( ImageDraw.Draw(im_colour).line(
(0, line_pos[cursor][1], im_width, line_pos[cursor][1]), (0, line_pos[cursor][1], im_width, line_pos[cursor][1]),
fill = 'black') fill='black')
write(im_black, line_pos[cursor], (date_width, line_height), write(im_black, line_pos[cursor], (date_width, line_height),
title, font = self.font, alignment='left') title, font=self.font, alignment='left')
cursor += 1 cursor += 1
@@ -202,11 +202,11 @@ class Agenda(inkycal_module):
if parser.all_day(_) == False: if parser.all_day(_) == False:
write(im_black, (x_time, line_pos[cursor][1]), write(im_black, (x_time, line_pos[cursor][1]),
(time_width, line_height), time, (time_width, line_height), time,
font = self.font, alignment='left') font=self.font, alignment='left')
write(im_black, (x_event, line_pos[cursor][1]), write(im_black, (x_event, line_pos[cursor][1]),
(event_width, line_height), (event_width, line_height),
''+title, font = self.font, alignment='left') '' + title, font=self.font, alignment='left')
cursor += 1 cursor += 1
# If no events were found, write only dates and lines # If no events were found, write only dates and lines
@@ -218,16 +218,16 @@ class Agenda(inkycal_module):
title = _['title'] title = _['title']
ImageDraw.Draw(im_colour).line( ImageDraw.Draw(im_colour).line(
(0, line_pos[cursor][1], im_width, line_pos[cursor][1]), (0, line_pos[cursor][1], im_width, line_pos[cursor][1]),
fill = 'black') fill='black')
write(im_black, line_pos[cursor], (date_width, line_height), write(im_black, line_pos[cursor], (date_width, line_height),
title, font = self.font, alignment='left') title, font=self.font, alignment='left')
cursor += 1 cursor += 1
# return the images ready for the display # return the images ready for the display
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone mode') print(f'running {filename} in standalone mode')

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Calendar module for Inky-Calendar Project Calendar module for Inky-Calendar Project
Copyright by aceisace Copyright by aceisace
@@ -23,34 +23,34 @@ class Calendar(inkycal_module):
optional = { optional = {
"week_starts_on" : { "week_starts_on": {
"label":"When does your week start? (default=Monday)", "label": "When does your week start? (default=Monday)",
"options": ["Monday", "Sunday"], "options": ["Monday", "Sunday"],
"default": "Monday" "default": "Monday"
}, },
"show_events" : { "show_events": {
"label":"Show parsed events? (default = True)", "label": "Show parsed events? (default = True)",
"options": [True, False], "options": [True, False],
"default": True "default": True
}, },
"ical_urls" : { "ical_urls": {
"label":"iCalendar URL/s, separate multiple ones with a comma", "label": "iCalendar URL/s, separate multiple ones with a comma",
}, },
"ical_files" : { "ical_files": {
"label":"iCalendar filepaths, separated with a comma", "label": "iCalendar filepaths, separated with a comma",
}, },
"date_format":{ "date_format": {
"label":"Use an arrow-supported token for custom date formatting "+ "label": "Use an arrow-supported token for custom date formatting " +
"see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. D MMM", "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. D MMM",
"default": "D MMM", "default": "D MMM",
}, },
"time_format":{ "time_format": {
"label":"Use an arrow-supported token for custom time formatting "+ "label": "Use an arrow-supported token for custom time formatting " +
"see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm", "see https://arrow.readthedocs.io/en/stable/#supported-tokens, e.g. HH:mm",
"default": "HH:mm" "default": "HH:mm"
}, },
@@ -83,7 +83,7 @@ class Calendar(inkycal_module):
# additional configuration # additional configuration
self.timezone = get_system_tz() self.timezone = get_system_tz()
self.num_font = ImageFont.truetype( self.num_font = ImageFont.truetype(
fonts['NotoSans-SemiCondensed'], size = self.fontsize) fonts['NotoSans-SemiCondensed'], size=self.fontsize)
# give an OK message # give an OK message
print(f'{filename} loaded') print(f'{filename} loaded')
@@ -99,8 +99,8 @@ class Calendar(inkycal_module):
logger.info(f'Image size: {im_size}') logger.info(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels # Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
# Allocate space for month-names, weekdays etc. # Allocate space for month-names, weekdays etc.
month_name_height = int(im_height * 0.10) month_name_height = int(im_height * 0.10)
@@ -136,29 +136,29 @@ class Calendar(inkycal_module):
grid_start_y = (month_name_height + weekdays_height + y_spacing_calendar) grid_start_y = (month_name_height + weekdays_height + y_spacing_calendar)
grid_start_x = x_spacing_calendar grid_start_x = x_spacing_calendar
grid_coordinates = [(grid_start_x + icon_width*x, grid_start_y + icon_height*y) grid_coordinates = [(grid_start_x + icon_width * x, grid_start_y + icon_height * y)
for y in range(calendar_rows) for x in range(calendar_cols)] for y in range(calendar_rows) for x in range(calendar_cols)]
weekday_pos = [(grid_start_x + icon_width*_, month_name_height) for _ in weekday_pos = [(grid_start_x + icon_width * _, month_name_height) for _ in
range(calendar_cols)] range(calendar_cols)]
now = arrow.now(tz = self.timezone) now = arrow.now(tz=self.timezone)
# Set weekstart of calendar to specified weekstart # Set weekstart of calendar to specified weekstart
if self.weekstart == "Monday": if self.weekstart == "Monday":
cal.setfirstweekday(cal.MONDAY) cal.setfirstweekday(cal.MONDAY)
weekstart = now.shift(days = - now.weekday()) weekstart = now.shift(days=- now.weekday())
else: else:
cal.setfirstweekday(cal.SUNDAY) cal.setfirstweekday(cal.SUNDAY)
weekstart = now.shift(days = - now.isoweekday()) weekstart = now.shift(days=- now.isoweekday())
# Write the name of current month # Write the name of current month
write(im_black, (0,0),(im_width, month_name_height), write(im_black, (0, 0), (im_width, month_name_height),
str(now.format('MMMM',locale=self.language)), font = self.font, str(now.format('MMMM', locale=self.language)), font=self.font,
autofit = True) autofit=True)
# Set up weeknames in local language and add to main section # Set up weeknames in local language and add to main section
weekday_names = [weekstart.shift(days=+_).format('ddd',locale=self.language) weekday_names = [weekstart.shift(days=+_).format('ddd', locale=self.language)
for _ in range(7)] for _ in range(7)]
logger.debug(f'weekday names: {weekday_names}') logger.debug(f'weekday names: {weekday_names}')
@@ -168,22 +168,22 @@ class Calendar(inkycal_module):
weekday_pos[_], weekday_pos[_],
(icon_width, weekdays_height), (icon_width, weekdays_height),
weekday_names[_], weekday_names[_],
font = self.font, font=self.font,
autofit = True, autofit=True,
fill_height=1.0 fill_height=1.0
) )
# Create a calendar template and flatten (remove nestings) # Create a calendar template and flatten (remove nestings)
flatten = lambda z: [x for y in z for x in y] flatten = lambda z: [x for y in z for x in y]
calendar_flat = flatten(cal.monthcalendar(now.year, now.month)) calendar_flat = flatten(cal.monthcalendar(now.year, now.month))
#logger.debug(f" calendar_flat: {calendar_flat}") # logger.debug(f" calendar_flat: {calendar_flat}")
# Map days of month to co-ordinates of grid -> 3: (row2_x,col3_y) # Map days of month to co-ordinates of grid -> 3: (row2_x,col3_y)
grid = {} grid = {}
for i in calendar_flat: for i in calendar_flat:
if i != 0: if i != 0:
grid[i] = grid_coordinates[calendar_flat.index(i)] grid[i] = grid_coordinates[calendar_flat.index(i)]
#logger.debug(f"grid:{grid}") # logger.debug(f"grid:{grid}")
# remove zeros from calendar since they are not required # remove zeros from calendar since they are not required
calendar_flat = [num for num in calendar_flat if num != 0] calendar_flat = [num for num in calendar_flat if num != 0]
@@ -192,21 +192,20 @@ class Calendar(inkycal_module):
for number in calendar_flat: for number in calendar_flat:
if number != int(now.day): if number != int(now.day):
write(im_black, grid[number], (icon_width, icon_height), write(im_black, grid[number], (icon_width, icon_height),
str(number), font = self.num_font, fill_height = 0.5, fill_width=0.5) str(number), font=self.num_font, fill_height=0.5, fill_width=0.5)
# Draw a red/black circle with the current day of month in white # Draw a red/black circle with the current day of month in white
icon = Image.new('RGBA', (icon_width, icon_height)) icon = Image.new('RGBA', (icon_width, icon_height))
current_day_pos = grid[int(now.day)] current_day_pos = grid[int(now.day)]
x_circle,y_circle = int(icon_width/2), int(icon_height/2) x_circle, y_circle = int(icon_width / 2), int(icon_height / 2)
radius = int(icon_width * 0.2) radius = int(icon_width * 0.2)
ImageDraw.Draw(icon).ellipse( ImageDraw.Draw(icon).ellipse(
(x_circle-radius, y_circle-radius, x_circle+radius, y_circle+radius), (x_circle - radius, y_circle - radius, x_circle + radius, y_circle + radius),
fill= 'black', outline=None) fill='black', outline=None)
write(icon, (0,0), (icon_width, icon_height), str(now.day), write(icon, (0, 0), (icon_width, icon_height), str(now.day),
font=self.num_font, fill_height = 0.5, colour='white') font=self.num_font, fill_height=0.5, colour='white')
im_colour.paste(icon, current_day_pos, icon) im_colour.paste(icon, current_day_pos, icon)
# If events should be loaded and shown... # If events should be loaded and shown...
if self.show_events == True: if self.show_events == True:
@@ -228,11 +227,10 @@ class Calendar(inkycal_module):
# generate list of coordinates for each line # generate list of coordinates for each line
events_offset = im_height - events_height events_offset = im_height - events_height
event_lines = [(0, events_offset + int(events_height/max_event_lines*_)) event_lines = [(0, events_offset + int(events_height / max_event_lines * _))
for _ in range(max_event_lines)] for _ in range(max_event_lines)]
#logger.debug(f"event_lines {event_lines}") # logger.debug(f"event_lines {event_lines}")
# timeline for filtering events within this month # timeline for filtering events within this month
month_start = arrow.get(now.floor('month')) month_start = arrow.get(now.floor('month'))
@@ -267,9 +265,9 @@ class Calendar(inkycal_module):
im_colour, im_colour,
grid[days], grid[days],
(icon_width, icon_height), (icon_width, icon_height),
radius = 6, radius=6,
thickness= 1, thickness=1,
shrinkage = (0.4, 0.2) shrinkage=(0.4, 0.2)
) )
# Filter upcoming events until 4 weeks in the future # Filter upcoming events until 4 weeks in the future
@@ -281,7 +279,6 @@ class Calendar(inkycal_module):
# delete events which won't be able to fit (more events than lines) # delete events which won't be able to fit (more events than lines)
upcoming_events[:max_event_lines] upcoming_events[:max_event_lines]
# Check if any events were found in the given timerange # Check if any events were found in the given timerange
if upcoming_events: if upcoming_events:
@@ -289,7 +286,7 @@ class Calendar(inkycal_module):
lang = self.language lang = self.language
date_width = int(max([self.font.getsize( date_width = int(max([self.font.getsize(
events['begin'].format(self.date_format,locale=lang))[0] events['begin'].format(self.date_format, locale=lang))[0]
for events in upcoming_events]) * 1.1) for events in upcoming_events]) * 1.1)
time_width = int(max([self.font.getsize( time_width = int(max([self.font.getsize(
@@ -311,36 +308,37 @@ class Calendar(inkycal_module):
name = event['title'] name = event['title']
date = event['begin'].format(self.date_format, locale=lang) date = event['begin'].format(self.date_format, locale=lang)
time = event['begin'].format(self.time_format, locale=lang) time = event['begin'].format(self.time_format, locale=lang)
#logger.debug(f"name:{name} date:{date} time:{time}") # logger.debug(f"name:{name} date:{date} time:{time}")
if now < event['end']: if now < event['end']:
write(im_colour, event_lines[cursor], (date_width, line_height), write(im_colour, event_lines[cursor], (date_width, line_height),
date, font=self.font, alignment = 'left') date, font=self.font, alignment='left')
# Check if event is all day # Check if event is all day
if parser.all_day(event) == True: if parser.all_day(event) == True:
write(im_black, (date_width, event_lines[cursor][1]), write(im_black, (date_width, event_lines[cursor][1]),
(event_width_l, line_height), name, font=self.font, (event_width_l, line_height), name, font=self.font,
alignment = 'left') alignment='left')
else: else:
write(im_black, (date_width, event_lines[cursor][1]), write(im_black, (date_width, event_lines[cursor][1]),
(time_width, line_height), time, font=self.font, (time_width, line_height), time, font=self.font,
alignment = 'left') alignment='left')
write(im_black, (date_width+time_width,event_lines[cursor][1]), write(im_black, (date_width + time_width, event_lines[cursor][1]),
(event_width_s, line_height), name, font=self.font, (event_width_s, line_height), name, font=self.font,
alignment = 'left') alignment='left')
cursor += 1 cursor += 1
else: else:
symbol = '- ' symbol = '- '
while self.font.getsize(symbol)[0] < im_width*0.9: while self.font.getsize(symbol)[0] < im_width * 0.9:
symbol += ' -' symbol += ' -'
write(im_black, event_lines[0], write(im_black, event_lines[0],
(im_width, self.font.getsize(symbol)[1]), symbol, (im_width, self.font.getsize(symbol)[1]), symbol,
font = self.font) font=self.font)
# return the images ready for the display # return the images ready for the display
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone mode') print(f'running {filename} in standalone mode')

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Feeds module for InkyCal Project Feeds module for InkyCal Project
@@ -11,6 +10,7 @@ from inkycal.modules.template import inkycal_module
from inkycal.custom import * from inkycal.custom import *
from random import shuffle from random import shuffle
try: try:
import feedparser import feedparser
except ImportError: except ImportError:
@@ -20,6 +20,7 @@ except ImportError:
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Feeds(inkycal_module): class Feeds(inkycal_module):
"""RSS class """RSS class
parses rss/atom feeds from given urls parses rss/atom feeds from given urls
@@ -28,8 +29,8 @@ class Feeds(inkycal_module):
name = "RSS / Atom - Display feeds from given RSS/ATOM feeds" name = "RSS / Atom - Display feeds from given RSS/ATOM feeds"
requires = { requires = {
"feed_urls" : { "feed_urls": {
"label":"Please enter ATOM or RSS feed URL/s, separated by a comma", "label": "Please enter ATOM or RSS feed URL/s, separated by a comma",
}, },
} }
@@ -74,7 +75,6 @@ class Feeds(inkycal_module):
if not isinstance(self.shuffle_feeds, bool): if not isinstance(self.shuffle_feeds, bool):
print('shuffle_feeds has to be a boolean: True/False') print('shuffle_feeds has to be a boolean: True/False')
def generate_image(self): def generate_image(self):
"""Generate image for this module""" """Generate image for this module"""
@@ -85,8 +85,8 @@ class Feeds(inkycal_module):
logger.info(f'Image size: {im_size}') logger.info(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels # Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
# Check if internet is available # Check if internet is available
if internet_available() == True: if internet_available() == True:
@@ -101,11 +101,11 @@ class Feeds(inkycal_module):
max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing))
# Calculate padding from top so the lines look centralised # Calculate padding from top so the lines look centralised
spacing_top = int( im_height % line_height / 2 ) spacing_top = int(im_height % line_height / 2)
# Calculate line_positions # Calculate line_positions
line_positions = [ line_positions = [
(0, spacing_top + _ * line_height ) for _ in range(max_lines)] (0, spacing_top + _ * line_height) for _ in range(max_lines)]
# Create list containing all feeds from all urls # Create list containing all feeds from all urls
parsed_feeds = [] parsed_feeds = []
@@ -130,7 +130,7 @@ class Feeds(inkycal_module):
filtered_feeds, counter = [], 0 filtered_feeds, counter = [], 0
for posts in parsed_feeds: for posts in parsed_feeds:
wrapped = text_wrap(posts, font = self.font, max_width = line_width) wrapped = text_wrap(posts, font=self.font, max_width=line_width)
counter += len(wrapped) counter += len(wrapped)
if counter < max_lines: if counter < max_lines:
filtered_feeds.append(wrapped) filtered_feeds.append(wrapped)
@@ -148,10 +148,11 @@ class Feeds(inkycal_module):
# Write feeds on image # Write feeds on image
for _ in range(len(filtered_feeds)): for _ in range(len(filtered_feeds)):
write(im_black, line_positions[_], (line_width, line_height), write(im_black, line_positions[_], (line_width, line_height),
filtered_feeds[_], font = self.font, alignment= 'left') filtered_feeds[_], font=self.font, alignment='left')
# return images # return images
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode') print(f'running {filename} in standalone/debug mode')

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Image module for Inkycal Project Image module for Inkycal Project
@@ -14,6 +13,7 @@ from inkycal.modules.inky_image import Inkyimage as Images
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Inkyimage(inkycal_module): class Inkyimage(inkycal_module):
"""Displays an image from URL or local path """Displays an image from URL or local path
""" """
@@ -22,13 +22,13 @@ class Inkyimage(inkycal_module):
requires = { requires = {
"path":{ "path": {
"label":"Path to a local folder, e.g. /home/pi/Desktop/images. " "label": "Path to a local folder, e.g. /home/pi/Desktop/images. "
"Only PNG and JPG/JPEG images are used for the slideshow." "Only PNG and JPG/JPEG images are used for the slideshow."
}, },
"palette": { "palette": {
"label":"Which palette should be used for converting images?", "label": "Which palette should be used for converting images?",
"options": ["bw", "bwr", "bwy"] "options": ["bw", "bwr", "bwy"]
} }
@@ -36,12 +36,12 @@ class Inkyimage(inkycal_module):
optional = { optional = {
"autoflip":{ "autoflip": {
"label":"Should the image be flipped automatically?", "label": "Should the image be flipped automatically?",
"options": [True, False] "options": [True, False]
}, },
"orientation":{ "orientation": {
"label": "Please select the desired orientation", "label": "Please select the desired orientation",
"options": ["vertical", "horizontal"] "options": ["vertical", "horizontal"]
} }
@@ -68,7 +68,6 @@ class Inkyimage(inkycal_module):
# give an OK message # give an OK message
print(f'{filename} loaded') print(f'{filename} loaded')
def generate_image(self): def generate_image(self):
"""Generate image for this module""" """Generate image for this module"""
@@ -93,7 +92,7 @@ class Inkyimage(inkycal_module):
im.autoflip(self.orientation) im.autoflip(self.orientation)
# resize the image so it can fit on the epaper # resize the image so it can fit on the epaper
im.resize( width=im_width, height=im_height ) im.resize(width=im_width, height=im_height)
# convert images according to specified palette # convert images according to specified palette
im_black, im_colour = im.to_palette(self.palette) im_black, im_colour = im.to_palette(self.palette)
@@ -104,5 +103,6 @@ class Inkyimage(inkycal_module):
# return images # return images
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode') print(f'running {filename} in standalone/debug mode')

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
iCanHazDadJoke module for InkyCal Project iCanHazDadJoke module for InkyCal Project
@@ -11,12 +10,14 @@ from inkycal.modules.template import inkycal_module
from inkycal.custom import * from inkycal.custom import *
import requests import requests
# Show less logging for request module # Show less logging for request module
logging.getLogger("urllib3").setLevel(logging.WARNING) logging.getLogger("urllib3").setLevel(logging.WARNING)
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Jokes(inkycal_module): class Jokes(inkycal_module):
"""Icanhazdad-api class """Icanhazdad-api class
parses rss/atom feeds from given urls parses rss/atom feeds from given urls
@@ -24,7 +25,6 @@ class Jokes(inkycal_module):
name = "iCanHazDad API - grab a random joke from icanhazdad api" name = "iCanHazDad API - grab a random joke from icanhazdad api"
def __init__(self, config): def __init__(self, config):
"""Initialize inkycal_feeds module""" """Initialize inkycal_feeds module"""
@@ -45,8 +45,8 @@ class Jokes(inkycal_module):
logger.info(f'image size: {im_width} x {im_height} px') logger.info(f'image size: {im_width} x {im_height} px')
# Create an image for black pixels and one for coloured pixels # Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
# Check if internet is available # Check if internet is available
if internet_available() == True: if internet_available() == True:
@@ -63,11 +63,11 @@ class Jokes(inkycal_module):
logger.debug(f"max_lines: {max_lines}") logger.debug(f"max_lines: {max_lines}")
# Calculate padding from top so the lines look centralised # Calculate padding from top so the lines look centralised
spacing_top = int( im_height % line_height / 2 ) spacing_top = int(im_height % line_height / 2)
# Calculate line_positions # Calculate line_positions
line_positions = [ line_positions = [
(0, spacing_top + _ * line_height ) for _ in range(max_lines)] (0, spacing_top + _ * line_height) for _ in range(max_lines)]
logger.debug(f'line positions: {line_positions}') logger.debug(f'line positions: {line_positions}')
@@ -80,7 +80,7 @@ class Jokes(inkycal_module):
logger.debug(f"joke: {joke}") logger.debug(f"joke: {joke}")
# wrap text in case joke is too large # wrap text in case joke is too large
wrapped = text_wrap(joke, font = self.font, max_width = line_width) wrapped = text_wrap(joke, font=self.font, max_width=line_width)
logger.debug(f"wrapped: {wrapped}") logger.debug(f"wrapped: {wrapped}")
# Check if joke can actually fit on the provided space # Check if joke can actually fit on the provided space
@@ -90,11 +90,11 @@ class Jokes(inkycal_module):
# Write the joke on the image # Write the joke on the image
for _ in range(len(wrapped)): for _ in range(len(wrapped)):
if _+1 > max_lines: if _ + 1 > max_lines:
logger.error('Ran out of lines for this joke :/') logger.error('Ran out of lines for this joke :/')
break break
write(im_black, line_positions[_], (line_width, line_height), write(im_black, line_positions[_], (line_width, line_height),
wrapped[_], font = self.font, alignment= 'left') wrapped[_], font=self.font, alignment='left')
# Return images for black and colour channels # Return images for black and colour channels
return im_black, im_colour return im_black, im_colour

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Inkycal-server module for Inkycal Project Inkycal-server module for Inkycal Project
@@ -17,6 +16,7 @@ from inkycal.modules.inky_image import Inkyimage as Images
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Inkyserver(inkycal_module): class Inkyserver(inkycal_module):
"""Displays an image from URL or local path """Displays an image from URL or local path
""" """
@@ -25,12 +25,12 @@ class Inkyserver(inkycal_module):
requires = { requires = {
"path":{ "path": {
"label": "Which URL should be used to get the image?" "label": "Which URL should be used to get the image?"
}, },
"palette": { "palette": {
"label":"Which palette should be used to convert the images?", "label": "Which palette should be used to convert the images?",
"options": ['bw', 'bwr', 'bwy'] "options": ['bw', 'bwr', 'bwy']
} }
@@ -38,11 +38,11 @@ class Inkyserver(inkycal_module):
optional = { optional = {
"path_body":{ "path_body": {
"label":"Send this data to the server via POST. Use a comma to " "label": "Send this data to the server via POST. Use a comma to "
"separate multiple items", "separate multiple items",
}, },
"dither":{ "dither": {
"label": "Dither images before sending to E-Paper? Default is False.", "label": "Dither images before sending to E-Paper? Default is False.",
"options": [False, True], "options": [False, True],
} }
@@ -75,7 +75,6 @@ class Inkyserver(inkycal_module):
# give an OK message # give an OK message
print(f'{filename} loaded') print(f'{filename} loaded')
def generate_image(self): def generate_image(self):
"""Generate image for this module""" """Generate image for this module"""
@@ -110,7 +109,7 @@ class Inkyserver(inkycal_module):
im = Images(response) im = Images(response)
# resize the image to respect padding # resize the image to respect padding
im.resize( width=im_width, height=im_height ) im.resize(width=im_width, height=im_height)
# convert image to given palette # convert image to given palette
im_black, im_colour = im.to_palette(self.palette, dither=self.dither) im_black, im_colour = im.to_palette(self.palette, dither=self.dither)
@@ -121,6 +120,7 @@ class Inkyserver(inkycal_module):
# return images # return images
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode') print(f'running {filename} in standalone/debug mode')
@@ -131,4 +131,3 @@ if __name__ == '__main__':
##inkycal_image_path_body = [ ##inkycal_image_path_body = [
## 'https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics', ## 'https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics',
## 'https ## 'https

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Image module for Inkycal Project Image module for Inkycal Project
@@ -16,6 +15,7 @@ from inkycal.modules.inky_image import Inkyimage as Images
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Slideshow(inkycal_module): class Slideshow(inkycal_module):
"""Cycles through images in a local image folder """Cycles through images in a local image folder
""" """
@@ -23,13 +23,13 @@ class Slideshow(inkycal_module):
requires = { requires = {
"path":{ "path": {
"label":"Path to a local folder, e.g. /home/pi/Desktop/images. " "label": "Path to a local folder, e.g. /home/pi/Desktop/images. "
"Only PNG and JPG/JPEG images are used for the slideshow." "Only PNG and JPG/JPEG images are used for the slideshow."
}, },
"palette": { "palette": {
"label":"Which palette should be used for converting images?", "label": "Which palette should be used for converting images?",
"options": ["bw", "bwr", "bwy"] "options": ["bw", "bwr", "bwy"]
} }
@@ -37,12 +37,12 @@ class Slideshow(inkycal_module):
optional = { optional = {
"autoflip":{ "autoflip": {
"label":"Should the image be flipped automatically? Default is False", "label": "Should the image be flipped automatically? Default is False",
"options": [False, True] "options": [False, True]
}, },
"orientation":{ "orientation": {
"label": "Please select the desired orientation", "label": "Please select the desired orientation",
"options": ["vertical", "horizontal"] "options": ["vertical", "horizontal"]
} }
@@ -119,7 +119,7 @@ class Slideshow(inkycal_module):
im.autoflip(self.orientation) im.autoflip(self.orientation)
# resize the image so it can fit on the epaper # resize the image so it can fit on the epaper
im.resize( width=im_width, height=im_height ) im.resize(width=im_width, height=im_height)
# convert images according to specified palette # convert images according to specified palette
im_black, im_colour = im.to_palette(self.palette) im_black, im_colour = im.to_palette(self.palette)
@@ -130,5 +130,6 @@ class Slideshow(inkycal_module):
# return images # return images
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode') print(f'running {filename} in standalone/debug mode')

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Stocks Module for Inkycal Project Stocks Module for Inkycal Project
@@ -34,8 +34,8 @@ except ImportError:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
class Stocks(inkycal_module):
class Stocks(inkycal_module):
name = "Stocks - Displays stock market infos from Yahoo finance" name = "Stocks - Displays stock market infos from Yahoo finance"
# required parameters # required parameters
@@ -59,7 +59,7 @@ class Stocks(inkycal_module):
# If tickers is a string from web-ui, convert to a list, else use # If tickers is a string from web-ui, convert to a list, else use
# tickers as-is i.e. for tests # tickers as-is i.e. for tests
if config['tickers'] and isinstance(config['tickers'], str): if config['tickers'] and isinstance(config['tickers'], str):
self.tickers = config['tickers'].replace(" ", "").split(',') #returns list self.tickers = config['tickers'].replace(" ", "").split(',') # returns list
else: else:
self.tickers = config['tickers'] self.tickers = config['tickers']
@@ -76,8 +76,8 @@ class Stocks(inkycal_module):
logger.info(f'image size: {im_width} x {im_height} px') logger.info(f'image size: {im_width} x {im_height} px')
# Create an image for black pixels and one for coloured pixels (required) # Create an image for black pixels and one for coloured pixels (required)
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
# Create tmp path # Create tmp path
tmpPath = '/tmp/inkycal_stocks/' tmpPath = '/tmp/inkycal_stocks/'
@@ -85,9 +85,9 @@ class Stocks(inkycal_module):
try: try:
os.mkdir(tmpPath) os.mkdir(tmpPath)
except OSError: except OSError:
print (f"Creation of tmp directory {tmpPath} failed") print(f"Creation of tmp directory {tmpPath} failed")
else: else:
print (f"Successfully created tmp directory {tmpPath} ") print(f"Successfully created tmp directory {tmpPath} ")
# Check if internet is available # Check if internet is available
if internet_available() == True: if internet_available() == True:
@@ -104,11 +104,11 @@ class Stocks(inkycal_module):
logger.debug(f"max_lines: {max_lines}") logger.debug(f"max_lines: {max_lines}")
# Calculate padding from top so the lines look centralised # Calculate padding from top so the lines look centralised
spacing_top = int( im_height % line_height / 2 ) spacing_top = int(im_height % line_height / 2)
# Calculate line_positions # Calculate line_positions
line_positions = [ line_positions = [
(0, spacing_top + _ * line_height ) for _ in range(max_lines)] (0, spacing_top + _ * line_height) for _ in range(max_lines)]
logger.debug(f'line positions: {line_positions}') logger.debug(f'line positions: {line_positions}')
@@ -162,8 +162,8 @@ class Stocks(inkycal_module):
currentHigh = (stockHistory.tail(1)['High'].iloc[0]) currentHigh = (stockHistory.tail(1)['High'].iloc[0])
currentLow = (stockHistory.tail(1)['Low'].iloc[0]) currentLow = (stockHistory.tail(1)['Low'].iloc[0])
currentOpen = (stockHistory.tail(1)['Open'].iloc[0]) currentOpen = (stockHistory.tail(1)['Open'].iloc[0])
currentGain = currentQuote-previousQuote currentGain = currentQuote - previousQuote
currentGainPercentage = (1-currentQuote/previousQuote)*-100 currentGainPercentage = (1 - currentQuote / previousQuote) * -100
firstQuote = stockHistory.tail(stockHistoryLen)['Close'].iloc[0] firstQuote = stockHistory.tail(stockHistoryLen)['Close'].iloc[0]
logger.info(f'firstQuote {firstQuote} ...') logger.info(f'firstQuote {firstQuote} ...')
@@ -178,14 +178,16 @@ class Stocks(inkycal_module):
stockNameLine = '{} ({})'.format(stockName, stockCurrency) stockNameLine = '{} ({})'.format(stockName, stockCurrency)
stockCurrentValueLine = '{} {} {}'.format( stockCurrentValueLine = '{} {} {}'.format(
floatStr(precision, currentQuote), gainStr(precision, currentGain), percentageStr(currentGainPercentage)) floatStr(precision, currentQuote), gainStr(precision, currentGain),
percentageStr(currentGainPercentage))
stockDayValueLine = '1d OHL: {}/{}/{}'.format( stockDayValueLine = '1d OHL: {}/{}/{}'.format(
floatStr(precision, currentOpen), floatStr(precision, currentHigh), floatStr(precision, currentLow)) floatStr(precision, currentOpen), floatStr(precision, currentHigh), floatStr(precision, currentLow))
maxQuote = max(stockHistory.High) maxQuote = max(stockHistory.High)
minQuote = min(stockHistory.Low) minQuote = min(stockHistory.Low)
logger.info(f'high {maxQuote} low {minQuote} ...') logger.info(f'high {maxQuote} low {minQuote} ...')
stockMonthValueLine = '{}d OHL: {}/{}/{}'.format( stockMonthValueLine = '{}d OHL: {}/{}/{}'.format(
stockHistoryLen,floatStr(precision, firstQuote),floatStr(precision, maxQuote),floatStr(precision, minQuote)) stockHistoryLen, floatStr(precision, firstQuote), floatStr(precision, maxQuote),
floatStr(precision, minQuote))
logger.info(stockNameLine) logger.info(stockNameLine)
logger.info(stockCurrentValueLine) logger.info(stockCurrentValueLine)
@@ -216,25 +218,25 @@ class Stocks(inkycal_module):
logger.info(f'creating chart data...') logger.info(f'creating chart data...')
chartData = stockHistory.reset_index() chartData = stockHistory.reset_index()
chartCloseData = chartData.loc[:,'Close'] chartCloseData = chartData.loc[:, 'Close']
chartTimeData = chartData.loc[:,'Date'] chartTimeData = chartData.loc[:, 'Date']
logger.info(f'creating chart plot...') logger.info(f'creating chart plot...')
fig, ax = plt.subplots() # Create a figure containing a single axes. fig, ax = plt.subplots() # Create a figure containing a single axes.
ax.plot(chartTimeData, chartCloseData, linewidth=8) # Plot some data on the axes. ax.plot(chartTimeData, chartCloseData, linewidth=8) # Plot some data on the axes.
ax.set_xticklabels([]) ax.set_xticklabels([])
ax.set_yticklabels([]) ax.set_yticklabels([])
chartPath = tmpPath+ticker+'.png' chartPath = tmpPath + ticker + '.png'
logger.info(f'saving chart image to {chartPath}...') logger.info(f'saving chart image to {chartPath}...')
plt.savefig(chartPath) plt.savefig(chartPath)
logger.info(f'chartSpace is...{im_width} {im_height}') logger.info(f'chartSpace is...{im_width} {im_height}')
logger.info(f'open chart ...{chartPath}') logger.info(f'open chart ...{chartPath}')
chartImage = Image.open(chartPath) chartImage = Image.open(chartPath)
chartImage.thumbnail((im_width/4,line_height*4), Image.BICUBIC) chartImage.thumbnail((im_width / 4, line_height * 4), Image.BICUBIC)
chartPasteX = im_width-(chartImage.width) chartPasteX = im_width - (chartImage.width)
chartPasteY = line_height*5*_ chartPasteY = line_height * 5 * _
logger.info(f'pasting chart image with index {_} to...{chartPasteX} {chartPasteY}') logger.info(f'pasting chart image with index {_} to...{chartPasteX} {chartPasteY}')
if firstQuote > currentQuote: if firstQuote > currentQuote:
@@ -247,22 +249,23 @@ class Stocks(inkycal_module):
# Write/Draw something on the black image # Write/Draw something on the black image
for _ in range(len(parsed_tickers)): for _ in range(len(parsed_tickers)):
if _+1 > max_lines: if _ + 1 > max_lines:
logger.error('Ran out of lines for parsed_ticker_colour') logger.error('Ran out of lines for parsed_ticker_colour')
break break
write(im_black, line_positions[_], (line_width, line_height), write(im_black, line_positions[_], (line_width, line_height),
parsed_tickers[_], font = self.font, alignment= 'left') parsed_tickers[_], font=self.font, alignment='left')
# Write/Draw something on the colour image # Write/Draw something on the colour image
for _ in range(len(parsed_tickers_colour)): for _ in range(len(parsed_tickers_colour)):
if _+1 > max_lines: if _ + 1 > max_lines:
logger.error('Ran out of lines for parsed_tickers_colour') logger.error('Ran out of lines for parsed_tickers_colour')
break break
write(im_colour, line_positions[_], (line_width, line_height), write(im_colour, line_positions[_], (line_width, line_height),
parsed_tickers_colour[_], font = self.font, alignment= 'left') parsed_tickers_colour[_], font=self.font, alignment='left')
# Save image of black and colour channel in image-folder # Save image of black and colour channel in image-folder
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print('running module in standalone/debug mode') print('running module in standalone/debug mode')

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
todoist module for Inky-Calendar Project todoist module for Inky-Calendar Project
@@ -18,6 +17,7 @@ except ImportError:
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Todoist(inkycal_module): class Todoist(inkycal_module):
"""Todoist api class """Todoist api class
parses todo's from api-key parses todo's from api-key
@@ -27,13 +27,13 @@ class Todoist(inkycal_module):
requires = { requires = {
'api_key': { 'api_key': {
"label":"Please enter your Todoist API-key", "label": "Please enter your Todoist API-key",
}, },
} }
optional = { optional = {
'project_filter': { 'project_filter': {
"label":"Show Todos only from following project (separated by a comma). Leave empty to show "+ "label": "Show Todos only from following project (separated by a comma). Leave empty to show " +
"todos from all projects", "todos from all projects",
} }
} }
@@ -80,8 +80,8 @@ class Todoist(inkycal_module):
logger.info(f'Image size: {im_size}') logger.info(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels # Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
# Check if internet is available # Check if internet is available
if internet_available() == True: if internet_available() == True:
@@ -97,11 +97,11 @@ class Todoist(inkycal_module):
max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing)) max_lines = (im_height // (self.font.getsize('hg')[1] + line_spacing))
# Calculate padding from top so the lines look centralised # Calculate padding from top so the lines look centralised
spacing_top = int( im_height % line_height / 2 ) spacing_top = int(im_height % line_height / 2)
# Calculate line_positions # Calculate line_positions
line_positions = [ line_positions = [
(0, spacing_top + _ * line_height ) for _ in range(max_lines)] (0, spacing_top + _ * line_height) for _ in range(max_lines)]
# Get all projects by name and id # Get all projects by name and id
all_projects = {project['id']: project['name'] all_projects = {project['id']: project['name']
@@ -128,15 +128,15 @@ class Todoist(inkycal_module):
# Create single-use generator to filter undone and non-deleted tasks # Create single-use generator to filter undone and non-deleted tasks
tasks = (task.data for task in self._api.state['items'] if tasks = (task.data for task in self._api.state['items'] if
task['checked'] == 0 and task['is_deleted']==0) task['checked'] == 0 and task['is_deleted'] == 0)
# Simplify the tasks for faster processing # Simplify the tasks for faster processing
simplified = [ simplified = [
{ {
'name':task['content'], 'name': task['content'],
'due':task['due']['string'] if task['due'] != None else "", 'due': task['due']['string'] if task['due'] != None else "",
'priority':task['priority'], 'priority': task['priority'],
'project':all_projects[ task['project_id' ] ] if task['project_id'] in all_projects else "deleted" 'project': all_projects[task['project_id']] if task['project_id'] in all_projects else "deleted"
} }
for task in tasks] for task in tasks]
@@ -147,11 +147,11 @@ class Todoist(inkycal_module):
# Get maximum width of project names for selected font # Get maximum width of project names for selected font
project_width = int(max([ project_width = int(max([
self.font.getsize(task['project'])[0] for task in simplified ]) * 1.1) self.font.getsize(task['project'])[0] for task in simplified]) * 1.1)
# Get maximum width of project dues for selected font # Get maximum width of project dues for selected font
due_width = int(max([ due_width = int(max([
self.font.getsize(task['due'])[0] for task in simplified ]) * 1.1) self.font.getsize(task['due'])[0] for task in simplified]) * 1.1)
# Group tasks by project name # Group tasks by project name
grouped = {name: [] for id_, name in all_projects.items()} grouped = {name: [] for id_, name in all_projects.items()}
@@ -162,7 +162,6 @@ class Todoist(inkycal_module):
logger.debug(f"grouped: {grouped}") logger.debug(f"grouped: {grouped}")
# Add the parsed todos on the image # Add the parsed todos on the image
cursor = 0 cursor = 0
for name, todos in grouped.items(): for name, todos in grouped.items():
@@ -188,8 +187,8 @@ class Todoist(inkycal_module):
# Add todo name # Add todo name
write( write(
im_black, im_black,
(line_x+project_width+due_width, line_y), (line_x + project_width + due_width, line_y),
(im_width-project_width-due_width, line_height), (im_width - project_width - due_width, line_height),
todo['name'], font=self.font, alignment='left') todo['name'], font=self.font, alignment='left')
cursor += 1 cursor += 1
@@ -200,5 +199,6 @@ class Todoist(inkycal_module):
# return the images ready for the display # return the images ready for the display
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone/debug mode') print(f'running {filename} in standalone/debug mode')

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Weather module for Inky-Calendar software. Weather module for Inky-Calendar software.
Copyright by aceisace Copyright by aceisace
@@ -21,6 +21,7 @@ except ImportError:
filename = os.path.basename(__file__).split('.py')[0] filename = os.path.basename(__file__).split('.py')[0]
logger = logging.getLogger(filename) logger = logging.getLogger(filename)
class Weather(inkycal_module): class Weather(inkycal_module):
"""Weather class """Weather class
parses weather details from openweathermap parses weather details from openweathermap
@@ -29,13 +30,13 @@ class Weather(inkycal_module):
requires = { requires = {
"api_key" : { "api_key": {
"label":"Please enter openweathermap api-key. You can create one for free on openweathermap", "label": "Please enter openweathermap api-key. You can create one for free on openweathermap",
}, },
"location": { "location": {
"label":"Please enter your location in the following format: City, Country-Code. "+ "label": "Please enter your location in the following format: City, Country-Code. " +
"You can also enter the location ID found in the url "+ "You can also enter the location ID found in the url " +
"e.g. https://openweathermap.org/city/4893171 -> ID is 4893171" "e.g. https://openweathermap.org/city/4893171 -> ID is 4893171"
} }
} }
@@ -43,17 +44,17 @@ class Weather(inkycal_module):
optional = { optional = {
"round_temperature": { "round_temperature": {
"label":"Round temperature to the nearest degree?", "label": "Round temperature to the nearest degree?",
"options": [True, False], "options": [True, False],
}, },
"round_windspeed": { "round_windspeed": {
"label":"Round windspeed?", "label": "Round windspeed?",
"options": [True, False], "options": [True, False],
}, },
"forecast_interval": { "forecast_interval": {
"label":"Please select the forecast interval", "label": "Please select the forecast interval",
"options": ["daily", "hourly"], "options": ["daily", "hourly"],
}, },
@@ -103,12 +104,11 @@ class Weather(inkycal_module):
self.timezone = get_system_tz() self.timezone = get_system_tz()
self.locale = config['language'] self.locale = config['language']
self.weatherfont = ImageFont.truetype( self.weatherfont = ImageFont.truetype(
fonts['weathericons-regular-webfont'], size = self.fontsize) fonts['weathericons-regular-webfont'], size=self.fontsize)
# give an OK message # give an OK message
print(f"{filename} loaded") print(f"{filename} loaded")
def generate_image(self): def generate_image(self):
"""Generate image for this module""" """Generate image for this module"""
@@ -119,8 +119,8 @@ class Weather(inkycal_module):
logger.info(f'Image size: {im_size}') logger.info(f'Image size: {im_size}')
# Create an image for black pixels and one for coloured pixels # Create an image for black pixels and one for coloured pixels
im_black = Image.new('RGB', size = im_size, color = 'white') im_black = Image.new('RGB', size=im_size, color='white')
im_colour = Image.new('RGB', size = im_size, color = 'white') im_colour = Image.new('RGB', size=im_size, color='white')
# Check if internet is available # Check if internet is available
if internet_available() == True: if internet_available() == True:
@@ -138,9 +138,8 @@ class Weather(inkycal_module):
lunations = dec("0.20439731") + (days * dec("0.03386319269")) lunations = dec("0.20439731") + (days * dec("0.03386319269"))
position = lunations % dec(1) position = lunations % dec(1)
index = math.floor((position * dec(8)) + dec("0.5")) index = math.floor((position * dec(8)) + dec("0.5"))
return {0: '\uf095',1: '\uf099',2: '\uf09c',3: '\uf0a0', return {0: '\uf095', 1: '\uf099', 2: '\uf09c', 3: '\uf0a0',
4: '\uf0a3',5: '\uf0a7',6: '\uf0aa',7: '\uf0ae' }[int(index) & 7] 4: '\uf0a3', 5: '\uf0a7', 6: '\uf0aa', 7: '\uf0ae'}[int(index) & 7]
def is_negative(temp): def is_negative(temp):
"""Check if temp is below freezing point of water (0°C/30°F) """Check if temp is below freezing point of water (0°C/30°F)
@@ -163,15 +162,14 @@ class Weather(inkycal_module):
'11n': '\uf03b', '13n': '\uf038', '50n': '\uf023' '11n': '\uf03b', '13n': '\uf038', '50n': '\uf023'
} }
def draw_icon(image, xy, box_size, icon, rotation=None):
def draw_icon(image, xy, box_size, icon, rotation = None):
"""Custom function to add icons of weather font on image """Custom function to add icons of weather font on image
image = on which image should the text be added? image = on which image should the text be added?
xy = xy-coordinates as tuple -> (x,y) xy = xy-coordinates as tuple -> (x,y)
box_size = size of text-box -> (width,height) box_size = size of text-box -> (width,height)
icon = icon-unicode, looks this up in weathericons dictionary icon = icon-unicode, looks this up in weathericons dictionary
""" """
x,y = xy x, y = xy
box_width, box_height = box_size box_width, box_height = box_size
text = icon text = icon
font = self.weatherfont font = self.weatherfont
@@ -199,22 +197,19 @@ class Weather(inkycal_module):
ImageDraw.Draw(space).text((x, y), text, fill='black', font=font) ImageDraw.Draw(space).text((x, y), text, fill='black', font=font)
if rotation != None: if rotation != None:
space.rotate(rotation, expand = True) space.rotate(rotation, expand=True)
# Update only region with text (add text with transparent background) # Update only region with text (add text with transparent background)
image.paste(space, xy, space) image.paste(space, xy, space)
# column1 column2 column3 column4 column5 column6 column7
# |----------|----------|----------|----------|----------|----------|----------|
# column1 column2 column3 column4 column5 column6 column7 # | time | temperat.| moonphase| forecast1| forecast2| forecast3| forecast4|
# |----------|----------|----------|----------|----------|----------|----------| # | current |----------|----------|----------|----------|----------|----------|
# | time | temperat.| moonphase| forecast1| forecast2| forecast3| forecast4| # | weather | humidity | sunrise | icon1 | icon2 | icon3 | icon4 |
# | current |----------|----------|----------|----------|----------|----------| # | icon |----------|----------|----------|----------|----------|----------|
# | weather | humidity | sunrise | icon1 | icon2 | icon3 | icon4 | # | | windspeed| sunset | temperat.| temperat.| temperat.| temperat.|
# | icon |----------|----------|----------|----------|----------|----------| # |----------|----------|----------|----------|----------|----------|----------|
# | | windspeed| sunset | temperat.| temperat.| temperat.| temperat.|
# |----------|----------|----------|----------|----------|----------|----------|
# Calculate size rows and columns # Calculate size rows and columns
col_width = im_width // 7 col_width = im_width // 7
@@ -226,13 +221,13 @@ class Weather(inkycal_module):
row_height = im_height // 3 row_height = im_height // 3
else: else:
logger.info('Please consider decreasing the height.') logger.info('Please consider decreasing the height.')
row_height = int( (im_height* (1-im_height/im_width)) / 3 ) row_height = int((im_height * (1 - im_height / im_width)) / 3)
logger.debug(f"row_height: {row_height} | col_width: {col_width}") logger.debug(f"row_height: {row_height} | col_width: {col_width}")
# Calculate spacings for better centering # Calculate spacings for better centering
spacing_top = int( (im_width % col_width) / 2 ) spacing_top = int((im_width % col_width) / 2)
spacing_left = int( (im_height % row_height) / 2 ) spacing_left = int((im_height % row_height) / 2)
# Define sizes for weather icons # Define sizes for weather icons
icon_small = int(col_width / 3) icon_small = int(col_width / 3)
@@ -249,60 +244,59 @@ class Weather(inkycal_module):
col7 = col6 + col_width col7 = col6 + col_width
# Calculate the y-axis position of each row # Calculate the y-axis position of each row
line_gap = int((im_height - spacing_top - 3*row_height) // 4) line_gap = int((im_height - spacing_top - 3 * row_height) // 4)
row1 = line_gap row1 = line_gap
row2 = row1 + line_gap + row_height row2 = row1 + line_gap + row_height
row3 = row2+ line_gap + row_height row3 = row2 + line_gap + row_height
# Draw lines on each row and border # Draw lines on each row and border
############################################################################ ############################################################################
## draw = ImageDraw.Draw(im_black) ## draw = ImageDraw.Draw(im_black)
## draw.line((0, 0, im_width, 0), fill='red') ## draw.line((0, 0, im_width, 0), fill='red')
## draw.line((0, im_height-1, im_width, im_height-1), fill='red') ## draw.line((0, im_height-1, im_width, im_height-1), fill='red')
## draw.line((0, row1, im_width, row1), fill='black') ## draw.line((0, row1, im_width, row1), fill='black')
## draw.line((0, row1+row_height, im_width, row1+row_height), fill='black') ## draw.line((0, row1+row_height, im_width, row1+row_height), fill='black')
## draw.line((0, row2, im_width, row2), fill='black') ## draw.line((0, row2, im_width, row2), fill='black')
## draw.line((0, row2+row_height, im_width, row2+row_height), fill='black') ## draw.line((0, row2+row_height, im_width, row2+row_height), fill='black')
## draw.line((0, row3, im_width, row3), fill='black') ## draw.line((0, row3, im_width, row3), fill='black')
## draw.line((0, row3+row_height, im_width, row3+row_height), fill='black') ## draw.line((0, row3+row_height, im_width, row3+row_height), fill='black')
############################################################################ ############################################################################
# Positions for current weather details # Positions for current weather details
weather_icon_pos = (col1, 0) weather_icon_pos = (col1, 0)
temperature_icon_pos = (col2, row1) temperature_icon_pos = (col2, row1)
temperature_pos = (col2+icon_small, row1) temperature_pos = (col2 + icon_small, row1)
humidity_icon_pos = (col2, row2) humidity_icon_pos = (col2, row2)
humidity_pos = (col2+icon_small, row2) humidity_pos = (col2 + icon_small, row2)
windspeed_icon_pos = (col2, row3) windspeed_icon_pos = (col2, row3)
windspeed_pos = (col2+icon_small, row3) windspeed_pos = (col2 + icon_small, row3)
# Positions for sunrise, sunset, moonphase # Positions for sunrise, sunset, moonphase
moonphase_pos = (col3, row1) moonphase_pos = (col3, row1)
sunrise_icon_pos = (col3, row2) sunrise_icon_pos = (col3, row2)
sunrise_time_pos = (col3+icon_small, row2) sunrise_time_pos = (col3 + icon_small, row2)
sunset_icon_pos = (col3, row3) sunset_icon_pos = (col3, row3)
sunset_time_pos = (col3+ icon_small, row3) sunset_time_pos = (col3 + icon_small, row3)
# Positions for forecast 1 # Positions for forecast 1
stamp_fc1 = (col4, row1) stamp_fc1 = (col4, row1)
icon_fc1 = (col4, row1+row_height) icon_fc1 = (col4, row1 + row_height)
temp_fc1 = (col4, row3) temp_fc1 = (col4, row3)
# Positions for forecast 2 # Positions for forecast 2
stamp_fc2 = (col5, row1) stamp_fc2 = (col5, row1)
icon_fc2 = (col5, row1+row_height) icon_fc2 = (col5, row1 + row_height)
temp_fc2 = (col5, row3) temp_fc2 = (col5, row3)
# Positions for forecast 3 # Positions for forecast 3
stamp_fc3 = (col6, row1) stamp_fc3 = (col6, row1)
icon_fc3 = (col6, row1+row_height) icon_fc3 = (col6, row1 + row_height)
temp_fc3 = (col6, row3) temp_fc3 = (col6, row3)
# Positions for forecast 4 # Positions for forecast 4
stamp_fc4 = (col7, row1) stamp_fc4 = (col7, row1)
icon_fc4 = (col7, row1+row_height) icon_fc4 = (col7, row1 + row_height)
temp_fc4 = (col7, row3) temp_fc4 = (col7, row3)
# Create current-weather and weather-forecast objects # Create current-weather and weather-forecast objects
@@ -343,8 +337,8 @@ class Weather(inkycal_module):
hour_gap = 3 hour_gap = 3
# Create timings for hourly forcasts # Create timings for hourly forcasts
forecast_timings = [now.shift(hours = + hour_gap + _).floor('hour') forecast_timings = [now.shift(hours=+ hour_gap + _).floor('hour')
for _ in range(0,12,3)] for _ in range(0, 12, 3)]
# Create forecast objects for given timings # Create forecast objects for given timings
forecasts = [forecast.get_weather_at(forecast_time.datetime) for forecasts = [forecast.get_weather_at(forecast_time.datetime) for
@@ -357,9 +351,9 @@ class Weather(inkycal_module):
forecast.temperature(unit=temp_unit)['temp'], ndigits=dec_temp)) forecast.temperature(unit=temp_unit)['temp'], ndigits=dec_temp))
icon = forecast.weather_icon_name icon = forecast.weather_icon_name
fc_data['fc'+str(forecasts.index(forecast)+1)] = { fc_data['fc' + str(forecasts.index(forecast) + 1)] = {
'temp':temp, 'temp': temp,
'icon':icon, 'icon': icon,
'stamp': forecast_timings[forecasts.index(forecast)].to( 'stamp': forecast_timings[forecasts.index(forecast)].to(
get_system_tz()).format('H.00' if self.hour_format == 24 else 'h a') get_system_tz()).format('H.00' if self.hour_format == 24 else 'h a')
} }
@@ -368,7 +362,6 @@ class Weather(inkycal_module):
logger.debug("getting daily forecasts") logger.debug("getting daily forecasts")
def calculate_forecast(days_from_today): def calculate_forecast(days_from_today):
"""Get temperature range and most frequent icon code for forecast """Get temperature range and most frequent icon code for forecast
days_from_today should be int from 1-4: e.g. 2 -> 2 days from today days_from_today should be int from 1-4: e.g. 2 -> 2 days from today
@@ -389,7 +382,6 @@ class Weather(inkycal_module):
# Calculate min. and max. temp for this day # Calculate min. and max. temp for this day
temp_range = f'{max(daily_temp)}°/{min(daily_temp)}°' temp_range = f'{max(daily_temp)}°/{min(daily_temp)}°'
# Get all weather icon codes for this day # Get all weather icon codes for this day
daily_icons = [_.weather_icon_name for _ in forecasts] daily_icons = [_.weather_icon_name for _ in forecasts]
# Find most common element from all weather icon codes # Find most common element from all weather icon codes
@@ -397,20 +389,20 @@ class Weather(inkycal_module):
weekday = now.shift(days=days_from_today).format('ddd', locale= weekday = now.shift(days=days_from_today).format('ddd', locale=
self.locale) self.locale)
return {'temp':temp_range, 'icon':status, 'stamp': weekday} return {'temp': temp_range, 'icon': status, 'stamp': weekday}
forecasts = [calculate_forecast(days) for days in range (1,5)] forecasts = [calculate_forecast(days) for days in range(1, 5)]
fc_data = {} fc_data = {}
for forecast in forecasts: for forecast in forecasts:
fc_data['fc'+str(forecasts.index(forecast)+1)] = { fc_data['fc' + str(forecasts.index(forecast) + 1)] = {
'temp':forecast['temp'], 'temp': forecast['temp'],
'icon':forecast['icon'], 'icon': forecast['icon'],
'stamp': forecast['stamp'] 'stamp': forecast['stamp']
} }
for key,val in fc_data.items(): for key, val in fc_data.items():
logger.debug((key,val)) logger.debug((key, val))
# Get some current weather details # Get some current weather details
temperature = '{}°'.format(round( temperature = '{}°'.format(round(
@@ -460,63 +452,63 @@ class Weather(inkycal_module):
'\uf053') '\uf053')
if is_negative(temperature): if is_negative(temperature):
write(im_black, temperature_pos, (col_width-icon_small, row_height), write(im_black, temperature_pos, (col_width - icon_small, row_height),
temperature, font = self.font) temperature, font=self.font)
else: else:
write(im_black, temperature_pos, (col_width-icon_small, row_height), write(im_black, temperature_pos, (col_width - icon_small, row_height),
temperature, font = self.font) temperature, font=self.font)
draw_icon(im_colour, humidity_icon_pos, (icon_small, row_height), draw_icon(im_colour, humidity_icon_pos, (icon_small, row_height),
'\uf07a') '\uf07a')
write(im_black, humidity_pos, (col_width-icon_small, row_height), write(im_black, humidity_pos, (col_width - icon_small, row_height),
humidity+'%', font = self.font) humidity + '%', font=self.font)
draw_icon(im_colour, windspeed_icon_pos, (icon_small, icon_small), draw_icon(im_colour, windspeed_icon_pos, (icon_small, icon_small),
'\uf050') '\uf050')
write(im_black, windspeed_pos, (col_width-icon_small, row_height), write(im_black, windspeed_pos, (col_width - icon_small, row_height),
wind, font=self.font) wind, font=self.font)
# Fill weather details in col 3 (moonphase, sunrise, sunset) # Fill weather details in col 3 (moonphase, sunrise, sunset)
draw_icon(im_colour, moonphase_pos, (col_width, row_height), moonphase) draw_icon(im_colour, moonphase_pos, (col_width, row_height), moonphase)
draw_icon(im_colour, sunrise_icon_pos, (icon_small, icon_small), '\uf051') draw_icon(im_colour, sunrise_icon_pos, (icon_small, icon_small), '\uf051')
write(im_black, sunrise_time_pos, (col_width-icon_small, row_height), write(im_black, sunrise_time_pos, (col_width - icon_small, row_height),
sunrise, font = self.font) sunrise, font=self.font)
draw_icon(im_colour, sunset_icon_pos, (icon_small, icon_small), '\uf052') draw_icon(im_colour, sunset_icon_pos, (icon_small, icon_small), '\uf052')
write(im_black, sunset_time_pos, (col_width-icon_small, row_height), sunset, write(im_black, sunset_time_pos, (col_width - icon_small, row_height), sunset,
font = self.font) font=self.font)
# Add the forecast data to the correct places # Add the forecast data to the correct places
for pos in range(1, len(fc_data)+1): for pos in range(1, len(fc_data) + 1):
stamp = fc_data[f'fc{pos}']['stamp'] stamp = fc_data[f'fc{pos}']['stamp']
icon = weathericons[fc_data[f'fc{pos}']['icon']] icon = weathericons[fc_data[f'fc{pos}']['icon']]
temp = fc_data[f'fc{pos}']['temp'] temp = fc_data[f'fc{pos}']['temp']
write(im_black, eval(f'stamp_fc{pos}'), (col_width, row_height), write(im_black, eval(f'stamp_fc{pos}'), (col_width, row_height),
stamp, font = self.font) stamp, font=self.font)
draw_icon(im_colour, eval(f'icon_fc{pos}'), (col_width, row_height+line_gap*2), draw_icon(im_colour, eval(f'icon_fc{pos}'), (col_width, row_height + line_gap * 2),
icon) icon)
write(im_black, eval(f'temp_fc{pos}'), (col_width, row_height), write(im_black, eval(f'temp_fc{pos}'), (col_width, row_height),
temp, font = self.font) temp, font=self.font)
border_h = row3 + row_height border_h = row3 + row_height
border_w = col_width - 3 #leave 3 pixels gap border_w = col_width - 3 # leave 3 pixels gap
# Add borders around each sub-section # Add borders around each sub-section
draw_border(im_black, (col1, row1), (col_width*3 - 3, border_h), draw_border(im_black, (col1, row1), (col_width * 3 - 3, border_h),
shrinkage=(0,0)) shrinkage=(0, 0))
for _ in range(4,8): for _ in range(4, 8):
draw_border(im_black, (eval(f'col{_}'), row1), (border_w, border_h), draw_border(im_black, (eval(f'col{_}'), row1), (border_w, border_h),
shrinkage=(0,0)) shrinkage=(0, 0))
# return the images ready for the display # return the images ready for the display
return im_black, im_colour return im_black, im_colour
if __name__ == '__main__': if __name__ == '__main__':
print(f'running {filename} in standalone mode') print(f'running {filename} in standalone mode')

View File

@@ -1,6 +1,9 @@
#!python3
import abc import abc
from inkycal.custom import * from inkycal.custom import *
class inkycal_module(metaclass=abc.ABCMeta): class inkycal_module(metaclass=abc.ABCMeta):
"""Generic base class for inkycal modules""" """Generic base class for inkycal modules"""
@@ -23,7 +26,7 @@ class inkycal_module(metaclass=abc.ABCMeta):
self.fontsize = conf["fontsize"] self.fontsize = conf["fontsize"]
self.font = ImageFont.truetype( self.font = ImageFont.truetype(
fonts['NotoSansUI-Regular'], size = self.fontsize) fonts['NotoSansUI-Regular'], size=self.fontsize)
def set(self, help=False, **kwargs): def set(self, help=False, **kwargs):
"""Set attributes of class, e.g. class.set(key=value) """Set attributes of class, e.g. class.set(key=value)
@@ -87,6 +90,3 @@ class inkycal_module(metaclass=abc.ABCMeta):
except: except:
raise Exception( raise Exception(
'Ohoh, something went wrong while trying to get the config of this module') 'Ohoh, something went wrong while trying to get the config of this module')

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
iCalendar parser test (ical_parser) iCalendar parser test (ical_parser)
@@ -14,10 +13,10 @@ from urllib.request import urlopen
from inkycal.modules.ical_parser import iCalendar from inkycal.modules.ical_parser import iCalendar
from helper_functions import * from helper_functions import *
ical = iCalendar() ical = iCalendar()
test_ical = 'https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics' test_ical = 'https://calendar.google.com/calendar/ical/en.usa%23holiday%40group.v.calendar.google.com/public/basic.ics'
class ical_parser_test(unittest.TestCase): class ical_parser_test(unittest.TestCase):
def test_load_url(self): def test_load_url(self):
@@ -49,8 +48,8 @@ class ical_parser_test(unittest.TestCase):
print('OK') print('OK')
os.remove('dummy.ical') os.remove('dummy.ical')
if __name__ == '__main__':
if __name__ == '__main__':
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))

View File

@@ -1,5 +1,5 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Agenda test (inkycal_agenda) Agenda test (inkycal_agenda)
Copyright by aceisace Copyright by aceisace
@@ -7,16 +7,16 @@ Copyright by aceisace
import unittest import unittest
from inkycal.modules import Agenda as Module from inkycal.modules import Agenda as Module
from helper_functions import * from helper_functions import *
environment = get_environment() environment = get_environment()
# Set to True to preview images. Only works on Raspberry Pi OS with Desktop # Set to True to preview images. Only works on Raspberry Pi OS with Desktop
use_preview = False use_preview = False
sample_url = "https://www.officeholidays.com/ics-fed/usa" sample_url = "https://www.officeholidays.com/ics-fed/usa"
tests = [ tests = [
{ {
"name": "Agenda", "name": "Agenda",
"config": { "config": {
"size": [400, 200], "size": [400, 200],
@@ -29,8 +29,8 @@ tests = [
"fontsize": 12, "fontsize": 12,
"language": "en" "language": "en"
} }
}, },
{ {
"name": "Agenda", "name": "Agenda",
"config": { "config": {
"size": [500, 800], "size": [500, 800],
@@ -43,8 +43,8 @@ tests = [
"fontsize": 12, "fontsize": 12,
"language": "en" "language": "en"
} }
}, },
{ {
"position": 1, "position": 1,
"name": "Agenda", "name": "Agenda",
"config": { "config": {
@@ -58,27 +58,27 @@ tests = [
"fontsize": 12, "fontsize": 12,
"language": "en" "language": "en"
} }
}, },
] ]
class module_test(unittest.TestCase): class module_test(unittest.TestCase):
def test_get_config(self): def test_get_config(self):
print('getting data for web-ui...', end = "") print('getting data for web-ui...', end="")
Module.get_config() Module.get_config()
print('OK') print('OK')
def test_generate_image(self): def test_generate_image(self):
for test in tests: for test in tests:
print(f'test {tests.index(test)+1} generating image..') print(f'test {tests.index(test) + 1} generating image..')
module = Module(test) module = Module(test)
im_black, im_colour = module.generate_image() im_black, im_colour = module.generate_image()
print('OK') print('OK')
if use_preview == True and environment == 'Raspberry': if use_preview == True and environment == 'Raspberry':
preview(merge(im_black, im_colour)) preview(merge(im_black, im_colour))
if __name__ == '__main__':
if __name__ == '__main__':
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Calendar test (inkycal_calendar) Calendar test (inkycal_calendar)
@@ -9,16 +8,16 @@ Copyright by aceisace
import unittest import unittest
from inkycal.modules import Calendar as Module from inkycal.modules import Calendar as Module
from helper_functions import * from helper_functions import *
environment = get_environment() environment = get_environment()
# Set to True to preview images. Only works on Raspberry Pi OS with Desktop # Set to True to preview images. Only works on Raspberry Pi OS with Desktop
use_preview = False use_preview = False
sample_url = "https://www.officeholidays.com/ics-fed/usa" sample_url = "https://www.officeholidays.com/ics-fed/usa"
tests = [ tests = [
{ {
"name": "Calendar", "name": "Calendar",
"config": { "config": {
"size": [500, 500], "size": [500, 500],
@@ -27,10 +26,10 @@ tests = [
"ical_urls": sample_url, "ical_urls": sample_url,
"ical_files": None, "ical_files": None,
"date_format": "D MMM", "time_format": "HH:mm", "date_format": "D MMM", "time_format": "HH:mm",
"padding_x": 10,"padding_y": 10,"fontsize": 12,"language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Calendar", "name": "Calendar",
"config": { "config": {
"size": [400, 800], "size": [400, 800],
@@ -39,10 +38,10 @@ tests = [
"ical_urls": sample_url, "ical_urls": sample_url,
"ical_files": None, "ical_files": None,
"date_format": "D MMM", "time_format": "HH:mm", "date_format": "D MMM", "time_format": "HH:mm",
"padding_x": 10,"padding_y": 10,"fontsize": 12,"language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Calendar", "name": "Calendar",
"config": { "config": {
"size": [400, 800], "size": [400, 800],
@@ -51,10 +50,10 @@ tests = [
"ical_urls": sample_url, "ical_urls": sample_url,
"ical_files": None, "ical_files": None,
"date_format": "D MMM", "time_format": "HH:mm", "date_format": "D MMM", "time_format": "HH:mm",
"padding_x": 10,"padding_y": 10,"fontsize": 12,"language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Calendar", "name": "Calendar",
"config": { "config": {
"size": [400, 800], "size": [400, 800],
@@ -63,28 +62,29 @@ tests = [
"ical_urls": None, "ical_urls": None,
"ical_files": None, "ical_files": None,
"date_format": "D MMM", "time_format": "HH:mm", "date_format": "D MMM", "time_format": "HH:mm",
"padding_x": 10,"padding_y": 10,"fontsize": 12,"language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
] ]
class module_test(unittest.TestCase): class module_test(unittest.TestCase):
def test_get_config(self): def test_get_config(self):
print('getting data for web-ui...', end = "") print('getting data for web-ui...', end="")
Module.get_config() Module.get_config()
print('OK') print('OK')
def test_generate_image(self): def test_generate_image(self):
for test in tests: for test in tests:
print(f'test {tests.index(test)+1} generating image..', end="") print(f'test {tests.index(test) + 1} generating image..', end="")
module = Module(test) module = Module(test)
im_black, im_colour = module.generate_image() im_black, im_colour = module.generate_image()
print('OK') print('OK')
if use_preview == True and environment == 'Raspberry': if use_preview == True and environment == 'Raspberry':
preview(merge(im_black, im_colour)) preview(merge(im_black, im_colour))
if __name__ == '__main__':
if __name__ == '__main__':
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Feeds test (inykcal_feeds) Feeds test (inykcal_feeds)
@@ -9,61 +8,62 @@ Copyright by aceisace
import unittest import unittest
from inkycal.modules import Feeds as Module from inkycal.modules import Feeds as Module
from helper_functions import * from helper_functions import *
environment = get_environment() environment = get_environment()
# Set to True to preview images. Only works on Raspberry Pi OS with Desktop # Set to True to preview images. Only works on Raspberry Pi OS with Desktop
use_preview = False use_preview = False
tests = [ tests = [
{ {
"name": "Feeds", "name": "Feeds",
"config": { "config": {
"size": [400,200], "size": [400, 200],
"feed_urls": "http://feeds.bbci.co.uk/news/world/rss.xml#", "feed_urls": "http://feeds.bbci.co.uk/news/world/rss.xml#",
"shuffle_feeds": True, "shuffle_feeds": True,
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Feeds", "name": "Feeds",
"config": { "config": {
"size": [400,100], "size": [400, 100],
"feed_urls": "http://feeds.bbci.co.uk/news/world/rss.xml#", "feed_urls": "http://feeds.bbci.co.uk/news/world/rss.xml#",
"shuffle_feeds": False, "shuffle_feeds": False,
"padding_x": 10, "padding_y": 10, "fontsize": 14, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 14, "language": "en"
} }
}, },
{ {
"name": "Feeds", "name": "Feeds",
"config": { "config": {
"size": [400,100], "size": [400, 100],
"feed_urls": "https://www.anekdot.ru/rss/export_top.xml", "feed_urls": "https://www.anekdot.ru/rss/export_top.xml",
"shuffle_feeds": False, "shuffle_feeds": False,
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
] ]
class module_test(unittest.TestCase): class module_test(unittest.TestCase):
def test_get_config(self): def test_get_config(self):
print('getting data for web-ui...', end = "") print('getting data for web-ui...', end="")
Module.get_config() Module.get_config()
print('OK') print('OK')
def test_generate_image(self): def test_generate_image(self):
for test in tests: for test in tests:
print(f'test {tests.index(test)+1} generating image..') print(f'test {tests.index(test) + 1} generating image..')
module = Module(test) module = Module(test)
im_black, im_colour = module.generate_image() im_black, im_colour = module.generate_image()
print('OK') print('OK')
if use_preview == True and environment == 'Raspberry': if use_preview == True and environment == 'Raspberry':
preview(merge(im_black, im_colour)) preview(merge(im_black, im_colour))
if __name__ == '__main__':
if __name__ == '__main__':
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))
unittest.main() unittest.main()

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Image test (inkycal_image) Image test (inkycal_image)
@@ -10,71 +9,71 @@ import unittest
from inkycal.modules import Inkyimage as Module from inkycal.modules import Inkyimage as Module
from inkycal.custom import top_level from inkycal.custom import top_level
from helper_functions import * from helper_functions import *
environment = get_environment() environment = get_environment()
# Set to True to preview images. Only works on Raspberry Pi OS with Desktop # Set to True to preview images. Only works on Raspberry Pi OS with Desktop
use_preview = False use_preview = False
test_path = f'{top_level}/Gallery/coffee.png' test_path = f'{top_level}/Gallery/coffee.png'
tests = [ tests = [
{ {
"name": "Inkyimage", "name": "Inkyimage",
"config": { "config": {
"size": [400,200], "size": [400, 200],
"path": test_path, "path": test_path,
"palette": "bwr", "palette": "bwr",
"autoflip": True, "autoflip": True,
"orientation": "vertical", "orientation": "vertical",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Inkyimage", "name": "Inkyimage",
"config": { "config": {
"size": [800,500], "size": [800, 500],
"path": test_path, "path": test_path,
"palette": "bwy", "palette": "bwy",
"autoflip": True, "autoflip": True,
"orientation": "vertical", "orientation": "vertical",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Inkyimage", "name": "Inkyimage",
"config": { "config": {
"size": [400,100], "size": [400, 100],
"path": test_path, "path": test_path,
"palette": "bw", "palette": "bw",
"autoflip": False, "autoflip": False,
"orientation": "vertical", "orientation": "vertical",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Inkyimage", "name": "Inkyimage",
"config": { "config": {
"size": [400,100], "size": [400, 100],
"path": test_path, "path": test_path,
"palette": "bwr", "palette": "bwr",
"autoflip": True, "autoflip": True,
"orientation": "vertical", "orientation": "vertical",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Inkyimage", "name": "Inkyimage",
"config": { "config": {
"size": [400,100], "size": [400, 100],
"path": test_path, "path": test_path,
"palette": "bwy", "palette": "bwy",
"autoflip": True, "autoflip": True,
"orientation": "horizontal", "orientation": "horizontal",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Inkyimage", "name": "Inkyimage",
"config": { "config": {
"size": [500, 800], "size": [500, 800],
@@ -84,8 +83,8 @@ tests = [
"orientation": "vertical", "orientation": "vertical",
"padding_x": 0, "padding_y": 0, "fontsize": 12, "language": "en" "padding_x": 0, "padding_y": 0, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Inkyimage", "name": "Inkyimage",
"config": { "config": {
"size": [500, 800], "size": [500, 800],
@@ -95,26 +94,27 @@ tests = [
"orientation": "vertical", "orientation": "vertical",
"padding_x": 20, "padding_y": 20, "fontsize": 12, "language": "en" "padding_x": 20, "padding_y": 20, "fontsize": 12, "language": "en"
} }
}, },
] ]
class module_test(unittest.TestCase): class module_test(unittest.TestCase):
def test_get_config(self): def test_get_config(self):
print('getting data for web-ui...', end = "") print('getting data for web-ui...', end="")
Module.get_config() Module.get_config()
print('OK') print('OK')
def test_generate_image(self): def test_generate_image(self):
for test in tests: for test in tests:
print(f'test {tests.index(test)+1} generating image..') print(f'test {tests.index(test) + 1} generating image..')
module = Module(test) module = Module(test)
im_black, im_colour = module.generate_image() im_black, im_colour = module.generate_image()
print('OK') print('OK')
if use_preview == True and environment == 'Raspberry': if use_preview == True and environment == 'Raspberry':
preview(merge(im_black, im_colour)) preview(merge(im_black, im_colour))
if __name__ == '__main__':
if __name__ == '__main__':
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Jokes test (inkycal_jokes) Jokes test (inkycal_jokes)

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Slideshow test (inkycal_slideshow) Slideshow test (inkycal_slideshow)

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Stocks test (inkycal_stocks) Stocks test (inkycal_stocks)
@@ -9,80 +8,81 @@ Copyright by aceisace
import unittest import unittest
from inkycal.modules import Stocks as Module from inkycal.modules import Stocks as Module
from helper_functions import * from helper_functions import *
environment = get_environment() environment = get_environment()
# Set to True to preview images. Only works on Raspberry Pi OS with Desktop # Set to True to preview images. Only works on Raspberry Pi OS with Desktop
use_preview = False use_preview = False
tests = [ tests = [
{ {
"name": "Stocks", "name": "Stocks",
"config": { "config": {
"size": [528, 30], "size": [528, 30],
"tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'], "tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'],
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Stocks", "name": "Stocks",
"config": { "config": {
"size": [528, 50], "size": [528, 50],
"tickers": [], "tickers": [],
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Stocks", "name": "Stocks",
"config": { "config": {
"size": [528, 200], "size": [528, 200],
"tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'], "tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'],
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Stocks", "name": "Stocks",
"config": { "config": {
"size": [528, 800], "size": [528, 800],
"tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'], "tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'],
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Stocks", "name": "Stocks",
"config": { "config": {
"size": [528, 100], "size": [528, 100],
"tickers": "TSLA,AMD,NVDA,^DJI,BTC-USD,EURUSD=X", "tickers": "TSLA,AMD,NVDA,^DJI,BTC-USD,EURUSD=X",
"padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 12, "language": "en"
} }
}, },
{ {
"name": "Stocks", "name": "Stocks",
"config": { "config": {
"size": [528, 400], "size": [528, 400],
"tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'], "tickers": ['TSLA', 'AMD', 'NVDA', '^DJI', 'BTC-USD', 'EURUSD=X'],
"padding_x": 10, "padding_y": 10, "fontsize": 14, "language": "en" "padding_x": 10, "padding_y": 10, "fontsize": 14, "language": "en"
} }
}, },
] ]
class module_test(unittest.TestCase): class module_test(unittest.TestCase):
def test_get_config(self): def test_get_config(self):
print('getting data for web-ui...', end = "") print('getting data for web-ui...', end="")
Module.get_config() Module.get_config()
print('OK') print('OK')
def test_generate_image(self): def test_generate_image(self):
for test in tests: for test in tests:
print(f'test {tests.index(test)+1} generating image..') print(f'test {tests.index(test) + 1} generating image..')
module = Module(test) module = Module(test)
im_black, im_colour = module.generate_image() im_black, im_colour = module.generate_image()
print('OK') print('OK')
if use_preview == True and environment == 'Raspberry': if use_preview == True and environment == 'Raspberry':
preview(merge(im_black, im_colour)) preview(merge(im_black, im_colour))
if __name__ == '__main__':
if __name__ == '__main__':
logger = logging.getLogger() logger = logging.getLogger()
logger.level = logging.DEBUG logger.level = logging.DEBUG
logger.addHandler(logging.StreamHandler(sys.stdout)) logger.addHandler(logging.StreamHandler(sys.stdout))

View File

@@ -1,2 +0,0 @@
import unittest
from inkycal.modules import Todoist as Module

View File

@@ -1,3 +1,5 @@
#!python3
import unittest import unittest
from inkycal.modules import Todoist as Module from inkycal.modules import Todoist as Module
from helper_functions import * from helper_functions import *

View File

@@ -1,3 +1,5 @@
#!python3
import unittest import unittest
from inkycal.modules import Weather as Module from inkycal.modules import Weather as Module
from helper_functions import * from helper_functions import *

View File

@@ -1,5 +1,4 @@
#!/usr/bin/python3 #!python3
# -*- coding: utf-8 -*-
""" """
Main test (main) Main test (main)

View File

@@ -1,5 +1,4 @@
#!python3 #!python3
# -*- coding: utf-8 -*-
from setuptools import setup from setuptools import setup
from os import path from os import path