You've already forked eink-calendar
mirror of
https://github.com/javierpena/eink-calendar.git
synced 2025-08-10 21:52:01 +02:00
First upload
This commit is contained in:
38
drivers/caldavprovider.py
Normal file
38
drivers/caldavprovider.py
Normal file
@@ -0,0 +1,38 @@
|
||||
from datetime import datetime
|
||||
|
||||
import caldav
|
||||
import icalendar
|
||||
import pytz
|
||||
import urllib3
|
||||
|
||||
urllib3.disable_warnings()
|
||||
|
||||
class CalDavProvider():
|
||||
def __init__(self, username, password):
|
||||
self.tz = pytz.timezone('Europe/Madrid')
|
||||
self.username = username
|
||||
self.password = password
|
||||
|
||||
def get_calendar(self, url, date_start, date_end):
|
||||
# print("%s %s" % (date_start, date_end))
|
||||
client = caldav.DAVClient(url=url, username=self.username, password=self.password, ssl_verify_cert=False)
|
||||
calendar = caldav.Calendar(client=client, url=url)
|
||||
returned_events = []
|
||||
|
||||
events_found = calendar.date_search(
|
||||
start=date_start, end=date_end,
|
||||
compfilter='VEVENT', expand=True)
|
||||
if events_found:
|
||||
for event in events_found:
|
||||
cal = icalendar.Calendar.from_ical(event.data)
|
||||
single_event = {}
|
||||
for event in cal.walk('vevent'):
|
||||
date_start = event.get('dtstart')
|
||||
duration = event.get('duration')
|
||||
summary = event.get('summary')
|
||||
single_event['event_start'] = date_start.dt.astimezone(self.tz)
|
||||
single_event['event_end'] = (date_start.dt + duration.dt).astimezone(self.tz)
|
||||
single_event['event_title'] = summary
|
||||
returned_events.append(single_event)
|
||||
|
||||
return returned_events
|
25
drivers/einkdriver.py
Normal file
25
drivers/einkdriver.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from . import epd7in5bc
|
||||
|
||||
class EinkDriver():
|
||||
def __init__(self, xres, yres):
|
||||
self.epd = epd7in5bc.EPD()
|
||||
self.epd.init()
|
||||
self.epd.Clear()
|
||||
self.xres = xres
|
||||
self.yres = yres
|
||||
|
||||
# image1: black/white image
|
||||
# image2: black/yellow image
|
||||
def display(self, image1=None, image2=None):
|
||||
self.epd.init()
|
||||
self.epd.display(self.epd.getbuffer(image1), self.epd.getbuffer(image2))
|
||||
self.epd.sleep()
|
||||
|
||||
def end(self):
|
||||
print("Ending e-ink driver")
|
||||
self.epd.init()
|
||||
self.epd.Clear()
|
||||
self.epd.sleep()
|
||||
self.epd.Dev_exit()
|
||||
print("e-ink driver finished")
|
||||
|
197
drivers/epd7in5bc.py
Normal file
197
drivers/epd7in5bc.py
Normal file
@@ -0,0 +1,197 @@
|
||||
# *****************************************************************************
|
||||
# * | File : epd7in5bc.py
|
||||
# * | Author : Waveshare team
|
||||
# * | Function : Electronic paper driver
|
||||
# * | Info :
|
||||
# *----------------
|
||||
# * | This version: V4.0
|
||||
# * | Date : 2019-06-20
|
||||
# # | Info : python demo
|
||||
# -----------------------------------------------------------------------------
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
|
||||
import logging
|
||||
from . import epdconfig
|
||||
|
||||
# Display resolution
|
||||
EPD_WIDTH = 640
|
||||
EPD_HEIGHT = 384
|
||||
|
||||
class EPD:
|
||||
def __init__(self):
|
||||
self.reset_pin = epdconfig.RST_PIN
|
||||
self.dc_pin = epdconfig.DC_PIN
|
||||
self.busy_pin = epdconfig.BUSY_PIN
|
||||
self.cs_pin = epdconfig.CS_PIN
|
||||
self.width = EPD_WIDTH
|
||||
self.height = EPD_HEIGHT
|
||||
|
||||
# Hardware reset
|
||||
def reset(self):
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(200)
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(10)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(200)
|
||||
|
||||
def send_command(self, command):
|
||||
epdconfig.digital_write(self.dc_pin, 0)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([command])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data(self, data):
|
||||
epdconfig.digital_write(self.dc_pin, 1)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([data])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data_array(self, data):
|
||||
epdconfig.digital_write(self.dc_pin, 1)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.SPI.writebytes2(data)
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def ReadBusy(self):
|
||||
logging.debug("e-Paper busy")
|
||||
while(epdconfig.digital_read(self.busy_pin) == 0): # 0: idle, 1: busy
|
||||
epdconfig.delay_ms(100)
|
||||
logging.debug("e-Paper busy release")
|
||||
|
||||
def init(self):
|
||||
if (epdconfig.module_init() != 0):
|
||||
return -1
|
||||
|
||||
self.reset()
|
||||
|
||||
self.send_command(0x01) # POWER_SETTING
|
||||
self.send_data(0x37)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x00) # PANEL_SETTING
|
||||
self.send_data(0xCF)
|
||||
self.send_data(0x08)
|
||||
|
||||
self.send_command(0x30) # PLL_CONTROL
|
||||
self.send_data(0x3A) # PLL: 0-15:0x3C, 15+:0x3A
|
||||
|
||||
self.send_command(0x82) # VCM_DC_SETTING
|
||||
self.send_data(0x28) #all temperature range
|
||||
|
||||
self.send_command(0x06) # BOOSTER_SOFT_START
|
||||
self.send_data(0xc7)
|
||||
self.send_data(0xcc)
|
||||
self.send_data(0x15)
|
||||
|
||||
self.send_command(0x50) # VCOM AND DATA INTERVAL SETTING
|
||||
self.send_data(0x77)
|
||||
|
||||
self.send_command(0x60) # TCON_SETTING
|
||||
self.send_data(0x22)
|
||||
|
||||
self.send_command(0x65) # FLASH CONTROL
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x61) # TCON_RESOLUTION
|
||||
self.send_data(self.width >> 8) # source 640
|
||||
self.send_data(self.width & 0xff)
|
||||
self.send_data(self.height >> 8) # gate 384
|
||||
self.send_data(self.height & 0xff)
|
||||
|
||||
self.send_command(0xe5) # FLASH MODE
|
||||
self.send_data(0x03)
|
||||
|
||||
return 0
|
||||
|
||||
def getbuffer(self, image):
|
||||
img = image
|
||||
imwidth, imheight = img.size
|
||||
if(imwidth == self.width and imheight == self.height):
|
||||
img = img.convert('1')
|
||||
elif(imwidth == self.height and imheight == self.width):
|
||||
img = img.rotate(90, expand=True).convert('1')
|
||||
else:
|
||||
logging.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height))
|
||||
# return a blank buffer
|
||||
return [0x00] * (int(self.width/8) * self.height)
|
||||
|
||||
buf = bytearray(img.tobytes('raw'))
|
||||
return buf
|
||||
|
||||
def display(self, imageblack, imagered):
|
||||
buf = [0x00] * ((self.width // 2) * self.height)
|
||||
|
||||
for i in range(0, int(self.width / 8 * self.height)):
|
||||
temp1 = imageblack[i]
|
||||
temp2 = imagered[i]
|
||||
j = 0
|
||||
while (j < 8):
|
||||
if ((temp2 & 0x80) == 0x00):
|
||||
temp3 = 0x04 #red
|
||||
elif ((temp1 & 0x80) == 0x00):
|
||||
temp3 = 0x00 #black
|
||||
else:
|
||||
temp3 = 0x03 #white
|
||||
|
||||
temp3 = (temp3 << 4) & 0xFF
|
||||
temp1 = (temp1 << 1) & 0xFF
|
||||
temp2 = (temp2 << 1) & 0xFF
|
||||
j += 1
|
||||
if((temp2 & 0x80) == 0x00):
|
||||
temp3 |= 0x04 #red
|
||||
elif ((temp1 & 0x80) == 0x00):
|
||||
temp3 |= 0x00 #black
|
||||
else:
|
||||
temp3 |= 0x03 #white
|
||||
temp1 = (temp1 << 1) & 0xFF
|
||||
temp2 = (temp2 << 1) & 0xFF
|
||||
buf[i * 4 + (j//2)] = temp3
|
||||
j += 1
|
||||
|
||||
self.send_command(0x10)
|
||||
self.send_data_array(buf)
|
||||
self.send_command(0x04) # POWER ON
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) # display refresh
|
||||
epdconfig.delay_ms(100)
|
||||
self.ReadBusy()
|
||||
|
||||
def Clear(self):
|
||||
buf = [0x33] * ((self.width // 2) * self.height)
|
||||
self.send_command(0x10)
|
||||
self.send_data_array(buf)
|
||||
self.send_command(0x04) # POWER ON
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) # display refresh
|
||||
epdconfig.delay_ms(100)
|
||||
self.ReadBusy()
|
||||
|
||||
def sleep(self):
|
||||
self.send_command(0x02) # POWER_OFF
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x07) # DEEP_SLEEP
|
||||
self.send_data(0XA5)
|
||||
|
||||
def Dev_exit(self):
|
||||
epdconfig.module_exit()
|
||||
### END OF FILE ###
|
156
drivers/epdconfig.py
Normal file
156
drivers/epdconfig.py
Normal file
@@ -0,0 +1,156 @@
|
||||
# /*****************************************************************************
|
||||
# * | File : epdconfig.py
|
||||
# * | Author : Waveshare team
|
||||
# * | Function : Hardware underlying interface
|
||||
# * | Info :
|
||||
# *----------------
|
||||
# * | This version: V1.0
|
||||
# * | Date : 2019-06-21
|
||||
# * | Info :
|
||||
# ******************************************************************************
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documnetation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in
|
||||
# all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS OR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
#
|
||||
|
||||
import os
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
|
||||
|
||||
class RaspberryPi:
|
||||
# Pin definition
|
||||
RST_PIN = 17
|
||||
DC_PIN = 25
|
||||
CS_PIN = 8
|
||||
BUSY_PIN = 24
|
||||
|
||||
def __init__(self):
|
||||
import spidev
|
||||
import RPi.GPIO
|
||||
|
||||
self.GPIO = RPi.GPIO
|
||||
|
||||
# SPI device, bus = 0, device = 0
|
||||
self.SPI = spidev.SpiDev(0, 0)
|
||||
|
||||
def digital_write(self, pin, value):
|
||||
self.GPIO.output(pin, value)
|
||||
|
||||
def digital_read(self, pin):
|
||||
return self.GPIO.input(pin)
|
||||
|
||||
def delay_ms(self, delaytime):
|
||||
time.sleep(delaytime / 1000.0)
|
||||
|
||||
def spi_writebyte(self, data):
|
||||
self.SPI.writebytes(data)
|
||||
|
||||
def module_init(self):
|
||||
self.GPIO.setmode(self.GPIO.BCM)
|
||||
self.GPIO.setwarnings(False)
|
||||
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
|
||||
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
|
||||
self.GPIO.setup(self.CS_PIN, self.GPIO.OUT)
|
||||
self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
|
||||
self.SPI.max_speed_hz = 4000000
|
||||
self.SPI.mode = 0b00
|
||||
return 0
|
||||
|
||||
def module_exit(self):
|
||||
logging.debug("spi end")
|
||||
self.SPI.close()
|
||||
|
||||
logging.debug("close 5V, Module enters 0 power consumption ...")
|
||||
self.GPIO.setmode(self.GPIO.BCM)
|
||||
self.GPIO.output(self.RST_PIN, 0)
|
||||
self.GPIO.output(self.DC_PIN, 0)
|
||||
|
||||
self.GPIO.cleanup()
|
||||
|
||||
|
||||
class JetsonNano:
|
||||
# Pin definition
|
||||
RST_PIN = 17
|
||||
DC_PIN = 25
|
||||
CS_PIN = 8
|
||||
BUSY_PIN = 24
|
||||
|
||||
def __init__(self):
|
||||
import ctypes
|
||||
find_dirs = [
|
||||
os.path.dirname(os.path.realpath(__file__)),
|
||||
'/usr/local/lib',
|
||||
'/usr/lib',
|
||||
]
|
||||
self.SPI = None
|
||||
for find_dir in find_dirs:
|
||||
so_filename = os.path.join(find_dir, 'sysfs_software_spi.so')
|
||||
if os.path.exists(so_filename):
|
||||
self.SPI = ctypes.cdll.LoadLibrary(so_filename)
|
||||
break
|
||||
if self.SPI is None:
|
||||
raise RuntimeError('Cannot find sysfs_software_spi.so')
|
||||
|
||||
import Jetson.GPIO
|
||||
self.GPIO = Jetson.GPIO
|
||||
|
||||
def digital_write(self, pin, value):
|
||||
self.GPIO.output(pin, value)
|
||||
|
||||
def digital_read(self, pin):
|
||||
return self.GPIO.input(self.BUSY_PIN)
|
||||
|
||||
def delay_ms(self, delaytime):
|
||||
time.sleep(delaytime / 1000.0)
|
||||
|
||||
def spi_writebyte(self, data):
|
||||
self.SPI.SYSFS_software_spi_transfer(data[0])
|
||||
|
||||
def module_init(self):
|
||||
self.GPIO.setmode(self.GPIO.BCM)
|
||||
self.GPIO.setwarnings(False)
|
||||
self.GPIO.setup(self.RST_PIN, self.GPIO.OUT)
|
||||
self.GPIO.setup(self.DC_PIN, self.GPIO.OUT)
|
||||
self.GPIO.setup(self.CS_PIN, self.GPIO.OUT)
|
||||
self.GPIO.setup(self.BUSY_PIN, self.GPIO.IN)
|
||||
self.SPI.SYSFS_software_spi_begin()
|
||||
return 0
|
||||
|
||||
def module_exit(self):
|
||||
logging.debug("spi end")
|
||||
self.SPI.SYSFS_software_spi_end()
|
||||
|
||||
logging.debug("close 5V, Module enters 0 power consumption ...")
|
||||
self.GPIO.output(self.RST_PIN, 0)
|
||||
self.GPIO.output(self.DC_PIN, 0)
|
||||
|
||||
self.GPIO.cleanup()
|
||||
|
||||
|
||||
if os.path.exists('/sys/bus/platform/drivers/gpiomem-bcm2835'):
|
||||
implementation = RaspberryPi()
|
||||
else:
|
||||
implementation = JetsonNano()
|
||||
|
||||
for func in [x for x in dir(implementation) if not x.startswith('_')]:
|
||||
setattr(sys.modules[__name__], func, getattr(implementation, func))
|
||||
|
||||
|
||||
### END OF FILE ###
|
||||
|
52
drivers/gpiodriver.py
Normal file
52
drivers/gpiodriver.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from datetime import datetime
|
||||
import RPi.GPIO as GPIO
|
||||
import time
|
||||
|
||||
row_channels = [6, 5, 19, 13]
|
||||
column_channel = 26
|
||||
|
||||
class GPIODriver():
|
||||
def __init__(self):
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
GPIO.setup(row_channels, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
|
||||
GPIO.setup(column_channel, GPIO.OUT)
|
||||
|
||||
def wait_for_keypress(self, timeout=60):
|
||||
self.pressed = None
|
||||
|
||||
def callback_1(channel):
|
||||
# print("Pressed key 1")
|
||||
self.pressed = 1
|
||||
|
||||
def callback_2(channel):
|
||||
# print("Pressed key 2")
|
||||
self.pressed = 2
|
||||
|
||||
def callback_3(channel):
|
||||
# print("Pressed key 3")
|
||||
self.pressed = 3
|
||||
|
||||
def callback_4(channel):
|
||||
# print("Pressed key 4")
|
||||
self.pressed = 4
|
||||
|
||||
GPIO.add_event_detect(row_channels[0], GPIO.RISING, callback=callback_1, bouncetime=500)
|
||||
GPIO.add_event_detect(row_channels[1], GPIO.RISING, callback=callback_2, bouncetime=500)
|
||||
GPIO.add_event_detect(row_channels[2], GPIO.RISING, callback=callback_3, bouncetime=500)
|
||||
GPIO.add_event_detect(row_channels[3], GPIO.RISING, callback=callback_4, bouncetime=500)
|
||||
GPIO.output(column_channel, GPIO.HIGH)
|
||||
start_time = datetime.now()
|
||||
while not self.pressed:
|
||||
time.sleep(1)
|
||||
current_time = datetime.now()
|
||||
delta = current_time - start_time
|
||||
if delta.seconds > timeout:
|
||||
for chan in row_channels:
|
||||
GPIO.remove_event_detect(chan)
|
||||
GPIO.output(column_channel, GPIO.LOW)
|
||||
return None
|
||||
|
||||
for chan in row_channels:
|
||||
GPIO.remove_event_detect(chan)
|
||||
GPIO.output(column_channel, GPIO.LOW)
|
||||
return self.pressed
|
61
drivers/pygamedriver.py
Normal file
61
drivers/pygamedriver.py
Normal file
@@ -0,0 +1,61 @@
|
||||
from datetime import datetime
|
||||
import pygame
|
||||
import sys
|
||||
|
||||
class PygameDriver():
|
||||
def __init__(self, xres, yres):
|
||||
pygame.init()
|
||||
self.screen = pygame.display.set_mode((xres, yres))
|
||||
self.xres = xres
|
||||
self.yres = yres
|
||||
|
||||
# image1: black/white image
|
||||
# image2: black/yellow image
|
||||
def display(self, image1=None, image2=None):
|
||||
if image1:
|
||||
raw_str1 = image1.convert('RGBA').tobytes("raw", 'RGBA')
|
||||
pygame_surface1 = pygame.image.fromstring(raw_str1, (self.xres, self.yres), 'RGBA')
|
||||
self.screen.blit(pygame_surface1, (0, 0))
|
||||
|
||||
if image2:
|
||||
raw_str2 = image2.convert('RGB').tobytes("raw", 'RGB')
|
||||
pygame_surface2 = pygame.image.fromstring(raw_str2, (self.xres, self.yres), 'RGB')
|
||||
pygame_surface2.set_colorkey((255, 255, 255))
|
||||
|
||||
image_pixel_array = pygame.PixelArray(pygame_surface2)
|
||||
image_pixel_array.replace((0, 0, 0), (127, 100, 0))
|
||||
del image_pixel_array
|
||||
|
||||
self.screen.blit(pygame_surface2, (0, 0))
|
||||
|
||||
pygame.display.flip()
|
||||
|
||||
def end(self):
|
||||
pygame.quit()
|
||||
|
||||
class PygameKBDriver():
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def wait_for_keypress(self, timeout=60):
|
||||
start_time = datetime.now()
|
||||
while True:
|
||||
current_time = datetime.now()
|
||||
delta = current_time - start_time
|
||||
if delta.seconds > timeout:
|
||||
return None
|
||||
events = pygame.event.get()
|
||||
for event in events:
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit(0)
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_1:
|
||||
return 1
|
||||
elif event.key == pygame.K_2:
|
||||
return 2
|
||||
elif event.key == pygame.K_3:
|
||||
return 3
|
||||
elif event.key == pygame.K_4:
|
||||
return 4
|
||||
pygame.time.wait(1000)
|
Reference in New Issue
Block a user