Skip to content

Instantly share code, notes, and snippets.

@mu88
Last active July 9, 2023 12:59
Show Gist options
  • Save mu88/30672b24909995ade76ceda10cbde80b to your computer and use it in GitHub Desktop.
Save mu88/30672b24909995ade76ceda10cbde80b to your computer and use it in GitHub Desktop.
Display screenshot on Waveshare ePaper display
import framebuf
import gc
from machine import Pin, SPI, I2C
import network
import time
import urequests
import utime
class INA219:
def __init__(self, i2c_bus=1, addr=0x40):
self.i2c = I2C(i2c_bus);
self.addr = addr
# Set chip to known config values to start
self._cal_value = 0
self._current_lsb = 0
self._power_lsb = 0
self.set_calibration_32V_2A()
def read(self,address):
data = self.i2c.readfrom_mem(self.addr, address, 2)
return ((data[0] * 256 ) + data[1])
def write(self,address,data):
temp = [0,0]
temp[1] = data & 0xFF
temp[0] =(data & 0xFF00) >> 8
self.i2c.writeto_mem(self.addr,address,bytes(temp))
def set_calibration_32V_2A(self):
self._current_lsb = 1 # Current LSB = 100uA per bit
self._cal_value = 4096
self._power_lsb = .002 # Power LSB = 2mW per bit
self.write(0x05,self._cal_value)
# Set Config register to take into account the settings above
self.bus_voltage_range = 0x01
self.gain = 0x03
self.bus_adc_resolution = 0x0D
self.shunt_adc_resolution = 0x0D
self.mode = 0x07
self.config = self.bus_voltage_range << 13 | \
self.gain << 11 | \
self.bus_adc_resolution << 7 | \
self.shunt_adc_resolution << 3 | \
self.mode
self.write(0x00,self.config)
def getBusVoltage(self):
self.read(0x02)
bus_voltage = (self.read(0x02) >> 3) * 0.004
percentage = (bus_voltage -3)/1.2*100
if(percentage<0):percentage=0
elif(percentage>100):percentage=100
return percentage
# Display resolution
EPD_WIDTH = 800
EPD_HEIGHT = 480
RST_PIN = 12
DC_PIN = 8
CS_PIN = 9
BUSY_PIN = 13
class EPD_7in5_B:
def __init__(self):
self.reset_pin = Pin(RST_PIN, Pin.OUT)
self.busy_pin = Pin(BUSY_PIN, Pin.IN, Pin.PULL_UP)
self.cs_pin = Pin(CS_PIN, Pin.OUT)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.spi = SPI(1)
self.spi.init(baudrate=4000_000)
self.dc_pin = Pin(DC_PIN, Pin.OUT)
self.buffer_black = bytearray(self.height * self.width // 8)
self.buffer_red = bytearray(self.height * self.width // 8)
self.imageblack = framebuf.FrameBuffer(self.buffer_black, self.width, self.height, framebuf.MONO_HLSB)
self.imagered = framebuf.FrameBuffer(self.buffer_red, self.width, self.height, framebuf.MONO_HLSB)
self.init()
def digital_write(self, pin, value):
pin.value(value)
def digital_read(self, pin):
return pin.value()
def delay_ms(self, delaytime):
utime.sleep(delaytime / 1000.0)
def spi_writebyte(self, data):
self.spi.write(bytearray(data))
def module_exit(self):
self.digital_write(self.reset_pin, 0)
# Hardware reset
def reset(self):
self.digital_write(self.reset_pin, 1)
self.delay_ms(200)
self.digital_write(self.reset_pin, 0)
self.delay_ms(2)
self.digital_write(self.reset_pin, 1)
self.delay_ms(200)
def send_command(self, command):
self.digital_write(self.dc_pin, 0)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([command])
self.digital_write(self.cs_pin, 1)
def send_data(self, data):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([data])
self.digital_write(self.cs_pin, 1)
def send_data1(self, buf):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi.write(bytearray(buf))
self.digital_write(self.cs_pin, 1)
def WaitUntilIdle(self):
print("e-Paper busy")
while(self.digital_read(self.busy_pin) == 0): # Wait until the busy_pin goes LOW
self.delay_ms(20)
self.delay_ms(20)
print("e-Paper busy release")
def TurnOnDisplay(self):
self.send_command(0x12) # DISPLAY REFRESH
self.delay_ms(100) #!!!The delay here is necessary, 200uS at least!!!
self.WaitUntilIdle()
def init(self):
# EPD hardware init start
self.reset()
self.send_command(0x06) # btst
self.send_data(0x17)
self.send_data(0x17)
self.send_data(0x28) # If an exception is displayed, try using 0x38
self.send_data(0x17)
self.send_command(0x04) # POWER ON
self.delay_ms(100)
self.WaitUntilIdle()
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)
self.send_command(0x65) # Resolution setting
self.send_data(0x00)
self.send_data(0x00) # 800*480
self.send_data(0x00)
self.send_data(0x00)
return 0;
def Clear(self):
high = self.height
if( self.width % 8 == 0) :
wide = self.width // 8
else :
wide = self.width // 8 + 1
self.send_command(0x10)
for i in range(0, wide):
self.send_data1([0xff] * high)
self.send_command(0x13)
for i in range(0, wide):
self.send_data1([0x00] * high)
self.TurnOnDisplay()
def display(self):
high = self.height
if( self.width % 8 == 0) :
wide = self.width // 8
else :
wide = self.width // 8 + 1
# send black data
self.send_command(0x10)
for i in range(0, wide):
self.send_data1(self.buffer_black[(i * high) : ((i+1) * high)])
# send red data
self.send_command(0x13)
for i in range(0, wide):
self.send_data1(self.buffer_red[(i * high) : ((i+1) * high)])
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x02) # power off
self.WaitUntilIdle()
self.send_command(0x07) # deep sleep
self.send_data(0xa5)
def connect_wifi():
pin = Pin("LED", Pin.OUT)
pin.off()
# waiting some time between connecting and checking the status is crucial for a reliable WiFi connection
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
time.sleep(2)
wifi.connect('<<SSID>>', '<<Password>>')
time.sleep(2)
max_wait = 10
while max_wait > 0:
if wifi.status() < 0 or wifi.status() >= 3:
break
max_wait -= 1
time.sleep(1)
if wifi.status() != 3:
raise RuntimeError('network connection failed')
wifi = None
if __name__=='__main__':
gc.enable()
pin = Pin("LED", Pin.OUT)
pin.off()
epd = EPD_7in5_B()
epd.Clear()
sleep_in_seconds = 90
empty_buffer = bytearray(0)
ina219 = INA219(addr=0x43)
try:
connect_wifi()
while(True):
gc.collect()
response = urequests.get('http://<<Server>>/screenshotCreator/latestImage?blackAndWhite=true&asWaveshareBytes=true&addWaveshareInstructions=true')
if response.status_code == 200:
update_screen = response.headers.get('waveshare-update-screen', 'True') == 'True'
sleep_in_seconds = int(response.headers.get('waveshare-sleep-between-updates', '90'))
if update_screen:
last_modified = response.headers.get('waveshare-last-modified-local-time', 'xx:xx')
voltage_percentage = ina219.getBusVoltage()
epd.init() # explicitly wake up display from deep sleep
# assign black and red portion
gc.collect()
time.sleep(1)
epd.buffer_black = response.content
epd.imagered.fill(0x00)
epd.imagered.text(last_modified, 750, 460, 0xff)
epd.imagered.text(str(voltage_percentage), 20, 460, 0xff)
# display and go to deep sleep
epd.display()
epd.sleep()
# do not leak memory
epd.buffer_black = empty_buffer
update_screen = None
last_modified = None
response = None
time.sleep(sleep_in_seconds)
except Exception as e:
print(e)
f = open('error.txt', 'w')
f.write(str(e))
f.close()
pin = Pin("LED", Pin.OUT)
pin.on()
raise e
import framebuf
import gc
from machine import Pin, SPI
import network
import time
import urequests
import utime
# Display resolution
EPD_WIDTH = 800
EPD_HEIGHT = 480
RST_PIN = 12
DC_PIN = 8
CS_PIN = 9
BUSY_PIN = 13
class EPD_7in5_B:
def __init__(self):
self.reset_pin = Pin(RST_PIN, Pin.OUT)
self.busy_pin = Pin(BUSY_PIN, Pin.IN, Pin.PULL_UP)
self.cs_pin = Pin(CS_PIN, Pin.OUT)
self.width = EPD_WIDTH
self.height = EPD_HEIGHT
self.spi = SPI(1)
self.spi.init(baudrate=4000_000)
self.dc_pin = Pin(DC_PIN, Pin.OUT)
self.buffer_black = bytearray(self.height * self.width // 8)
self.buffer_red = bytearray(self.height * self.width // 8)
self.imageblack = framebuf.FrameBuffer(self.buffer_black, self.width, self.height, framebuf.MONO_HLSB)
self.imagered = framebuf.FrameBuffer(self.buffer_red, self.width, self.height, framebuf.MONO_HLSB)
self.init()
def digital_write(self, pin, value):
pin.value(value)
def digital_read(self, pin):
return pin.value()
def delay_ms(self, delaytime):
utime.sleep(delaytime / 1000.0)
def spi_writebyte(self, data):
self.spi.write(bytearray(data))
def module_exit(self):
self.digital_write(self.reset_pin, 0)
# Hardware reset
def reset(self):
self.digital_write(self.reset_pin, 1)
self.delay_ms(200)
self.digital_write(self.reset_pin, 0)
self.delay_ms(2)
self.digital_write(self.reset_pin, 1)
self.delay_ms(200)
def send_command(self, command):
self.digital_write(self.dc_pin, 0)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([command])
self.digital_write(self.cs_pin, 1)
def send_data(self, data):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi_writebyte([data])
self.digital_write(self.cs_pin, 1)
def send_data1(self, buf):
self.digital_write(self.dc_pin, 1)
self.digital_write(self.cs_pin, 0)
self.spi.write(bytearray(buf))
self.digital_write(self.cs_pin, 1)
def WaitUntilIdle(self):
print("e-Paper busy")
while(self.digital_read(self.busy_pin) == 0): # Wait until the busy_pin goes LOW
self.delay_ms(20)
self.delay_ms(20)
print("e-Paper busy release")
def TurnOnDisplay(self):
self.send_command(0x12) # DISPLAY REFRESH
self.delay_ms(100) #!!!The delay here is necessary, 200uS at least!!!
self.WaitUntilIdle()
def init(self):
# EPD hardware init start
self.reset()
self.send_command(0x06) # btst
self.send_data(0x17)
self.send_data(0x17)
self.send_data(0x28) # If an exception is displayed, try using 0x38
self.send_data(0x17)
self.send_command(0x04) # POWER ON
self.delay_ms(100)
self.WaitUntilIdle()
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)
self.send_command(0x65) # Resolution setting
self.send_data(0x00)
self.send_data(0x00) # 800*480
self.send_data(0x00)
self.send_data(0x00)
return 0;
def Clear(self):
high = self.height
if( self.width % 8 == 0) :
wide = self.width // 8
else :
wide = self.width // 8 + 1
self.send_command(0x10)
for i in range(0, wide):
self.send_data1([0xff] * high)
self.send_command(0x13)
for i in range(0, wide):
self.send_data1([0x00] * high)
self.TurnOnDisplay()
def display(self):
high = self.height
if( self.width % 8 == 0) :
wide = self.width // 8
else :
wide = self.width // 8 + 1
# send black data
self.send_command(0x10)
for i in range(0, wide):
self.send_data1(self.buffer_black[(i * high) : ((i+1) * high)])
# send red data
self.send_command(0x13)
for i in range(0, wide):
self.send_data1(self.buffer_red[(i * high) : ((i+1) * high)])
self.TurnOnDisplay()
def sleep(self):
self.send_command(0x02) # power off
self.WaitUntilIdle()
self.send_command(0x07) # deep sleep
self.send_data(0xa5)
def connect_wifi():
pin = Pin("LED", Pin.OUT)
pin.off()
# waiting some time between connecting and checking the status is crucial for a reliable WiFi connection
wifi = network.WLAN(network.STA_IF)
wifi.active(True)
time.sleep(2)
wifi.connect('<<SSID>>', '<<Password>>')
time.sleep(2)
max_wait = 10
while max_wait > 0:
if wifi.status() < 0 or wifi.status() >= 3:
break
max_wait -= 1
time.sleep(1)
if wifi.status() != 3:
raise RuntimeError('network connection failed')
wifi = None
if __name__=='__main__':
gc.enable()
pin = Pin("LED", Pin.OUT)
pin.off()
epd = EPD_7in5_B()
epd.Clear()
sleep_in_seconds = 90
empty_buffer = bytearray(0)
try:
connect_wifi()
while(True):
gc.collect()
response = urequests.get('http://<<Server>>/screenshotCreator/latestImage?blackAndWhite=true&asWaveshareBytes=true&addWaveshareInstructions=true')
if response.status_code == 200:
update_screen = response.headers.get('waveshare-update-screen', 'True') == 'True'
sleep_in_seconds = int(response.headers.get('waveshare-sleep-between-updates', '90'))
if update_screen:
last_modified = response.headers.get('waveshare-last-modified-local-time', 'xx:xx')
epd.init() # explicitly wake up display from deep sleep
# assign black and red portion
gc.collect()
time.sleep(1)
epd.buffer_black = response.content
epd.imagered.fill(0x00)
epd.imagered.text(last_modified, 750, 460, 0xff)
# display and go to deep sleep
epd.display()
epd.sleep()
# do not leak memory
epd.buffer_black = empty_buffer
update_screen = None
last_modified = None
response = None
time.sleep(sleep_in_seconds)
except Exception as e:
print(e)
f = open('error.txt', 'w')
f.write(str(e))
f.close()
pin = Pin("LED", Pin.OUT)
pin.on()
raise e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment