kopia lustrzana https://github.com/peterhinch/micropython-nano-gui
Added driver, demo and setup-example for the WeAct Studio 2.9in EPD display with the SSD1680 driver
rodzic
aef423a536
commit
c9fbe2a995
55
DISPLAYS.md
55
DISPLAYS.md
|
@ -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
|
||||
|
||||
|
|
14
DRIVERS.md
14
DRIVERS.md
|
@ -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
|
||||
|
|
|
@ -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')
|
|
@ -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()
|
|
@ -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)
|
Ładowanie…
Reference in New Issue