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