Added driver, demo and setup-example for the WeAct Studio 2.9in EPD display with the SSD1680 driver

pull/56/head
Enrico Rossini 2023-08-27 15:09:24 +02:00
rodzic aef423a536
commit c9fbe2a995
5 zmienionych plików z 536 dodań i 26 usunięć

Wyświetl plik

@ -13,32 +13,33 @@ owing to their long update time.
Size is diagonal in inches. C/M/GS color/1-bit monochrome/greyscale.
Width and height are pixels.
| Size | Width | Height | Tech | Driver | Description | Notes |
|:------:|:-----:|:------:|:------|:--------------|:----------------------------|:------|
| 0.96C | 94 | 64 | OLED | [SSD1331][1d] | [Adafruit 684][1m] | |
| 1.12GS | 96 | 96 | OLED | [SSD1327][11d]| [Seeed 104030011][21m] | Obsolescent. |
| 1.27C | 128 | 96 | OLED | [SSD1351][2d] | [Adafruit 1673][2m] | |
| 1.5C | 128 | 128 | OLED | [SSD1351][2d] | [Adafruit 1431][3m] | |
| 1.44C | 128 | 128 | TFT | [ST7735R][4d] | [Adafruit 2088][5m] | |
| 1.5C | 160 | 128 | TFT | [ST7735R][4d] | [Adafruit 358][6m] | |
| 1.3C | 240 | 240 | TFT | [ST7789][5d] | [Adafruit 4313][7m] | |
| 1.5GS | 128 | 128 | OLED | [SSD1327][11d]| [Waveshare 13992][20m] | |
| 2.0C | 320 | 240 | TFT | [ST7789][5d] | [Waveshare Pico LCD 2][18m] | For Pi Pico. |
| 1.54C | 240 | 240 | TFT | [ST7789][5d] | [Adafruit 3787][8m] | |
| 1.14C | 240 | 135 | TFT | [ST7789][5d] | [T-Display][9m] | ESP32 with attached display. |
| 2.8C | 320 | 240 | TFT | [ST7789][5d] | [Waveshare pico 2.8][10m] | Display for Pi Pico. |
| 1.14C | 240 | 135 | TFT | [ST7789][5d] | [Waveshare pico 1.14][11m] | For Pi Pico. Buttons good for micro-gui. |
| 1.14C | 240 | 135 | TFT | [ST7789][5d] | [Pimoroni pico 1.14][23m] | For Pi Pico. Buttons good for micro-gui. |
| 3.2C | 320 | 240 | TFT | [ILI9341][6d] | [Adafruit 1743][12m] | Big display. eBay equivalents work here. |
| 3.5C | 480 | 320 | TFT | [ILI9486][12d]| [Waveshare Rpi 3.5 LCD][22m]| Pi HAT. Many pixels. Needs plenty of RAM. |
| 3.5C | 480 | 320 | TFT | [ILI9486][12d]| [Adafruit 3.5 LCD][24m] | 3.5" HX8357D display, notes as above. |
| 3.5C | 480 | 320 | TFT | [ILI9486][12d]| [Waveshere RPI 3.5 LCD][25m]| 3.5" ILI9488 display, notes as above. |
| 2.9M | 296 | 128 | eInk | [UC8151D][7d] | [Adafruit 4262][13m] | Flexible ePaper display. |
| 2.9M | 296 | 128 | eInk | [UC8151D][7d] | [Adafruit 4777][15m] | FeatherWing ePaper display. |
| 4.2M | 400 | 300 | eInk | [WS][10d] | [Waveshare pico 4.2][19m] | Pico, Pico W plug in. Other hosts via cable. |
| 2.7M | 274 | 176 | eInk | [HAT][8d] | [Waveshare HAT][14m] | HAT designed for Raspberry Pi, repurposed. |
| 2.7M | 400 | 240 | Sharp | [Sharp][9d] | [Adafruit 4694][16m] | Micropower monochrome display. |
| 1.3M | 168 | 144 | Sharp | [Sharp][9d] | [Adafruit 3502][17m] | Ditto. |
| Size | Width | Height | Tech | Driver | Description | Notes |
|:------:|:-----:|:------:|:------|:---------------|:-----------------------------|:---------------------------------------------|
| 0.96C | 94 | 64 | OLED | [SSD1331][1d] | [Adafruit 684][1m] | |
| 1.12GS | 96 | 96 | OLED | [SSD1327][11d] | [Seeed 104030011][21m] | Obsolescent. |
| 1.27C | 128 | 96 | OLED | [SSD1351][2d] | [Adafruit 1673][2m] | |
| 1.5C | 128 | 128 | OLED | [SSD1351][2d] | [Adafruit 1431][3m] | |
| 1.44C | 128 | 128 | TFT | [ST7735R][4d] | [Adafruit 2088][5m] | |
| 1.5C | 160 | 128 | TFT | [ST7735R][4d] | [Adafruit 358][6m] | |
| 1.3C | 240 | 240 | TFT | [ST7789][5d] | [Adafruit 4313][7m] | |
| 1.5GS | 128 | 128 | OLED | [SSD1327][11d] | [Waveshare 13992][20m] | |
| 2.0C | 320 | 240 | TFT | [ST7789][5d] | [Waveshare Pico LCD 2][18m] | For Pi Pico. |
| 1.54C | 240 | 240 | TFT | [ST7789][5d] | [Adafruit 3787][8m] | |
| 1.14C | 240 | 135 | TFT | [ST7789][5d] | [T-Display][9m] | ESP32 with attached display. |
| 2.8C | 320 | 240 | TFT | [ST7789][5d] | [Waveshare pico 2.8][10m] | Display for Pi Pico. |
| 1.14C | 240 | 135 | TFT | [ST7789][5d] | [Waveshare pico 1.14][11m] | For Pi Pico. Buttons good for micro-gui. |
| 1.14C | 240 | 135 | TFT | [ST7789][5d] | [Pimoroni pico 1.14][23m] | For Pi Pico. Buttons good for micro-gui. |
| 3.2C | 320 | 240 | TFT | [ILI9341][6d] | [Adafruit 1743][12m] | Big display. eBay equivalents work here. |
| 3.5C | 480 | 320 | TFT | [ILI9486][12d] | [Waveshare Rpi 3.5 LCD][22m] | Pi HAT. Many pixels. Needs plenty of RAM. |
| 3.5C | 480 | 320 | TFT | [ILI9486][12d] | [Adafruit 3.5 LCD][24m] | 3.5" HX8357D display, notes as above. |
| 3.5C | 480 | 320 | TFT | [ILI9486][12d] | [Waveshere RPI 3.5 LCD][25m] | 3.5" ILI9488 display, notes as above. |
| 2.9M | 296 | 128 | eInk | [UC8151D][7d] | [Adafruit 4262][13m] | Flexible ePaper display. |
| 2.9M | 296 | 128 | eInk | [UC8151D][7d] | [Adafruit 4777][15m] | FeatherWing ePaper display. |
| 2.9M | 296 | 128 | eInk | [SSD1680][15d] | [WeAct Studio ePaper][26m] | WeAct Studio ePaper display. |
| 4.2M | 400 | 300 | eInk | [WS][10d] | [Waveshare pico 4.2][19m] | Pico, Pico W plug in. Other hosts via cable. |
| 2.7M | 274 | 176 | eInk | [HAT][8d] | [Waveshare HAT][14m] | HAT designed for Raspberry Pi, repurposed. |
| 2.7M | 400 | 240 | Sharp | [Sharp][9d] | [Adafruit 4694][16m] | Micropower monochrome display. |
| 1.3M | 168 | 144 | Sharp | [Sharp][9d] | [Adafruit 3502][17m] | Ditto. |
## Displays using compatible drivers
@ -105,6 +106,7 @@ simple. See [this doc](./DRIVERS.md#7-writing-device-drivers) for details.
[12d]: https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md#34-driver-for-ili9486
[13d]: https://github.com/peterhinch/micropython-nano-gui/blob/master/drivers/sh1106/sh1106.py
[14d]: https://github.com/peterhinch/micropython-nano-gui/blob/master/drivers/ssd1306/ssd1306.py
[15d]: https://github.com/peterhinch/micropython-nano-gui/blob/master/DRIVERS.md#54-weact-studio-ssd1680-eink-displays
[1m]: https://www.adafruit.com/product/684
[2m]: https://www.adafruit.com/product/1673
@ -131,4 +133,5 @@ simple. See [this doc](./DRIVERS.md#7-writing-device-drivers) for details.
[23m]: https://shop.pimoroni.com/products/pico-display-pack?variant=32368664215635
[24m]: https://www.adafruit.com/product/2050
[25m]: https://www.waveshare.com/wiki/Pico-ResTouch-LCD-3.5
[26m]: https://aliexpress.com/item/1005004644515880.html

Wyświetl plik

@ -1374,6 +1374,20 @@ Color values of 0 (white) to 3 (black) can explicitly be specified.
###### [Contents](./DRIVERS.md#contents)
## 5.4 WeAct Studio SSD1680 eInk Displays
The driver supports the WeAct Studio SSD1680 2.9 inch 296*128 pixel
[display](https://github.com/WeActStudio/WeActStudio.EpaperModule) that uses the
[SSD1680 driver](https://github.com/WeActStudio/WeActStudio.EpaperModule/blob/master/Doc/SSD1680.pdf).
This display lacks many features when compared to the ones from Waveshare,
two important examples are fast refresh and partial refresh. The big pro however is the price,
it costs half the money of the Waveshare 2.9in alternative.
The driver is cross platform and supports landscape or portrait mode. To keep
the buffer size down (to 4736 bytes) there is no greyscale support. It should
be noted that WeAct Studio product page suggests to not update the display more frequently than every 180s.
# 6. EPD Asynchronous support
The following applies to nano-gui. Under micro-gui the update mechanism is

Wyświetl plik

@ -0,0 +1,200 @@
# Nanogui driver for WeAct Studio 2.9" Black and White ePaper display.
# This driver can be used with the 2.13" EPD from WeAct Studio or with
# other displays with the same driver however, on my tests changing the resolution
# may rise exception, but I manage to successfully use this driver with the smaller
# display without changing the resolution.
# [Display](https://github.com/WeActStudio/WeActStudio.EpaperModule)
# EPD is subclassed from framebuf.FrameBuffer for use with Writer class and nanogui.
# Released under the MIT license see LICENSE
# Based on the following sources:
# https://github.com/peterhinch/micropython-nano-gui/blob/master/drivers/epaper/epd29.py
# https://github.com/hfwang132/ssd1680-micropython-drivers
# You can run a demo for this driver by executing the demo script "epd29_sync.py"
# or "epd29_weactstudio.py" after changing landscape=False when creating "ssd" on color_setup.py
import framebuf
import uasyncio as asyncio
from micropython import const
from time import sleep_ms, sleep_us, ticks_ms, ticks_us, ticks_diff
from gui.drivers.boolpalette import BoolPalette
from machine import lightsleep, Pin
class TimeoutError(Exception):
def __init__(self, msg):
super().__init__(msg)
class EPD(framebuf.FrameBuffer):
# A monochrome approach should be used for coding this. The rgb method ensures
# nothing breaks if users specify colors.
@staticmethod
def rgb(r, g, b):
return int((r > 127) or (g > 127) or (b > 127))
# Discard asyn: autodetect
def __init__(self, spi, cs, dc, rst_pin, busy, landscape=True):
self._spi = spi
self._cs = cs # Pins
self._dc = dc
self._rst = Pin(rst_pin, Pin.OUT, value=1)
self._rst_pin = rst_pin
self._busy = busy # Pin High if Busy
self._lsc = landscape
# ._as_busy is set immediately on start of task. Cleared
# when busy pin is physically 0.
self._as_busy = False
self.updated = asyncio.Event()
self.complete = asyncio.Event()
# Public bound variables required by nanogui.
# Dimensions in pixels as seen by nanogui (landscape mode).
self.width = 296 if landscape else 128
self.height = 128 if landscape else 296
# Other public bound variable.
# Special mode enables demos written for generic displays to run.
self.demo_mode = False
self._buffer = bytearray(self.height * self.width // 8)
self._mvb = memoryview(self._buffer)
mode = framebuf.MONO_VLSB if landscape else framebuf.MONO_HLSB
self.palette = BoolPalette(mode)
super().__init__(self._buffer, self.width, self.height, mode)
self.init()
def _command(self, command, data=None):
self._dc(0)
self._spi.write(command)
self._dc(1)
if data is not None:
self._data(data)
def _data(self, data, buf1=bytearray(1)):
for b in data:
buf1[0] = b
self._spi.write(buf1)
def hw_reset(self):
self._rst(1)
sleep_ms(200)
self._rst(0)
sleep_ms(200)
self._rst(1)
self.wait_until_ready()
# print("hardware reset successful")
def init(self):
# Hardware reset
self.hw_reset()
self._dc(1)
self._cs(0)
# Initialisation
cmd = self._command
# Software Reset
# print("software resetting...")
# cmd(b'\x12')
# self.wait_until_ready()
# print("software reset successful")
# deriver output control
cmd(b'\x01', b'\x27\x01\x01')
# data entry mode
cmd(b'\x11', b'\x01')
# set ram-x addr start/end pos
cmd(b'\x44', b'\x00\x0F')
# set ram-y addr start/end pos
cmd(b'\x45', b'\x27\x01\x00\x00')
# border waveform
cmd(b'\x3c', b'\x05')
# display update control
cmd(b'\x21', b'\x00\x80')
# set ram-x addr cnt to 0
cmd(b'\x4e', b'\x00')
# set ram-y addr cnt to 0x127
cmd(b'\x4F', b'\x27\x01')
# set to use internal temperature sensor
cmd(b'\x18', b'\x80')
'''
# read from internal temperature sensor
self._dc(0)
self._spi.write(b'\x1B')
print(self._spi.read(2))
self._dc(1)
print(self._spi.read(2))
'''
self.wait_until_ready()
# print('Init Done.')
# For use in synchronous code: blocking wait on ready state.
def wait_until_ready(self):
sleep_ms(50)
while not self.ready():
sleep_ms(100)
# Return immediate status. Pin state: 1 == busy.
def ready(self):
return not (self._as_busy or (self._busy() == 1))
# draw the current frame memory.
def show(self, buf1=bytearray(1),
fast_refresh=False, # USELESS for this driver, doesn't work well at all
deepsleep_after_refresh=False,
lightsleep_while_waiting_for_refresh=False):
if not self.ready():
# Hardware reset to exit deep sleep mode
self.hw_reset()
mvb = self._mvb
cmd = self._command
dat = self._data
cmd(b'\x24')
if self._lsc: # Landscape mode
wid = self.width
tbc = self.height // 8 # Vertical bytes per column
iidx = wid * (tbc - 1) # Initial index
idx = iidx # Index into framebuf
vbc = 0 # Current vertical byte count
hpc = 0 # Horizontal pixel count
for _ in range(len(mvb)):
buf1[0] = ~mvb[idx]
dat(buf1)
idx -= wid
vbc += 1
vbc %= tbc
if not vbc:
hpc += 1
idx = iidx + hpc
else:
for b in mvb:
buf1[0] = ~b
dat(buf1)
if fast_refresh:
cmd(b'\x22', b'\xFF')
else:
cmd(b'\x22', b'\xF7')
sleep_us(20)
cmd(b'\x20') # DISPLAY_REFRESH
if lightsleep_while_waiting_for_refresh:
# set Pin hold=True is needed before entering lightsleep and after you must revert it back to hold=False
# without this, entering lightsleep results in a low state on the reset pin, and this resets the driver
self._rst = Pin(self._rst_pin, Pin.OUT, value=1, hold=True)
lightsleep(3000) # can be used to lowering consumption on ESP32
self._rst = Pin(self._rst_pin, Pin.OUT, value=1, hold=False)
self.wait_until_ready()
if deepsleep_after_refresh:
cmd(b'\x10', b'\x01')
else:
cmd(b'\x10', b'\x00')

Wyświetl plik

@ -0,0 +1,271 @@
import utime
from time import time
from math import exp
# import uos
from color_setup import ssd
# On a monochrome display Writer is more efficient than CWriter.
from gui.core.writer import Writer
from gui.core.nanogui import refresh, circle
from gui.widgets.label import Label
# Fonts
import gui.fonts.arial35 as font_big
import gui.fonts.freesans20 as font_mid
import gui.fonts.arial10 as font_small
energy_meter_data_topic = "EnergyMeter"
weather_out_data_topic = "WeatherOut"
alert_thereshold = 30 # in minutes
prev_data_from_bridge = {energy_meter_data_topic: {"data": None, "timestamp": None},
weather_out_data_topic: {"data": None, "timestamp": None}}
in_data = {"co2": 689, "temperature": 25.5, "humidity": 54.12}
prev_data_from_bridge[energy_meter_data_topic]["data"] = {"power": 7.212, "voltage": 209.2}
prev_data_from_bridge[weather_out_data_topic]["data"] = {"temperature": 31.545, "humidity": 72.45}
in_temp = in_data["temperature"]
in_temp_int = str(int(in_temp))
in_temp_float = round(float(in_temp), 1)
in_temp_float = f'{in_temp_float:.1f}'
in_hum = str(int(in_data["humidity"]))
co2_val = str(int(in_data["co2"]))
pos = len(co2_val) - 1
sfasamento = 10 * pos
sfasamento_power = 10
power_unit = "W"
power_kw = -1
if prev_data_from_bridge[energy_meter_data_topic]["data"]:
try:
power_kw = round(prev_data_from_bridge[energy_meter_data_topic]["data"]["power"], 2)
volts = str(int(prev_data_from_bridge[energy_meter_data_topic]["data"]["voltage"]))
if prev_data_from_bridge[energy_meter_data_topic]["data"]["power"] < 1:
power = str(int(prev_data_from_bridge[energy_meter_data_topic]["data"]["power"] * 1000))
power_unit = "W"
else:
power = f'{power_kw:.2f}'
power_unit = "kW"
sfasamento_power = 0
except:
power = "- - -"
volts = "- - -"
else:
power = "- - -"
volts = "- - -"
if prev_data_from_bridge[weather_out_data_topic]["data"]:
try:
out_temp = round(float(prev_data_from_bridge[weather_out_data_topic]["data"]["temperature"]), 1)
out_temp = f'{out_temp:.1f}'
out_hum = str(int(prev_data_from_bridge[weather_out_data_topic]["data"]["humidity"]))
except:
out_temp = " - - -"
out_hum = "- -"
else:
out_temp = " - - -"
out_hum = "- -"
out_old_data = False
if prev_data_from_bridge[energy_meter_data_topic]["timestamp"] and \
time() - prev_data_from_bridge[energy_meter_data_topic]["timestamp"] > 60 * alert_thereshold:
out_old_data = True
energy_old_data = False
if prev_data_from_bridge[weather_out_data_topic]["timestamp"] and \
time() - prev_data_from_bridge[weather_out_data_topic]["timestamp"] > 60 * alert_thereshold:
energy_old_data = True
# --------- OUT TEMPERATURE AND HUMIDITY ---------
out_line_sep_pos = -1
ssd.line(0, out_line_sep_pos, ssd.width, out_line_sep_pos, 1)
label_out_pos = [out_line_sep_pos + 7, 5]
out_temp_pos = [out_line_sep_pos + 15, ssd.width - 85]
out_hum_pos = [out_temp_pos[0] - 1, ssd.width - 28]
# ssd.text(str(co2_val), 49+sfasamento, v_align_center, 1)
wri = Writer(ssd, font_small, verbose=False)
Label(wri, label_out_pos[0], label_out_pos[1], 'OUT', bdcolor=None)
if out_old_data:
ssd.fill_rect(label_out_pos[1] + 23, label_out_pos[0] - 2, 11, 14, 1)
ssd.fill_rect(label_out_pos[1] + 27, label_out_pos[0], 2, 6, 0)
ssd.fill_rect(label_out_pos[1] + 27, label_out_pos[0] + 8, 2, 2, 0)
Writer.set_textpos(ssd, out_hum_pos[0], out_hum_pos[1])
wri.printstring(out_hum + " %")
Writer.set_textpos(ssd, out_temp_pos[0] + 8, out_temp_pos[1] + 43)
wri.printstring("C")
# gradi
circle(ssd, out_temp_pos[1] + 41, out_temp_pos[0] + 8, 1, 1)
wri = Writer(ssd, font_mid, verbose=False)
Writer.set_textpos(ssd, out_temp_pos[0], out_temp_pos[1])
wri.printstring(out_temp)
# --------- IN TEMPERATURE AND HUMIDITY ---------
in_line_sep_pos = out_line_sep_pos + 43
ssd.line(0, in_line_sep_pos, ssd.width, in_line_sep_pos, 1)
# label_in_pos = [label_out_pos[0]+58, 5]
label_in_pos = [in_line_sep_pos + 6, 5]
in_temp_pos = [label_in_pos[0] + 18, ssd.width - 103]
in_hum_pos = [label_in_pos[0] + 1, ssd.width - 35]
# ssd.text(str(co2_val), 49+sfasamento, v_align_center, 1)
wri = Writer(ssd, font_small, verbose=False)
Label(wri, label_in_pos[0], label_in_pos[1], ' IN ', bdcolor=None)
Writer.set_textpos(ssd, in_hum_pos[0] + 8, in_hum_pos[1] + 22)
wri.printstring("%")
wri = Writer(ssd, font_big, verbose=False)
Writer.set_textpos(ssd, in_temp_pos[0], in_temp_pos[1])
wri.printstring(in_temp_int)
wri = Writer(ssd, font_mid, verbose=False)
Writer.set_textpos(ssd, in_hum_pos[0], in_hum_pos[1])
wri.printstring(in_hum)
Writer.set_textpos(ssd, in_temp_pos[0] + 11, in_temp_pos[1] + 42)
wri.printstring("." + in_temp_float.split(".")[1] + " C")
# gradi
circle(ssd, in_temp_pos[1] + 64, in_temp_pos[0] + 13, 2, 1)
# --------- IN CO2 ---------
co2_rect_pos = [5, in_temp_pos[0] + 38]
co2_rect_height = 105
v_align_co2_center = co2_rect_pos[1] + int(co2_rect_height / 2) - 1
ssd.rect(co2_rect_pos[0], co2_rect_pos[1], ssd.width - (co2_rect_pos[0] * 2), co2_rect_height, 1)
# ssd.line(co2_rect_pos[0], v_align_co2_center, ssd.width-co2_rect_pos[0], v_align_co2_center, 1)
co2_pos = [v_align_co2_center - int(co2_rect_height / 2) + 7, int(ssd.width / 2) - 18]
Writer.set_textpos(ssd, co2_pos[0], co2_pos[1])
wri.printstring("CO")
wri = Writer(ssd, font_small, verbose=False)
Writer.set_textpos(ssd, co2_pos[0] + 10, co2_pos[1] + 30)
wri.printstring("2")
Writer.set_textpos(ssd, v_align_co2_center + 28, int(ssd.width / 2) - 9)
wri.printstring("ppm")
wri = Writer(ssd, font_big, verbose=False)
Writer.set_textpos(ssd, v_align_co2_center - 13, int(ssd.width / 2) - 10 - sfasamento)
wri.printstring(co2_val)
# ssd.line(0, label_in_pos[0]+53, ssd.width, label_in_pos[0]+53, 1)
co2_scale_height = 10
co2_scale_borders = 5
co2_scale_pos = [co2_rect_pos[0], co2_rect_pos[1] + co2_rect_height - co2_scale_height]
co2_scale_width = ssd.width - (co2_rect_pos[0] * 2) - (co2_scale_borders * 2)
ssd.rect(co2_scale_pos[0] + co2_scale_borders, co2_scale_pos[1], co2_scale_width, co2_scale_height, 1)
co2_line_mid = 6 / 10
co2_line_high = 9 / 10
co2_x_scale_width = 0
co2_val = int(co2_val)
if 400 <= co2_val <= 1500:
co2_x_scale = (co2_val - 400) / 1100
co2_x_scale_width = int((co2_scale_width * (co2_line_mid)) * co2_x_scale)
ssd.fill_rect(co2_scale_pos[0] + co2_scale_borders, co2_scale_pos[1] + 3, co2_x_scale_width, co2_scale_height - 6,
1)
else:
co2_x_scale = ((co2_val - 1500) / 1350)
co2_x_scale = 1 - exp(-co2_x_scale)
co2_x_scale_width = int(co2_scale_width * (co2_line_mid)) + int(
(co2_scale_width * (1 - co2_line_mid)) * co2_x_scale)
ssd.fill_rect(co2_scale_pos[0] + co2_scale_borders, co2_scale_pos[1] + 3, co2_x_scale_width, co2_scale_height - 6,
1)
co2_scale_perc = co2_x_scale_width / co2_scale_width
if co2_scale_perc < co2_line_mid:
sep_co2_line_mid = co2_scale_height - 8
sep_co2_line_high = co2_scale_height - 6
sep_co2_line_mid_z = - 4
sep_co2_line_high_z = - 3
elif co2_line_mid <= co2_scale_perc < co2_line_high:
sep_co2_line_mid = co2_scale_height - 4
sep_co2_line_high = co2_scale_height - 6
sep_co2_line_mid_z = - 2
sep_co2_line_high_z = - 3
elif co2_scale_perc >= co2_line_high:
sep_co2_line_mid = co2_scale_height - 4
sep_co2_line_high = sep_co2_line_mid
sep_co2_line_mid_z = - 2
sep_co2_line_high_z = - 2
ssd.fill_rect(co2_rect_pos[0] + co2_scale_borders + int(co2_scale_width * (co2_line_mid)),
co2_rect_pos[1] + co2_rect_height - sep_co2_line_mid + sep_co2_line_mid_z, 1, sep_co2_line_mid, 1)
ssd.fill_rect(co2_rect_pos[0] + co2_scale_borders + int(co2_scale_width * (co2_line_high)),
co2_rect_pos[1] + co2_rect_height - sep_co2_line_high + sep_co2_line_high_z, 1, sep_co2_line_high, 1)
# --------- ENERGY METER ---------
energy_line_sep_pos = co2_scale_pos[1] + co2_scale_height + 12
ssd.line(0, energy_line_sep_pos, ssd.width, energy_line_sep_pos, 1)
label_energy_pos = [energy_line_sep_pos + 7, 5]
power_pos = [label_energy_pos[0] + 22, co2_rect_pos[0] + 6]
volts_pos = [label_energy_pos[0], ssd.width - 48]
# ssd.text(str(co2_val), 49+sfasamento, v_align_center, 1)
wri = Writer(ssd, font_small, verbose=False)
Label(wri, label_energy_pos[0], label_energy_pos[1], 'Energy', bdcolor=None)
if energy_old_data:
ssd.fill_rect(label_energy_pos[1] + 36, label_energy_pos[0] - 2, 11, 14, 1)
ssd.fill_rect(label_energy_pos[1] + 40, label_energy_pos[0], 2, 6, 0)
ssd.fill_rect(label_energy_pos[1] + 40, label_energy_pos[0] + 8, 2, 2, 0)
Writer.set_textpos(ssd, volts_pos[0] + 8, volts_pos[1] + 35)
wri.printstring("V")
wri = Writer(ssd, font_big, verbose=False)
Writer.set_textpos(ssd, power_pos[0], power_pos[1] + sfasamento_power)
wri.printstring(power)
wri = Writer(ssd, font_mid, verbose=False)
Writer.set_textpos(ssd, volts_pos[0], volts_pos[1])
wri.printstring(volts)
Writer.set_textpos(ssd, power_pos[0] + 11, power_pos[1] + 75)
wri.printstring(power_unit)
# power slider
energy_scale_height = 9
energy_scale_borders = 5
energy_scale_pos = [co2_rect_pos[0], ssd.height - energy_scale_height]
energy_scale_width = co2_scale_width
# energy_scale_width = ssd.width - (energy_scale_borders*2)
ssd.rect(energy_scale_pos[0] + energy_scale_borders, energy_scale_pos[1], energy_scale_width, energy_scale_height, 1)
if power_kw != -1:
if power_kw >= 7.7:
enery_x_scale = 1
else:
enery_x_scale = power_kw / 7.7
enery_x_scale_width = int(energy_scale_width * enery_x_scale)
ssd.fill_rect(energy_scale_pos[0] + co2_scale_borders, energy_scale_pos[1] + 3, enery_x_scale_width,
energy_scale_height - 6, 1)
# ssd.line(int(ssd.width/2), 0, int(ssd.width/2), ssd.height, 1)
# ssd.line(0, int(ssd.height/2), ssd.width, int(ssd.height/2), 1)
ssd.rect(0, 0, ssd.width, ssd.height, 1)
ssd.show()

Wyświetl plik

@ -0,0 +1,22 @@
# WIRING
# 15 BUSY
# 4 DC
# 2 Rst
# 5 CS
# 23 SDA
# 18 SCL
from machine import Pin, SPI
import gc
# *** Choose your color display driver here ***
from drivers.ssd1680.epd29_ssd1680 import EPD as SSD
dc = Pin(4, Pin.OUT, value=0)
rst_pin = 2
cs = Pin(5, Pin.OUT, value=1)
busy = Pin(15, Pin.IN)
spi = SPI(1, baudrate=10000000, sck=Pin(18), mosi=Pin(23))
gc.collect() # Precaution before instantiating framebuf
ssd = SSD(spi, cs, dc, rst_pin, busy, landscape=True)