Touchscreen driver POC
Example documentation
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
# *****************************************************************************
|
||||
# * | File : epd2in13_V2.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
|
||||
import numpy as np
|
||||
|
||||
# Display resolution
|
||||
EPD_WIDTH = 122
|
||||
EPD_HEIGHT = 250
|
||||
|
||||
class EPD_2IN13_V2:
|
||||
def __init__(self):
|
||||
self.reset_pin = epdconfig.EPD_RST_PIN
|
||||
self.dc_pin = epdconfig.EPD_DC_PIN
|
||||
self.busy_pin = epdconfig.EPD_BUSY_PIN
|
||||
self.cs_pin = epdconfig.EPD_CS_PIN
|
||||
self.width = EPD_WIDTH
|
||||
self.height = EPD_HEIGHT
|
||||
epdconfig.address = 0x14
|
||||
|
||||
FULL_UPDATE = 0
|
||||
PART_UPDATE = 1
|
||||
lut_full_update= [
|
||||
0x80,0x60,0x40,0x00,0x00,0x00,0x00, #LUT0: BB: VS 0 ~7
|
||||
0x10,0x60,0x20,0x00,0x00,0x00,0x00, #LUT1: BW: VS 0 ~7
|
||||
0x80,0x60,0x40,0x00,0x00,0x00,0x00, #LUT2: WB: VS 0 ~7
|
||||
0x10,0x60,0x20,0x00,0x00,0x00,0x00, #LUT3: WW: VS 0 ~7
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT4: VCOM: VS 0 ~7
|
||||
|
||||
0x03,0x03,0x00,0x00,0x02, # TP0 A~D RP0
|
||||
0x09,0x09,0x00,0x00,0x02, # TP1 A~D RP1
|
||||
0x03,0x03,0x00,0x00,0x02, # TP2 A~D RP2
|
||||
0x00,0x00,0x00,0x00,0x00, # TP3 A~D RP3
|
||||
0x00,0x00,0x00,0x00,0x00, # TP4 A~D RP4
|
||||
0x00,0x00,0x00,0x00,0x00, # TP5 A~D RP5
|
||||
0x00,0x00,0x00,0x00,0x00, # TP6 A~D RP6
|
||||
|
||||
0x15,0x41,0xA8,0x32,0x30,0x0A,
|
||||
]
|
||||
|
||||
lut_partial_update = [ #20 bytes
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT0: BB: VS 0 ~7
|
||||
0x80,0x00,0x00,0x00,0x00,0x00,0x00, #LUT1: BW: VS 0 ~7
|
||||
0x40,0x00,0x00,0x00,0x00,0x00,0x00, #LUT2: WB: VS 0 ~7
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT3: WW: VS 0 ~7
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00, #LUT4: VCOM: VS 0 ~7
|
||||
|
||||
0x0A,0x00,0x00,0x00,0x00, # TP0 A~D RP0
|
||||
0x00,0x00,0x00,0x00,0x00, # TP1 A~D RP1
|
||||
0x00,0x00,0x00,0x00,0x00, # TP2 A~D RP2
|
||||
0x00,0x00,0x00,0x00,0x00, # TP3 A~D RP3
|
||||
0x00,0x00,0x00,0x00,0x00, # TP4 A~D RP4
|
||||
0x00,0x00,0x00,0x00,0x00, # TP5 A~D RP5
|
||||
0x00,0x00,0x00,0x00,0x00, # TP6 A~D RP6
|
||||
|
||||
0x15,0x41,0xA8,0x32,0x30,0x0A,
|
||||
]
|
||||
|
||||
# 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(5)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(200)
|
||||
|
||||
def send_command(self, command):
|
||||
epdconfig.digital_write(self.dc_pin, 0)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([command])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data(self, data):
|
||||
epdconfig.digital_write(self.dc_pin, 1)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([data])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data2(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):
|
||||
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
|
||||
epdconfig.delay_ms(10)
|
||||
|
||||
def TurnOnDisplay(self):
|
||||
self.send_command(0x22)
|
||||
self.send_data(0xC7)
|
||||
self.send_command(0x20)
|
||||
self.ReadBusy()
|
||||
|
||||
def TurnOnDisplayPart(self):
|
||||
self.send_command(0x22)
|
||||
self.send_data(0x0c)
|
||||
self.send_command(0x20)
|
||||
# self.ReadBusy()
|
||||
|
||||
def TurnOnDisplayPart_Wait(self):
|
||||
self.send_command(0x22)
|
||||
self.send_data(0x0c)
|
||||
self.send_command(0x20)
|
||||
self.ReadBusy()
|
||||
|
||||
def init(self, update):
|
||||
if (epdconfig.module_init() != 0):
|
||||
return -1
|
||||
# EPD hardware init start
|
||||
self.reset()
|
||||
if(update == self.FULL_UPDATE):
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) # soft reset
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x74) #set analog block control
|
||||
self.send_data(0x54)
|
||||
self.send_command(0x7E) #set digital block control
|
||||
self.send_data(0x3B)
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0xF9)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x01)
|
||||
|
||||
self.send_command(0x44) #set Ram-X address start/end position
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x0F) #0x0C-->(15+1)*8=128
|
||||
|
||||
self.send_command(0x45) #set Ram-Y address start/end position
|
||||
self.send_data(0xF9) #0xF9-->(249+1)=250
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x03)
|
||||
|
||||
self.send_command(0x2C) #VCOM Voltage
|
||||
self.send_data(0x55) #
|
||||
|
||||
self.send_command(0x03)
|
||||
self.send_data(self.lut_full_update[70])
|
||||
|
||||
self.send_command(0x04) #
|
||||
self.send_data(self.lut_full_update[71])
|
||||
self.send_data(self.lut_full_update[72])
|
||||
self.send_data(self.lut_full_update[73])
|
||||
|
||||
self.send_command(0x3A) #Dummy Line
|
||||
self.send_data(self.lut_full_update[74])
|
||||
self.send_command(0x3B) #Gate time
|
||||
self.send_data(self.lut_full_update[75])
|
||||
|
||||
self.send_command(0x32)
|
||||
for count in range(70):
|
||||
self.send_data(self.lut_full_update[count])
|
||||
|
||||
self.send_command(0x4E) # set RAM x address count to 0
|
||||
self.send_data(0x00)
|
||||
self.send_command(0x4F) # set RAM y address count to 0X127
|
||||
self.send_data(0xF9)
|
||||
self.send_data(0x00)
|
||||
self.ReadBusy()
|
||||
else:
|
||||
self.send_command(0x2C) #VCOM Voltage
|
||||
self.send_data(0x26)
|
||||
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x32)
|
||||
for count in range(70):
|
||||
self.send_data(self.lut_partial_update[count])
|
||||
|
||||
self.send_command(0x37)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x40)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x22)
|
||||
self.send_data(0xC0)
|
||||
self.send_command(0x20)
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x01)
|
||||
return 0
|
||||
|
||||
def getbuffer(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
buf = [0xFF] * (linewidth * self.height)
|
||||
image_monocolor = image.convert('1')
|
||||
imwidth, imheight = image_monocolor.size
|
||||
pixels = image_monocolor.load()
|
||||
|
||||
if(imwidth == self.width and imheight == self.height):
|
||||
# logging.debug("Vertical")
|
||||
for y in range(imheight):
|
||||
for x in range(imwidth):
|
||||
if pixels[x, y] == 0:
|
||||
x = imwidth - x
|
||||
buf[int(x / 8) + y * linewidth] &= ~(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:
|
||||
newy = imwidth - newy - 1
|
||||
buf[int(newx / 8) + newy*linewidth] &= ~(0x80 >> (y % 8))
|
||||
return buf
|
||||
|
||||
|
||||
def display(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, linewidth):
|
||||
# self.send_data(image[i + j * linewidth])
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplay()
|
||||
|
||||
def displayPartial(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, linewidth):
|
||||
# self.send_data(image[i + j * linewidth])
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplayPart()
|
||||
|
||||
def displayPartial_Wait(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(image[i + j * linewidth])
|
||||
|
||||
self.TurnOnDisplayPart_Wait()
|
||||
|
||||
def displayPartBaseImage(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(image[i + j * linewidth])
|
||||
|
||||
|
||||
self.send_command(0x26)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(image[i + j * linewidth])
|
||||
self.TurnOnDisplay()
|
||||
|
||||
def Clear(self, color):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(color)
|
||||
|
||||
self.TurnOnDisplay()
|
||||
|
||||
def sleep(self):
|
||||
# self.send_command(0x22) #POWER OFF
|
||||
# self.send_data(0xC3)
|
||||
# self.send_command(0x20)
|
||||
|
||||
self.send_command(0x10) #enter deep sleep
|
||||
self.send_data(0x03)
|
||||
epdconfig.delay_ms(100)
|
||||
|
||||
def Dev_exit(self):
|
||||
epdconfig.module_exit()
|
||||
|
||||
### END OF FILE ###
|
||||
|
||||
@@ -0,0 +1,436 @@
|
||||
# *****************************************************************************
|
||||
# * | File : epd2in13_V3.py
|
||||
# * | Author : Waveshare team
|
||||
# * | Function : Electronic paper driver
|
||||
# * | Info :
|
||||
# *----------------
|
||||
# * | This version: V1.1
|
||||
# * | Date : 2021-10-30
|
||||
# # | 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
|
||||
import numpy as np
|
||||
|
||||
# Display resolution
|
||||
EPD_WIDTH = 122
|
||||
EPD_HEIGHT = 250
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class EPD:
|
||||
def __init__(self):
|
||||
self.reset_pin = epdconfig.EPD_RST_PIN
|
||||
self.dc_pin = epdconfig.EPD_DC_PIN
|
||||
self.busy_pin = epdconfig.EPD_BUSY_PIN
|
||||
self.cs_pin = epdconfig.EPD_CS_PIN
|
||||
self.width = EPD_WIDTH
|
||||
self.height = EPD_HEIGHT
|
||||
epdconfig.address = 0x14
|
||||
|
||||
FULL_UPDATE = 0
|
||||
PART_UPDATE = 1
|
||||
|
||||
lut_partial_update= [
|
||||
0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x10,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,
|
||||
0x22,0x17,0x41,0x00,0x32,0x36,
|
||||
]
|
||||
|
||||
lut_full_update = [
|
||||
0x80,0x4A,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x40,0x4A,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x80,0x4A,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x40,0x4A,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0xF,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0xF,0x0,0x0,0xF,0x0,0x0,0x2,
|
||||
0xF,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,
|
||||
0x22,0x17,0x41,0x0,0x32,0x36,
|
||||
]
|
||||
|
||||
'''
|
||||
function :Hardware reset
|
||||
parameter:
|
||||
'''
|
||||
def reset(self):
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(20)
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(2)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(20)
|
||||
|
||||
'''
|
||||
function :send command
|
||||
parameter:
|
||||
command : Command register
|
||||
'''
|
||||
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)
|
||||
|
||||
'''
|
||||
function :send data
|
||||
parameter:
|
||||
data : Write data
|
||||
'''
|
||||
def send_data(self, data):
|
||||
epdconfig.digital_write(self.dc_pin, 1)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([data])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data2(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)
|
||||
|
||||
'''
|
||||
function :Wait until the busy_pin goes LOW
|
||||
parameter:
|
||||
'''
|
||||
def ReadBusy(self):
|
||||
logger.debug("e-Paper busy")
|
||||
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
|
||||
epdconfig.delay_ms(10)
|
||||
logger.debug("e-Paper busy release")
|
||||
|
||||
'''
|
||||
function : Turn On Display
|
||||
parameter:
|
||||
'''
|
||||
def TurnOnDisplay(self):
|
||||
self.send_command(0x22) # Display Update Control
|
||||
self.send_data(0xC7)
|
||||
self.send_command(0x20) # Activate Display Update Sequence
|
||||
self.ReadBusy()
|
||||
|
||||
'''
|
||||
function : Turn On Display Part
|
||||
parameter:
|
||||
'''
|
||||
def TurnOnDisplayPart(self):
|
||||
self.send_command(0x22) # Display Update Control
|
||||
self.send_data(0x0c) # fast:0x0c, quality:0x0f, 0xcf
|
||||
self.send_command(0x20) # Activate Display Update Sequence
|
||||
# self.ReadBusy()
|
||||
|
||||
def TurnOnDisplayPart_Wait(self):
|
||||
self.send_command(0x22) # Display Update Control
|
||||
self.send_data(0x0c) # fast:0x0c, quality:0x0f, 0xcf
|
||||
self.send_command(0x20) # Activate Display Update Sequence
|
||||
self.ReadBusy()
|
||||
|
||||
'''
|
||||
function : Set lut
|
||||
parameter:
|
||||
lut : lut data
|
||||
'''
|
||||
def Lut(self, lut):
|
||||
self.send_command(0x32)
|
||||
for i in range(0, 153):
|
||||
self.send_data(lut[i])
|
||||
self.ReadBusy()
|
||||
|
||||
'''
|
||||
function : Send lut data and configuration
|
||||
parameter:
|
||||
lut : lut data
|
||||
'''
|
||||
def SetLut(self, lut):
|
||||
self.Lut(lut)
|
||||
self.send_command(0x3f)
|
||||
self.send_data(lut[153])
|
||||
self.send_command(0x03) # gate voltage
|
||||
self.send_data(lut[154])
|
||||
self.send_command(0x04) # source voltage
|
||||
self.send_data(lut[155]) # VSH
|
||||
self.send_data(lut[156]) # VSH2
|
||||
self.send_data(lut[157]) # VSL
|
||||
self.send_command(0x2c) # VCOM
|
||||
self.send_data(lut[158])
|
||||
|
||||
'''
|
||||
function : Setting the display window
|
||||
parameter:
|
||||
xstart : X-axis starting position
|
||||
ystart : Y-axis starting position
|
||||
xend : End position of X-axis
|
||||
yend : End position of Y-axis
|
||||
'''
|
||||
def SetWindow(self, x_start, y_start, x_end, y_end):
|
||||
self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
|
||||
# x point must be the multiple of 8 or the last 3 bits will be ignored
|
||||
self.send_data((x_start>>3) & 0xFF)
|
||||
self.send_data((x_end>>3) & 0xFF)
|
||||
|
||||
self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
|
||||
self.send_data(y_start & 0xFF)
|
||||
self.send_data((y_start >> 8) & 0xFF)
|
||||
self.send_data(y_end & 0xFF)
|
||||
self.send_data((y_end >> 8) & 0xFF)
|
||||
|
||||
'''
|
||||
function : Set Cursor
|
||||
parameter:
|
||||
x : X-axis starting position
|
||||
y : Y-axis starting position
|
||||
'''
|
||||
def SetCursor(self, x, y):
|
||||
self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
|
||||
# x point must be the multiple of 8 or the last 3 bits will be ignored
|
||||
self.send_data(x & 0xFF)
|
||||
|
||||
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
|
||||
self.send_data(y & 0xFF)
|
||||
self.send_data((y >> 8) & 0xFF)
|
||||
|
||||
'''
|
||||
function : Initialize the e-Paper register
|
||||
parameter:
|
||||
'''
|
||||
def init(self, update):
|
||||
if (epdconfig.module_init() != 0):
|
||||
return -1
|
||||
|
||||
if update == self.FULL_UPDATE:
|
||||
# EPD hardware init start
|
||||
self.reset()
|
||||
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) #SWRESET
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0xf9)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(0, 0, self.width-1, self.height-1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
self.send_command(0x3c)
|
||||
self.send_data(0x05)
|
||||
|
||||
self.send_command(0x21) # Display update control
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x18)
|
||||
self.send_data(0x80)
|
||||
|
||||
self.ReadBusy()
|
||||
|
||||
self.SetLut(self.lut_full_update)
|
||||
|
||||
else:
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(1)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
|
||||
self.SetLut(self.lut_partial_update)
|
||||
self.send_command(0x37)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x40)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x22)
|
||||
self.send_data(0xC0)
|
||||
self.send_command(0x20)
|
||||
self.ReadBusy()
|
||||
|
||||
self.SetWindow(0, 0, self.width - 1, self.height - 1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
return 0
|
||||
|
||||
'''
|
||||
function : Display images
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def getbuffer(self, image):
|
||||
img = image
|
||||
imwidth, imheight = img.size
|
||||
if(imwidth == self.width and imheight == self.height):
|
||||
img = img.rotate(180, expand=True).convert('1')
|
||||
elif(imwidth == self.height and imheight == self.width):
|
||||
# image has correct dimensions, but needs to be rotated
|
||||
img = img.rotate(270, expand=True).convert('1')
|
||||
else:
|
||||
logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height))
|
||||
# return a blank buffer
|
||||
return [0x00] * (int(self.width/8) * self.height)
|
||||
|
||||
buf = bytearray(img.tobytes('raw'))
|
||||
return buf
|
||||
|
||||
'''
|
||||
function : Sends the image buffer in RAM to e-Paper and displays
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def display(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, linewidth):
|
||||
# self.send_data(image[i + j * linewidth])
|
||||
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplay()
|
||||
|
||||
'''
|
||||
function : Sends the image buffer in RAM to e-Paper and partial refresh
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def displayPartial(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, linewidth):
|
||||
# self.send_data(image[i + j * linewidth])
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplayPart()
|
||||
|
||||
def displayPartial_Wait(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, linewidth):
|
||||
# self.send_data(image[i + j * linewidth])
|
||||
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplayPart_Wait()
|
||||
|
||||
'''
|
||||
function : Refresh a base image
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def displayPartBaseImage(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(image[i + j * linewidth])
|
||||
|
||||
self.send_command(0x26)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(image[i + j * linewidth])
|
||||
self.TurnOnDisplay()
|
||||
|
||||
'''
|
||||
function : Clear screen
|
||||
parameter:
|
||||
'''
|
||||
def Clear(self, color):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
# logger.debug(linewidth)
|
||||
|
||||
self.send_command(0x24)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(color)
|
||||
|
||||
self.TurnOnDisplay()
|
||||
|
||||
'''
|
||||
function : Enter sleep mode
|
||||
parameter:
|
||||
'''
|
||||
def sleep(self):
|
||||
self.send_command(0x10) #enter deep sleep
|
||||
self.send_data(0x01)
|
||||
|
||||
epdconfig.delay_ms(2000)
|
||||
|
||||
def Dev_exit(self):
|
||||
epdconfig.module_exit()
|
||||
|
||||
### END OF FILE ###
|
||||
|
||||
@@ -0,0 +1,370 @@
|
||||
# *****************************************************************************
|
||||
# * | File : epd2in13_V4.py
|
||||
# * | Author : Waveshare team
|
||||
# * | Function : Electronic paper driver
|
||||
# * | Info :
|
||||
# *----------------
|
||||
# * | This version: V1.0
|
||||
# * | Date : 2023-08-14
|
||||
# # | 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
|
||||
import numpy as np
|
||||
|
||||
# Display resolution
|
||||
EPD_WIDTH = 122
|
||||
EPD_HEIGHT = 250
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class EPD:
|
||||
def __init__(self):
|
||||
self.reset_pin = epdconfig.EPD_RST_PIN
|
||||
self.dc_pin = epdconfig.EPD_DC_PIN
|
||||
self.busy_pin = epdconfig.EPD_BUSY_PIN
|
||||
self.cs_pin = epdconfig.EPD_CS_PIN
|
||||
self.width = EPD_WIDTH
|
||||
self.height = EPD_HEIGHT
|
||||
epdconfig.address = 0x14
|
||||
|
||||
FULL_UPDATE = 0
|
||||
PART_UPDATE = 1
|
||||
|
||||
'''
|
||||
function :Hardware reset
|
||||
parameter:
|
||||
'''
|
||||
def reset(self):
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(20)
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(2)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(20)
|
||||
|
||||
'''
|
||||
function :send command
|
||||
parameter:
|
||||
command : Command register
|
||||
'''
|
||||
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)
|
||||
|
||||
'''
|
||||
function :send data
|
||||
parameter:
|
||||
data : Write data
|
||||
'''
|
||||
def send_data(self, data):
|
||||
epdconfig.digital_write(self.dc_pin, 1)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([data])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data2(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)
|
||||
|
||||
'''
|
||||
function :Wait until the busy_pin goes LOW
|
||||
parameter:
|
||||
'''
|
||||
def ReadBusy(self):
|
||||
logger.debug("e-Paper busy")
|
||||
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
|
||||
epdconfig.delay_ms(10)
|
||||
logger.debug("e-Paper busy release")
|
||||
|
||||
'''
|
||||
function : Turn On Display
|
||||
parameter:
|
||||
'''
|
||||
def TurnOnDisplay(self):
|
||||
self.send_command(0x22) # Display Update Control
|
||||
self.send_data(0xF7)
|
||||
self.send_command(0x20) # Activate Display Update Sequence
|
||||
self.ReadBusy()
|
||||
|
||||
'''
|
||||
function : Turn On Display Part
|
||||
parameter:
|
||||
'''
|
||||
def TurnOnDisplayPart(self):
|
||||
self.send_command(0x22) # Display Update Control
|
||||
self.send_data(0xFF) # fast:0x0c, quality:0x0f, 0xcf
|
||||
self.send_command(0x20) # Activate Display Update Sequence
|
||||
# self.ReadBusy()
|
||||
|
||||
def TurnOnDisplayPart_Wait(self):
|
||||
self.send_command(0x22) # Display Update Control
|
||||
self.send_data(0xFF) # fast:0x0c, quality:0x0f, 0xcf
|
||||
self.send_command(0x20) # Activate Display Update Sequence
|
||||
self.ReadBusy()
|
||||
|
||||
'''
|
||||
function : Setting the display window
|
||||
parameter:
|
||||
xstart : X-axis starting position
|
||||
ystart : Y-axis starting position
|
||||
xend : End position of X-axis
|
||||
yend : End position of Y-axis
|
||||
'''
|
||||
def SetWindow(self, x_start, y_start, x_end, y_end):
|
||||
self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
|
||||
# x point must be the multiple of 8 or the last 3 bits will be ignored
|
||||
self.send_data((x_start>>3) & 0xFF)
|
||||
self.send_data((x_end>>3) & 0xFF)
|
||||
|
||||
self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
|
||||
self.send_data(y_start & 0xFF)
|
||||
self.send_data((y_start >> 8) & 0xFF)
|
||||
self.send_data(y_end & 0xFF)
|
||||
self.send_data((y_end >> 8) & 0xFF)
|
||||
|
||||
'''
|
||||
function : Set Cursor
|
||||
parameter:
|
||||
x : X-axis starting position
|
||||
y : Y-axis starting position
|
||||
'''
|
||||
def SetCursor(self, x, y):
|
||||
self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
|
||||
# x point must be the multiple of 8 or the last 3 bits will be ignored
|
||||
self.send_data(x & 0xFF)
|
||||
|
||||
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
|
||||
self.send_data(y & 0xFF)
|
||||
self.send_data((y >> 8) & 0xFF)
|
||||
|
||||
'''
|
||||
function : Initialize the e-Paper register
|
||||
parameter:
|
||||
'''
|
||||
def init(self, update):
|
||||
if (epdconfig.module_init() != 0):
|
||||
return -1
|
||||
|
||||
if update == self.FULL_UPDATE:
|
||||
# EPD hardware init start
|
||||
self.reset()
|
||||
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) #SWRESET
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0xf9)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(0, 0, self.width-1, self.height-1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
self.send_command(0x3c)
|
||||
self.send_data(0x05)
|
||||
|
||||
self.send_command(0x21) # Display update control
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x18)
|
||||
self.send_data(0x80)
|
||||
|
||||
self.ReadBusy()
|
||||
|
||||
else:
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(1)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0xf9)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(0, 0, self.width - 1, self.height - 1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
return 0
|
||||
|
||||
'''
|
||||
function : Display images
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def getbuffer(self, image):
|
||||
img = image
|
||||
imwidth, imheight = img.size
|
||||
if(imwidth == self.width and imheight == self.height):
|
||||
img = img.rotate(180, expand=True).convert('1')
|
||||
elif(imwidth == self.height and imheight == self.width):
|
||||
# image has correct dimensions, but needs to be rotated
|
||||
img = img.rotate(270, expand=True).convert('1')
|
||||
else:
|
||||
logger.warning("Wrong image dimensions: must be " + str(self.width) + "x" + str(self.height))
|
||||
# return a blank buffer
|
||||
return [0x00] * (int(self.width/8) * self.height)
|
||||
|
||||
buf = bytearray(img.tobytes('raw'))
|
||||
return buf
|
||||
|
||||
'''
|
||||
function : Sends the image buffer in RAM to e-Paper and displays
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def display(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, linewidth):
|
||||
# self.send_data(image[i + j * linewidth])
|
||||
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplay()
|
||||
|
||||
'''
|
||||
function : Sends the image buffer in RAM to e-Paper and partial refresh
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def displayPartial(self, image):
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(1)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0xf9)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(0, 0, self.width - 1, self.height - 1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplayPart()
|
||||
|
||||
def displayPartial_Wait(self, image):
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(1)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0xf9)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(0, 0, self.width - 1, self.height - 1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplayPart_Wait()
|
||||
|
||||
'''
|
||||
function : Refresh a base image
|
||||
parameter:
|
||||
image : Image data
|
||||
'''
|
||||
def displayPartBaseImage(self, image):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
|
||||
self.send_command(0x24)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(image[i + j * linewidth])
|
||||
|
||||
self.send_command(0x26)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(image[i + j * linewidth])
|
||||
self.TurnOnDisplay()
|
||||
|
||||
'''
|
||||
function : Clear screen
|
||||
parameter:
|
||||
'''
|
||||
def Clear(self, color):
|
||||
if self.width%8 == 0:
|
||||
linewidth = int(self.width/8)
|
||||
else:
|
||||
linewidth = int(self.width/8) + 1
|
||||
# logger.debug(linewidth)
|
||||
|
||||
self.send_command(0x24)
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, linewidth):
|
||||
self.send_data(color)
|
||||
|
||||
self.TurnOnDisplay()
|
||||
|
||||
'''
|
||||
function : Enter sleep mode
|
||||
parameter:
|
||||
'''
|
||||
def sleep(self):
|
||||
self.send_command(0x10) #enter deep sleep
|
||||
self.send_data(0x01)
|
||||
|
||||
epdconfig.delay_ms(2000)
|
||||
|
||||
def Dev_exit(self):
|
||||
epdconfig.module_exit()
|
||||
|
||||
### END OF FILE ###
|
||||
|
||||
@@ -0,0 +1,586 @@
|
||||
# *****************************************************************************
|
||||
# * | File : epd2in9_V2.py
|
||||
# * | Author : Waveshare team
|
||||
# * | Function : Electronic paper driver
|
||||
# * | Info :
|
||||
# *----------------
|
||||
# * | This version: V1.0
|
||||
# * | Date : 2020-10-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
|
||||
import numpy as np
|
||||
|
||||
# Display resolution
|
||||
EPD_WIDTH = 128
|
||||
EPD_HEIGHT = 296
|
||||
|
||||
class EPD_2IN9_V2:
|
||||
def __init__(self):
|
||||
self.reset_pin = epdconfig.EPD_RST_PIN
|
||||
self.dc_pin = epdconfig.EPD_DC_PIN
|
||||
self.busy_pin = epdconfig.EPD_BUSY_PIN
|
||||
self.cs_pin = epdconfig.EPD_CS_PIN
|
||||
self.width = EPD_WIDTH
|
||||
self.height = EPD_HEIGHT
|
||||
epdconfig.address = 0x48
|
||||
|
||||
WF_PARTIAL_2IN9 = [
|
||||
0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0A,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,
|
||||
0x22,0x17,0x41,0xB0,0x32,0x36,
|
||||
]
|
||||
|
||||
WF_PARTIAL_2IN9_Wait = [
|
||||
0x0,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x80,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x40,0x40,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x80,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0A,0x0,0x0,0x0,0x0,0x0,0x2,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x1,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x0,0x0,0x0,0x0,0x0,0x0,0x0,
|
||||
0x22,0x22,0x22,0x22,0x22,0x22,0x0,0x0,0x0,
|
||||
0x22,0x17,0x41,0xB0,0x32,0x36,
|
||||
]
|
||||
|
||||
Gray4 = [
|
||||
0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x20, 0x60, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x28, 0x60, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x2A, 0x60, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00,
|
||||
0x1E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x02, 0x00, 0x05, 0x14, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x22, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00,
|
||||
0x22, 0x17, 0x41, 0xAE, 0x32, 0x28,
|
||||
]
|
||||
|
||||
WF_FULL = [
|
||||
0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x19, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x24, 0x42, 0x22, 0x22, 0x23, 0x32, 0x00, 0x00, 0x00,
|
||||
0x22, 0x17, 0x41, 0xAE, 0x32, 0x38]
|
||||
|
||||
# Hardware reset
|
||||
def reset(self):
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(20)
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(2)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
epdconfig.delay_ms(20)
|
||||
|
||||
def send_command(self, command):
|
||||
epdconfig.digital_write(self.dc_pin, 0)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([command])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data(self, data):
|
||||
epdconfig.digital_write(self.dc_pin, 1)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte([data])
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def send_data2(self, data):
|
||||
epdconfig.digital_write(self.dc_pin, 1)
|
||||
epdconfig.digital_write(self.cs_pin, 0)
|
||||
epdconfig.spi_writebyte2(data)
|
||||
epdconfig.digital_write(self.cs_pin, 1)
|
||||
|
||||
def ReadBusy(self):
|
||||
# logging.debug("e-Paper busy")
|
||||
while(epdconfig.digital_read(self.busy_pin) == 1): # 0: idle, 1: busy
|
||||
epdconfig.delay_ms(0.1)
|
||||
# logging.debug("e-Paper busy release")
|
||||
|
||||
def TurnOnDisplay(self):
|
||||
self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2
|
||||
self.send_data(0xF7)
|
||||
self.send_command(0x20) # MASTER_ACTIVATION
|
||||
self.ReadBusy()
|
||||
|
||||
def TurnOnDisplay_Partial(self):
|
||||
self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2
|
||||
self.send_data(0x0F)
|
||||
self.send_command(0x20) # MASTER_ACTIVATION
|
||||
# self.ReadBusy()
|
||||
|
||||
def TurnOnDisplay_Partial_Wait(self):
|
||||
self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2
|
||||
self.send_data(0x0F)
|
||||
self.send_command(0x20) # MASTER_ACTIVATION
|
||||
self.ReadBusy()
|
||||
|
||||
def TurnOnDisplay_4Gray(self):
|
||||
self.send_command(0x22) # DISPLAY_UPDATE_CONTROL_2
|
||||
self.send_data(0xC7)
|
||||
self.send_command(0x20) # MASTER_ACTIVATION
|
||||
self.ReadBusy()
|
||||
|
||||
def SendLut(self, lut):
|
||||
self.send_command(0x32)
|
||||
# for i in range(0, 153):
|
||||
# self.send_data(self.WF_PARTIAL_2IN9[i])
|
||||
if(lut):
|
||||
self.send_data2(self.WF_PARTIAL_2IN9)
|
||||
else:
|
||||
self.send_data2(self.WF_PARTIAL_2IN9_Wait)
|
||||
self.ReadBusy()
|
||||
|
||||
def lut(self, lut):
|
||||
self.send_command(0x32)
|
||||
for i in range(0, 153):
|
||||
self.send_data(lut[i])
|
||||
self.ReadBusy()
|
||||
|
||||
def SetLut(self, lut):
|
||||
self.lut(lut)
|
||||
self.send_command(0x3f)
|
||||
self.send_data(lut[153])
|
||||
self.send_command(0x03); # gate voltage
|
||||
self.send_data(lut[154])
|
||||
self.send_command(0x04); # source voltage
|
||||
self.send_data(lut[155]) # VSH
|
||||
self.send_data(lut[156]) # VSH2
|
||||
self.send_data(lut[157]) # VSL
|
||||
self.send_command(0x2c); # VCOM
|
||||
self.send_data(lut[158])
|
||||
|
||||
def SetWindow(self, x_start, y_start, x_end, y_end):
|
||||
self.send_command(0x44) # SET_RAM_X_ADDRESS_START_END_POSITION
|
||||
# x point must be the multiple of 8 or the last 3 bits will be ignored
|
||||
self.send_data((x_start>>3) & 0xFF)
|
||||
self.send_data((x_end>>3) & 0xFF)
|
||||
self.send_command(0x45) # SET_RAM_Y_ADDRESS_START_END_POSITION
|
||||
self.send_data(y_start & 0xFF)
|
||||
self.send_data((y_start >> 8) & 0xFF)
|
||||
self.send_data(y_end & 0xFF)
|
||||
self.send_data((y_end >> 8) & 0xFF)
|
||||
|
||||
def SetCursor(self, x, y):
|
||||
self.send_command(0x4E) # SET_RAM_X_ADDRESS_COUNTER
|
||||
# x point must be the multiple of 8 or the last 3 bits will be ignored
|
||||
self.send_data(x & 0xFF)
|
||||
|
||||
self.send_command(0x4F) # SET_RAM_Y_ADDRESS_COUNTER
|
||||
self.send_data(y & 0xFF)
|
||||
self.send_data((y >> 8) & 0xFF)
|
||||
self.ReadBusy()
|
||||
|
||||
def init(self):
|
||||
if (epdconfig.module_init() != 0):
|
||||
return -1
|
||||
# EPD hardware init start
|
||||
self.reset()
|
||||
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) #SWRESET
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0x27)
|
||||
self.send_data(0x01)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(0, 0, self.width-1, self.height-1)
|
||||
|
||||
self.send_command(0x21) # Display update control
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x80)
|
||||
|
||||
self.SetCursor(0, 0)
|
||||
self.ReadBusy()
|
||||
# EPD hardware init end
|
||||
return 0
|
||||
|
||||
def init_Fast(self):
|
||||
if (epdconfig.module_init() != 0):
|
||||
return -1
|
||||
# EPD hardware init start
|
||||
self.reset()
|
||||
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) #SWRESET
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0x27)
|
||||
self.send_data(0x01)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(0, 0, self.width-1, self.height-1)
|
||||
|
||||
self.send_command(0x3C)
|
||||
self.send_data(0x05)
|
||||
|
||||
self.send_command(0x21) # Display update control
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x80)
|
||||
|
||||
self.SetCursor(0, 0)
|
||||
self.ReadBusy()
|
||||
|
||||
self.SetLut(self.WF_FULL)
|
||||
# EPD hardware init end
|
||||
return 0
|
||||
|
||||
def Init_4Gray(self):
|
||||
if (epdconfig.module_init() != 0):
|
||||
return -1
|
||||
self.reset()
|
||||
epdconfig.delay_ms(100)
|
||||
|
||||
self.ReadBusy()
|
||||
self.send_command(0x12) #SWRESET
|
||||
self.ReadBusy()
|
||||
|
||||
self.send_command(0x01) #Driver output control
|
||||
self.send_data(0x27)
|
||||
self.send_data(0x01)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x11) #data entry mode
|
||||
self.send_data(0x03)
|
||||
|
||||
self.SetWindow(8, 0, self.width, self.height-1)
|
||||
|
||||
self.send_command(0x3C)
|
||||
self.send_data(0x04)
|
||||
|
||||
self.SetCursor(1, 0)
|
||||
self.ReadBusy()
|
||||
|
||||
self.SetLut(self.Gray4)
|
||||
# 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 getbuffer_4Gray(self, image):
|
||||
# logger.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
|
||||
# logger.debug("imwidth = %d, imheight = %d",imwidth,imheight)
|
||||
if(imwidth == self.width and imheight == self.height):
|
||||
# logger.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):
|
||||
# logger.debug("Horizontal")
|
||||
for x in range(imwidth):
|
||||
for y in range(imheight):
|
||||
newx = y
|
||||
newy = self.height - x - 1
|
||||
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):
|
||||
if (image == None):
|
||||
return
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, int(self.width / 8)):
|
||||
# self.send_data(image[i + j * int(self.width / 8)])
|
||||
self.send_data2(image)
|
||||
self.TurnOnDisplay()
|
||||
|
||||
def display_Base(self, image):
|
||||
if (image == None):
|
||||
return
|
||||
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, int(self.width / 8)):
|
||||
# self.send_data(image[i + j * int(self.width / 8)])
|
||||
self.send_data2(image)
|
||||
|
||||
self.send_command(0x26) # WRITE_RAM
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, int(self.width / 8)):
|
||||
# self.send_data(image[i + j * int(self.width / 8)])
|
||||
self.send_data2(image)
|
||||
|
||||
self.TurnOnDisplay()
|
||||
|
||||
def display_Partial(self, image):
|
||||
if (image == None):
|
||||
return
|
||||
|
||||
# epdconfig.digital_write(self.reset_pin, 0)
|
||||
# epdconfig.delay_ms(2)
|
||||
# epdconfig.digital_write(self.reset_pin, 1)
|
||||
# epdconfig.delay_ms(2)
|
||||
|
||||
self.SendLut(1)
|
||||
self.send_command(0x37)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x40)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x22)
|
||||
self.send_data(0xC0)
|
||||
self.send_command(0x20)
|
||||
self.ReadBusy()
|
||||
|
||||
self.SetWindow(0, 0, self.width - 1, self.height - 1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, int(self.width / 8)):
|
||||
# self.send_data(image[i + j * int(self.width / 8)])
|
||||
self.send_data2(image)
|
||||
|
||||
self.TurnOnDisplay_Partial()
|
||||
|
||||
def display_Partial_Wait(self, image):
|
||||
if (image == None):
|
||||
return
|
||||
|
||||
epdconfig.digital_write(self.reset_pin, 0)
|
||||
epdconfig.delay_ms(1)
|
||||
epdconfig.digital_write(self.reset_pin, 1)
|
||||
# epdconfig.delay_ms(2)
|
||||
|
||||
self.SendLut(0)
|
||||
self.send_command(0x37)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x40)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
self.send_data(0x00)
|
||||
|
||||
self.send_command(0x3C) #BorderWavefrom
|
||||
self.send_data(0x80)
|
||||
|
||||
self.send_command(0x22)
|
||||
self.send_data(0xC0)
|
||||
self.send_command(0x20)
|
||||
self.ReadBusy()
|
||||
|
||||
self.SetWindow(0, 0, self.width - 1, self.height - 1)
|
||||
self.SetCursor(0, 0)
|
||||
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
# for j in range(0, self.height):
|
||||
# for i in range(0, int(self.width / 8)):
|
||||
# self.send_data(image[i + j * int(self.width / 8)])
|
||||
self.send_data2(image)
|
||||
|
||||
self.TurnOnDisplay_Partial_Wait()
|
||||
|
||||
def Clear(self, color):
|
||||
self.send_command(0x24) # WRITE_RAM
|
||||
for j in range(0, self.height):
|
||||
for i in range(0, int(self.width / 8)):
|
||||
self.send_data(color)
|
||||
self.TurnOnDisplay()
|
||||
|
||||
def display_4Gray(self, image):
|
||||
self.send_command(0x24)
|
||||
for i in range(0, 4736):
|
||||
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 |= 0x00
|
||||
elif(temp2 == 0x00):
|
||||
temp3 |= 0x01
|
||||
elif(temp2 == 0x80):
|
||||
temp3 |= 0x01
|
||||
else: #0x40
|
||||
temp3 |= 0x00
|
||||
temp3 <<= 1
|
||||
|
||||
temp1 <<= 2
|
||||
temp2 = temp1&0xC0
|
||||
if(temp2 == 0xC0):
|
||||
temp3 |= 0x00
|
||||
elif(temp2 == 0x00):
|
||||
temp3 |= 0x01
|
||||
elif(temp2 == 0x80):
|
||||
temp3 |= 0x01
|
||||
else : #0x40
|
||||
temp3 |= 0x00
|
||||
if(j!=1 or k!=1):
|
||||
temp3 <<= 1
|
||||
temp1 <<= 2
|
||||
self.send_data(temp3)
|
||||
|
||||
self.send_command(0x26)
|
||||
for i in range(0, 4736):
|
||||
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 |= 0x00
|
||||
elif(temp2 == 0x00):
|
||||
temp3 |= 0x01
|
||||
elif(temp2 == 0x80):
|
||||
temp3 |= 0x00
|
||||
else: #0x40
|
||||
temp3 |= 0x01
|
||||
temp3 <<= 1
|
||||
|
||||
temp1 <<= 2
|
||||
temp2 = temp1&0xC0
|
||||
if(temp2 == 0xC0):
|
||||
temp3 |= 0x00
|
||||
elif(temp2 == 0x00):
|
||||
temp3 |= 0x01
|
||||
elif(temp2 == 0x80):
|
||||
temp3 |= 0x00
|
||||
else: #0x40
|
||||
temp3 |= 0x01
|
||||
if(j!=1 or k!=1):
|
||||
temp3 <<= 1
|
||||
temp1 <<= 2
|
||||
self.send_data(temp3)
|
||||
|
||||
self.TurnOnDisplay_4Gray()
|
||||
|
||||
def sleep(self):
|
||||
self.send_command(0x10) # DEEP_SLEEP_MODE
|
||||
self.send_data(0x01)
|
||||
|
||||
def Dev_exit(self):
|
||||
epdconfig.module_exit()
|
||||
### END OF FILE ###
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
# /*****************************************************************************
|
||||
# * | File : epdconfig.py
|
||||
# * | Author : Waveshare team
|
||||
# * | Function : Hardware underlying interface
|
||||
# * | Info :
|
||||
# *----------------
|
||||
# * | This version: V1.0
|
||||
# * | Date : 2020-12-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 gpiozero
|
||||
import time
|
||||
from smbus import SMBus
|
||||
import spidev
|
||||
import ctypes
|
||||
import logging
|
||||
|
||||
# e-Paper
|
||||
EPD_RST_PIN = 17
|
||||
EPD_DC_PIN = 25
|
||||
EPD_CS_PIN = 8
|
||||
EPD_BUSY_PIN = 24
|
||||
|
||||
# TP
|
||||
TRST = 22
|
||||
INT = 27
|
||||
|
||||
spi = spidev.SpiDev(0, 0)
|
||||
address = 0x0
|
||||
# address = 0x14
|
||||
# address = 0x48
|
||||
bus = SMBus(1)
|
||||
|
||||
|
||||
GPIO_RST_PIN = gpiozero.LED(EPD_RST_PIN)
|
||||
GPIO_DC_PIN = gpiozero.LED(EPD_DC_PIN)
|
||||
# GPIO_CS_PIN = gpiozero.LED(EPD_CS_PIN)
|
||||
GPIO_TRST = gpiozero.LED(TRST)
|
||||
|
||||
GPIO_BUSY_PIN = gpiozero.Button(EPD_BUSY_PIN, pull_up = False)
|
||||
GPIO_INT = gpiozero.Button(INT, pull_up = False)
|
||||
|
||||
|
||||
def digital_write(pin, value):
|
||||
if pin == EPD_RST_PIN:
|
||||
if value:
|
||||
GPIO_RST_PIN.on()
|
||||
else:
|
||||
GPIO_RST_PIN.off()
|
||||
elif pin == EPD_DC_PIN:
|
||||
if value:
|
||||
GPIO_DC_PIN.on()
|
||||
else:
|
||||
GPIO_DC_PIN.off()
|
||||
# elif pin == EPD_CS_PIN:
|
||||
# if value:
|
||||
# GPIO_CS_PIN.on()
|
||||
# else:
|
||||
# GPIO_CS_PIN.off()
|
||||
elif pin == TRST:
|
||||
if value:
|
||||
GPIO_TRST.on()
|
||||
else:
|
||||
GPIO_TRST.off()
|
||||
|
||||
def digital_read(pin):
|
||||
if pin == EPD_BUSY_PIN:
|
||||
return GPIO_BUSY_PIN.value
|
||||
elif pin == INT:
|
||||
return GPIO_INT.value
|
||||
|
||||
def delay_ms(delaytime):
|
||||
time.sleep(delaytime / 1000.0)
|
||||
|
||||
def spi_writebyte(data):
|
||||
spi.writebytes(data)
|
||||
|
||||
def spi_writebyte2(data):
|
||||
spi.writebytes2(data)
|
||||
|
||||
def i2c_writebyte(reg, value):
|
||||
bus.write_word_data(address, (reg>>8) & 0xff, (reg & 0xff) | ((value & 0xff) << 8))
|
||||
|
||||
def i2c_write(reg):
|
||||
bus.write_byte_data(address, (reg>>8) & 0xff, reg & 0xff)
|
||||
|
||||
def i2c_readbyte(reg, len):
|
||||
i2c_write(reg)
|
||||
rbuf = []
|
||||
for i in range(len):
|
||||
rbuf.append(int(bus.read_byte(address)))
|
||||
return rbuf
|
||||
|
||||
def module_init():
|
||||
|
||||
spi.max_speed_hz = 10000000
|
||||
spi.mode = 0b00
|
||||
|
||||
return 0
|
||||
|
||||
def module_exit():
|
||||
logging.debug("spi end")
|
||||
spi.close()
|
||||
bus.close()
|
||||
|
||||
logging.debug("close 5V, Module enters 0 power consumption ...")
|
||||
GPIO_RST_PIN.off()
|
||||
GPIO_DC_PIN.off()
|
||||
# GPIO_CS_PIN.off()
|
||||
GPIO_TRST.off()
|
||||
|
||||
GPIO_RST_PIN.close()
|
||||
GPIO_DC_PIN.close()
|
||||
# GPIO_CS_PIN.close()
|
||||
GPIO_TRST.close()
|
||||
|
||||
GPIO_BUSY_PIN.close()
|
||||
GPIO_INT.close()
|
||||
|
||||
|
||||
### END OF FILE ###
|
||||
@@ -0,0 +1,84 @@
|
||||
import logging
|
||||
from . import epdconfig as config
|
||||
|
||||
class GT_Development:
|
||||
def __init__(self):
|
||||
self.Touch = 0
|
||||
self.TouchpointFlag = 0
|
||||
self.TouchCount = 0
|
||||
self.Touchkeytrackid = [0, 1, 2, 3, 4]
|
||||
self.X = [0, 1, 2, 3, 4]
|
||||
self.Y = [0, 1, 2, 3, 4]
|
||||
self.S = [0, 1, 2, 3, 4]
|
||||
|
||||
class GT1151:
|
||||
def __init__(self):
|
||||
# e-Paper
|
||||
self.ERST = config.EPD_RST_PIN
|
||||
self.DC = config.EPD_DC_PIN
|
||||
self.CS = config.EPD_CS_PIN
|
||||
self.BUSY = config.EPD_BUSY_PIN
|
||||
# TP
|
||||
self.TRST = config.TRST
|
||||
self.INT = config.INT
|
||||
|
||||
def digital_read(self, pin):
|
||||
return config.digital_read(pin)
|
||||
|
||||
def GT_Reset(self):
|
||||
config.digital_write(self.TRST, 1)
|
||||
config.delay_ms(100)
|
||||
config.digital_write(self.TRST, 0)
|
||||
config.delay_ms(100)
|
||||
config.digital_write(self.TRST, 1)
|
||||
config.delay_ms(100)
|
||||
|
||||
def GT_Write(self, Reg, Data):
|
||||
config.i2c_writebyte(Reg, Data)
|
||||
|
||||
def GT_Read(self, Reg, len):
|
||||
return config.i2c_readbyte(Reg, len)
|
||||
|
||||
def GT_ReadVersion(self):
|
||||
buf = self.GT_Read(0x8140, 4)
|
||||
print(buf)
|
||||
|
||||
def GT_Init(self):
|
||||
self.GT_Reset()
|
||||
self.GT_ReadVersion()
|
||||
|
||||
def GT_Scan(self, GT_Dev, GT_Old):
|
||||
buf = []
|
||||
mask = 0x00
|
||||
|
||||
if(GT_Dev.Touch == 1):
|
||||
GT_Dev.Touch = 0
|
||||
buf = self.GT_Read(0x814E, 1)
|
||||
|
||||
if(buf[0]&0x80 == 0x00):
|
||||
self.GT_Write(0x814E, mask)
|
||||
config.delay_ms(10)
|
||||
|
||||
else:
|
||||
GT_Dev.TouchpointFlag = buf[0]&0x80
|
||||
GT_Dev.TouchCount = buf[0]&0x0f
|
||||
|
||||
if(GT_Dev.TouchCount > 5 or GT_Dev.TouchCount < 1):
|
||||
self.GT_Write(0x814E, mask)
|
||||
return
|
||||
|
||||
buf = self.GT_Read(0x814F, GT_Dev.TouchCount*8)
|
||||
self.GT_Write(0x814E, mask)
|
||||
|
||||
GT_Old.X[0] = GT_Dev.X[0];
|
||||
GT_Old.Y[0] = GT_Dev.Y[0];
|
||||
GT_Old.S[0] = GT_Dev.S[0];
|
||||
|
||||
for i in range(0, GT_Dev.TouchCount, 1):
|
||||
GT_Dev.Touchkeytrackid[i] = buf[0 + 8*i]
|
||||
GT_Dev.X[i] = (buf[2 + 8*i] << 8) + buf[1 + 8*i]
|
||||
GT_Dev.Y[i] = (buf[4 + 8*i] << 8) + buf[3 + 8*i]
|
||||
GT_Dev.S[i] = (buf[6 + 8*i] << 8) + buf[5 + 8*i]
|
||||
|
||||
print(GT_Dev.X[0], GT_Dev.Y[0], GT_Dev.S[0])
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import logging
|
||||
from . import epdconfig as config
|
||||
|
||||
class ICNT_Development:
|
||||
def __init__(self):
|
||||
self.Touch = 0
|
||||
self.TouchGestureid = 0
|
||||
self.TouchCount = 0
|
||||
|
||||
self.TouchEvenid = [0, 1, 2, 3, 4]
|
||||
self.X = [0, 1, 2, 3, 4]
|
||||
self.Y = [0, 1, 2, 3, 4]
|
||||
self.P = [0, 1, 2, 3, 4]
|
||||
|
||||
class INCT86:
|
||||
def __init__(self):
|
||||
# e-Paper
|
||||
self.ERST = config.EPD_RST_PIN
|
||||
self.DC = config.EPD_DC_PIN
|
||||
self.CS = config.EPD_CS_PIN
|
||||
self.BUSY = config.EPD_BUSY_PIN
|
||||
# TP
|
||||
self.TRST = config.TRST
|
||||
self.INT = config.INT
|
||||
|
||||
def digital_read(self, pin):
|
||||
return config.digital_read(pin)
|
||||
|
||||
def ICNT_Reset(self):
|
||||
config.digital_write(self.TRST, 1)
|
||||
config.delay_ms(100)
|
||||
config.digital_write(self.TRST, 0)
|
||||
config.delay_ms(100)
|
||||
config.digital_write(self.TRST, 1)
|
||||
config.delay_ms(100)
|
||||
|
||||
def ICNT_Write(self, Reg, Data):
|
||||
config.i2c_writebyte(Reg, Data)
|
||||
|
||||
def ICNT_Read(self, Reg, len):
|
||||
return config.i2c_readbyte(Reg, len)
|
||||
|
||||
def ICNT_ReadVersion(self):
|
||||
buf = self.ICNT_Read(0x000a, 4)
|
||||
print(buf)
|
||||
|
||||
def ICNT_Init(self):
|
||||
self.ICNT_Reset()
|
||||
self.ICNT_ReadVersion()
|
||||
|
||||
def ICNT_Scan(self, ICNT_Dev, ICNT_Old):
|
||||
buf = []
|
||||
mask = 0x00
|
||||
|
||||
if(ICNT_Dev.Touch == 1):
|
||||
# ICNT_Dev.Touch = 0
|
||||
buf = self.ICNT_Read(0x1001, 1)
|
||||
|
||||
if(buf[0] == 0x00):
|
||||
self.ICNT_Write(0x1001, mask)
|
||||
config.delay_ms(1)
|
||||
# print("buffers status is 0")
|
||||
return
|
||||
else:
|
||||
ICNT_Dev.TouchCount = buf[0]
|
||||
|
||||
if(ICNT_Dev.TouchCount > 5 or ICNT_Dev.TouchCount < 1):
|
||||
self.ICNT_Write(0x1001, mask)
|
||||
ICNT_Dev.TouchCount = 0
|
||||
# print("TouchCount number is wrong")
|
||||
return
|
||||
|
||||
buf = self.ICNT_Read(0x1002, ICNT_Dev.TouchCount*7)
|
||||
self.ICNT_Write(0x1001, mask)
|
||||
|
||||
ICNT_Old.X[0] = ICNT_Dev.X[0];
|
||||
ICNT_Old.Y[0] = ICNT_Dev.Y[0];
|
||||
ICNT_Old.P[0] = ICNT_Dev.P[0];
|
||||
|
||||
for i in range(0, ICNT_Dev.TouchCount, 1):
|
||||
ICNT_Dev.TouchEvenid[i] = buf[6 + 7*i]
|
||||
ICNT_Dev.X[i] = 295 - ((buf[2 + 7*i] << 8) + buf[1 + 7*i])
|
||||
ICNT_Dev.Y[i] = 127 - ((buf[4 + 7*i] << 8) + buf[3 + 7*i])
|
||||
ICNT_Dev.P[i] = buf[5 + 7*i]
|
||||
|
||||
print(ICNT_Dev.X[0], ICNT_Dev.Y[0], ICNT_Dev.P[0])
|
||||
return
|
||||
return
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
# This little program is for the Waveshare 2.9
|
||||
# inch Version 2 black and white only epaper display
|
||||
# It uses OpenWeatherMap API to display weather info
|
||||
import sys
|
||||
import os
|
||||
picdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../pic/2in9')
|
||||
icondir = os.path.join(picdir, 'icon')
|
||||
fontdir = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../../pic')
|
||||
|
||||
# Search lib folder for display driver modules
|
||||
sys.path.append('lib')
|
||||
from . import epd2in9_V2
|
||||
epd = epd2in9_V2.EPD_2IN9_V2()
|
||||
|
||||
from datetime import datetime
|
||||
import time
|
||||
from PIL import Image,ImageDraw,ImageFont
|
||||
import traceback
|
||||
|
||||
import requests, json
|
||||
from io import BytesIO
|
||||
import csv
|
||||
|
||||
# define funciton for writing image and sleeping for 5 min.
|
||||
def write_to_screen(image, sleep_seconds):
|
||||
print('Writing to screen.')
|
||||
# Write to screen
|
||||
h_image = Image.new('1', (epd.height, epd.width), 255)
|
||||
# Open the template
|
||||
screen_output_file = Image.open(os.path.join(picdir, image))
|
||||
# Initialize the drawing context with template as background
|
||||
h_image.paste(screen_output_file, (0, 0))
|
||||
epd.display(epd.getbuffer(h_image))
|
||||
# Sleep
|
||||
print('Sleeping for ' + str(sleep_seconds) +'.')
|
||||
time.sleep(sleep_seconds)
|
||||
|
||||
# define function for displaying error
|
||||
def display_error(error_source):
|
||||
# Display an error
|
||||
print('Error in the', error_source, 'request.')
|
||||
# Initialize drawing
|
||||
error_image = Image.new('1', (epd.height, epd.width), 255)
|
||||
# Initialize the drawing
|
||||
draw = ImageDraw.Draw(error_image)
|
||||
draw.text((5, 5), error_source +' ERROR', font=font20, fill=black)
|
||||
draw.text((5, 30), 'Retrying in 30 seconds', font=font20, fill=black)
|
||||
current_time = datetime.now().strftime('%H:%M')
|
||||
draw.text((5, 55), 'Last Refresh: ' + str(current_time), font = font20, fill=black)
|
||||
# Save the error image
|
||||
error_image_file = 'error.png'
|
||||
error_image.save(os.path.join(picdir, error_image_file))
|
||||
# Close error image
|
||||
error_image.close()
|
||||
# Write error to screen
|
||||
write_to_screen(error_image_file, 30)
|
||||
|
||||
# Set the fonts
|
||||
font12 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 12)
|
||||
font16 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 16)
|
||||
font20 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 20)
|
||||
font24 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 24)
|
||||
font30 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 30)
|
||||
font35 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 35)
|
||||
font50 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 50)
|
||||
font60 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 60)
|
||||
font100 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 100)
|
||||
font160 = ImageFont.truetype(os.path.join(fontdir, 'Font.ttc'), 160)
|
||||
|
||||
# Set the special fonts
|
||||
font18_Roboto_Bold = ImageFont.truetype(os.path.join(fontdir, 'Roboto-Bold.ttf'), 18)
|
||||
font20_Roboto_Bold = ImageFont.truetype(os.path.join(fontdir, 'Roboto-Bold.ttf'), 20)
|
||||
font20_Roboto_Regular = ImageFont.truetype(os.path.join(fontdir, 'Roboto-Regular.ttf'), 20)
|
||||
font34_Roboto_Black = ImageFont.truetype(os.path.join(fontdir, 'Roboto-Black.ttf'), 34)
|
||||
|
||||
# Set the colors
|
||||
black = 'rgb(0,0,0)'
|
||||
white = 'rgb(255,255,255)'
|
||||
grey = 'rgb(235,235,235)'
|
||||
|
||||
# Initialize and clear screen
|
||||
# print('Initializing and clearing screen.')
|
||||
# epd.init()
|
||||
# epd.Clear()
|
||||
|
||||
# I provide my API_KEY for you to test: 82ec63bb0530e31e0ef9042786d195cc, Please try to use your own API_KEY
|
||||
API_KEY = '******API KEY*******'
|
||||
LOCATION = 'Shenzhen'
|
||||
LATITUDE = '22.543097'
|
||||
LONGITUDE = '114.057861'
|
||||
UNITS = 'imperial'
|
||||
CSV_OPTION = False # if csv_option == True, a weather data will be appended to 'record.csv'
|
||||
|
||||
BASE_URL = 'http://api.openweathermap.org/data/2.5/onecall?'
|
||||
URL = BASE_URL + 'lat=' + LATITUDE + '&lon=' + LONGITUDE + '&units=' + UNITS +'&appid=' + API_KEY
|
||||
|
||||
def get_weather_png():
|
||||
# Ensure there are no errors with connection
|
||||
error_connect = True
|
||||
while error_connect == True:
|
||||
try:
|
||||
# HTTP request
|
||||
print('Attempting to connect to OWM.')
|
||||
response = requests.get(URL)
|
||||
print('Connection to OWM successful.')
|
||||
error_connect = None
|
||||
except:
|
||||
# Call function to display connection error
|
||||
print('Connection error.')
|
||||
display_error('CONNECTION')
|
||||
|
||||
error = None
|
||||
while error == None:
|
||||
# Check status of code request
|
||||
if response.status_code == 200:
|
||||
print('Connection to Open Weather successful.')
|
||||
# get data in jason format
|
||||
data = response.json()
|
||||
|
||||
# get current dict block
|
||||
current = data['current']
|
||||
# get current
|
||||
temp_current = current['temp']
|
||||
# get feels like
|
||||
feels_like = current['feels_like']
|
||||
# get humidity
|
||||
humidity = current['humidity']
|
||||
# get pressure
|
||||
wind = current['wind_speed']
|
||||
# get description
|
||||
weather = current['weather']
|
||||
report = weather[0]['description']
|
||||
# get icon url
|
||||
icon_code = weather[0]['icon']
|
||||
#icon_URL = 'http://openweathermap.org/img/wn/'+ icon_code +'@4x.png'
|
||||
|
||||
# get daily dict block
|
||||
daily = data['daily']
|
||||
# get daily precip
|
||||
daily_precip_float = daily[0]['pop']
|
||||
#format daily precip
|
||||
daily_precip_percent = daily_precip_float * 100
|
||||
# get min and max temp
|
||||
daily_temp = daily[0]['temp']
|
||||
temp_max = daily_temp['max']
|
||||
temp_min = daily_temp['min']
|
||||
|
||||
# Append weather data to CSV if csv_option == True
|
||||
if CSV_OPTION == True:
|
||||
# Get current year, month, date, and time
|
||||
current_year = datetime.now().strftime('%Y')
|
||||
current_month = datetime.now().strftime('%m')
|
||||
current_date = datetime.now().strftime('%d')
|
||||
current_time = datetime.now().strftime('%H:%M')
|
||||
#open the CSV and append weather data
|
||||
with open('records.csv', 'a', newline='') as csv_file:
|
||||
writer = csv.writer(csv_file, delimiter=',')
|
||||
writer.writerow([current_year, current_month, current_date, current_time,
|
||||
LOCATION,temp_current, feels_like, temp_max, temp_min,
|
||||
humidity, daily_precip_float, wind])
|
||||
print('Weather data appended to CSV.')
|
||||
|
||||
# Set strings to be printed to screen
|
||||
string_location = 'City: ' + LOCATION
|
||||
string_temp_current = format(temp_current, '.0f') + u'\N{DEGREE SIGN}F'
|
||||
string_temp_current_C = format((temp_current-32)/1.8, '.0f') + u'\N{DEGREE SIGN}C'
|
||||
string_temp = string_temp_current + ' / ' + string_temp_current_C
|
||||
string_feels_like = 'Feels like: ' + format(feels_like, '.0f') + u'\N{DEGREE SIGN}F'
|
||||
string_humidity = 'Humidity: ' + str(humidity) + '%'
|
||||
string_wind = 'Wind: ' + format(wind, '.1f') + ' MPH'
|
||||
# string_report = 'Now: ' + report.title()
|
||||
string_report = report.title()
|
||||
string_temp_max = 'High: ' + format(temp_max, '>.0f') + u'\N{DEGREE SIGN}F'
|
||||
string_temp_min = 'Low: ' + format(temp_min, '>.0f') + u'\N{DEGREE SIGN}F'
|
||||
string_precip_percent = 'Precip: ' + str(format(daily_precip_percent, '.0f')) + '%'
|
||||
|
||||
# Set error code to false
|
||||
error = False
|
||||
|
||||
'''
|
||||
print('Location:', LOCATION)
|
||||
print('Temperature:', format(temp_current, '.0f'), u'\N{DEGREE SIGN}F')
|
||||
print('Feels Like:', format(feels_like, '.0f'), 'F')
|
||||
print('Humidity:', humidity)
|
||||
print('Wind Speed:', format(wind_speed, '.1f'), 'MPH')
|
||||
print('Report:', report.title())
|
||||
|
||||
print('High:', format(temp_max, '.0f'), 'F')
|
||||
print('Low:', format(temp_min, '.0f'), 'F')
|
||||
print('Probabilty of Precipitation: ' + str(format(daily_precip_percent, '.0f')) + '%')
|
||||
'''
|
||||
else:
|
||||
# Call function to display HTTP error
|
||||
display_error('HTTP')
|
||||
|
||||
# Open template file
|
||||
template = Image.open(os.path.join(picdir, 'template.bmp'))
|
||||
# Initialize the drawing context with template as background
|
||||
draw = ImageDraw.Draw(template)
|
||||
|
||||
draw.rectangle((0, 0, 295, 67), fill=white)
|
||||
|
||||
# Draw top left box
|
||||
## Open icon file
|
||||
icon_file = icon_code + '.png'
|
||||
icon_image = Image.open(os.path.join(icondir, icon_file))
|
||||
icon_image_resize = icon_image.resize((68, 68))
|
||||
|
||||
### Paste the image
|
||||
template.paste(icon_image_resize, (0, 0))
|
||||
## Place a black rectangle outline
|
||||
# draw.rectangle((15, 5, 80, 60), outline=black)
|
||||
## Draw text
|
||||
font_report = font20_Roboto_Bold
|
||||
font_report_size = 20
|
||||
while(font_report.getsize(string_report)[0] > 120):
|
||||
font_report_size -= 2
|
||||
font_report = ImageFont.truetype(os.path.join(fontdir, 'Roboto-Bold.ttf'), font_report_size)
|
||||
draw.text((70, 12), string_report, font=font_report, fill=black)
|
||||
draw.text((70, 34), string_precip_percent, font=font20_Roboto_Bold, fill=black)
|
||||
|
||||
# Draw top right box
|
||||
draw.text((12, 72), string_temp, font=font18_Roboto_Bold, fill=white)
|
||||
# draw.text((60, 30), string_feels_like, font=font20, fill=white)
|
||||
|
||||
# Draw bottom left box
|
||||
# draw.text((15, 85), string_temp_max, font=font20, fill=black)
|
||||
# draw.rectangle((15, 108, 265, 110), fill=black)
|
||||
# draw.text((15, 105), string_temp_min, font=font20, fill=black)
|
||||
|
||||
# Draw bottom middle box
|
||||
# draw.text((120, 85), string_humidity, font=font20, fill=black)
|
||||
# draw.text((120, 105), string_wind, font=font20, fill=black)
|
||||
|
||||
# Draw bottom right box
|
||||
draw.text((295-11-font20_Roboto_Regular.getsize('UPDATED')[0], 7), 'UPDATED', font=font20_Roboto_Regular, fill=black, align='right')
|
||||
current_time = datetime.now().strftime('%H:%M')
|
||||
draw.text((295-11-font34_Roboto_Black.getsize(current_time)[0], 25), current_time, font = font34_Roboto_Black, fill=black, align='right')
|
||||
# draw.rectangle((193, 35, 288, 85), outline=black)
|
||||
|
||||
draw.text((295-11-font18_Roboto_Bold.getsize(string_location)[0], 72), string_location, font = font18_Roboto_Bold, fill=white, align='right')
|
||||
|
||||
## Add a reminder to take out trash on Mon and Thurs
|
||||
# weekday = datetime.today().weekday()
|
||||
# if weekday == 0 or weekday == 3:
|
||||
# draw.rectangle((345, 13, 705, 55), fill =black)
|
||||
# draw.text((355, 15), 'TAKE OUT TRASH TODAY!', font=font18, fill=white)
|
||||
|
||||
# Save the image for display as PNG
|
||||
screen_output_file = os.path.join(picdir, 'screen_output.png')
|
||||
template.save(screen_output_file)
|
||||
# Close the template file
|
||||
template.close()
|
||||
|
||||
# Refresh clear screen to avoid burn-in at 3:00 AM
|
||||
# if datetime.now().strftime('%H') == '03':
|
||||
# print('Clearning screen to avoid burn-in.')
|
||||
# epd.Clear()
|
||||
|
||||
# Write to screen
|
||||
# write_to_screen(screen_output_file, 600)
|
||||
Reference in New Issue
Block a user