Here yah go - note that I use the esp-idf framework, as it allows me to use the built-in pull up/down resistors via a config line, rather than having to wire up any actual resistors.
I’ve also included my crude code for outputting the values to the screen, which includes the weirdness that the colours are off somehow 🤷♂️, so I’ve worked out how to get the colours I wanted and that’s in there.
esphome:
name: env0
esp32:
board: az-delivery-devkit-v4
# framework:
# type: arduino
framework:
type: esp-idf
version: recommended
# Enable Home Assistant API
api:
encryption:
key: ""
ota:
password: ""
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Fallback Hotspot"
password: ""
domain: ""
#captive_portal:
i2c:
sda: GPIO21
scl: GPIO22
scan: true
scl_pullup_enabled: True
sda_pullup_enabled: True
spi:
clk_pin: GPIO18
mosi_pin: GPIO23 # MasterOutSlaveIn - data sent from ESP32 to LCD
#miso_pin: .. # screen doesn't return data, so DOUT/MasterInSlaveOut isn't required
uart:
rx_pin: GPIO16
tx_pin: GPIO17
baud_rate: 9600
sensor:
# https://esphome.io/cookbook/bme280_environment.html
- platform: bme280
temperature:
name: "BME280 Temperature"
id: bme280_temperature
pressure:
name: "BME280 Pressure"
id: bme280_pressure
humidity:
name: "BME280 Relative Humidity"
id: bme280_humidity
address: 0x76
update_interval: 60s
- platform: pmsx003
type: PMSX003
pm_1_0:
name: "Particulate Matter <1.0µm Concentration"
id: pms5003_1um
pm_2_5:
name: "Particulate Matter <2.5µm Concentration"
id: pms5003_2dot5um
pm_10_0:
name: "Particulate Matter <10.0µm Concentration"
id: pms5003_10um
update_interval: 60000ms
font:
# gfonts://family[@weight]
- file: "gfonts://Roboto@light"
id: roboto20
size: 20
- file: "gfonts://Roboto@light"
id: roboto30
size: 30
- file: "gfonts://Roboto@light"
id: roboto40
size: 40
color:
- id: graph_red
red: 100%
green: 0%
blue: 0%
- id: graph_green
red: 0%
green: 100%
blue: 0%
- id: graph_blue
red: 0%
green: 0%
blue: 100%
- id: white
red: 100%
green: 100%
blue: 100%
- id: colour_text_gray
red: 60%
green: 60%
blue: 60%
- id: colour_text_red
red: 17% # red and blue swapped
green: 25%
blue: 82%
white: 0%
- id: colour_text_blue
red: 82% # red and blue swapped
green: 38%
blue: 0%
white: 0%
# graph:
# - id: particulates_simple_graph
# sensor: pms5003_10um
# duration: 8h
# width: 150
# height: 50
# - id: particulates_graph
# duration: 8h
# x_grid: 1h
# y_grid: 1.0 # degC/div
# width: 150
# height: 60
# traces:
# - sensor: pms5003_1um
# line_type: DOTTED
# line_thickness: 2
# color: graph_green
# - sensor: pms5003_2dot5um
# line_type: DASHED
# line_thickness: 2
# color: graph_red
# - sensor: pms5003_10um
# line_type: SOLID
# line_thickness: 2
# color: graph_blue
display:
#https://esphome.io/components/display/st7735.html
- platform: st7735
model: "INITR_MINI160X80"
cs_pin: GPIO5
dc_pin: GPIO19
device_width: 80
device_height: 160
rotation: 90
col_start: 26
row_start: 1
eight_bit_color: true
invert_colors: true
update_interval: 30s
lambda: |-
auto red = Color(255, 0, 0);
auto green = Color(0, 255, 0);
auto blue = Color(0, 0, 255);
auto white = Color(255, 255, 255);
auto black = Color(0, 0, 0);
auto black_fucked_inverted = Color(255, 255, 255);
auto white_fucked_inverted = Color(0, 0, 0);
// R and B colours swapped - because fuck knows??
auto colour_eu_aqi_good = Color(230, 240, 80);
auto colour_eu_aqi_fair = Color(170, 204, 80);
auto colour_eu_aqi_moderate = Color(65, 230, 240);
auto colour_eu_aqi_poor = Color(80, 80, 255);
auto colour_eu_aqi_vpoor = Color(50, 0, 150);
auto colour_eu_aqi_expoor = Color(129, 33, 125);
auto twodotfiveum_colour_text = colour_eu_aqi_good;
auto tenum_colour_text = colour_eu_aqi_good;
//it.fill(black_fucked_inverted);
it.fill(black);
//it.graph(5, 20, id(particulates_simple_graph));
//it.rectangle(0, 0, 30, 30, red);
//it.rectangle(10, 10, 30, 30, green);
//it.rectangle(20, 20, 30, 30, blue);
//it.rectangle(5, 5, 30, 30, white);
// Syntax is always: it.print(<x>, <y>, <font>, [color=COLOR_ON], [align=TextAlign::TOP_LEFT], <text>)
//it.print(0, 30, id(roboto20), white, TextAlign::TOP_LEFT, "Hello World!");
it.printf(0, 0, id(roboto40), colour_text_red, TextAlign::TOP_LEFT, "%2.1f", id(bme280_temperature).state);
it.printf(160, 0, id(roboto40), colour_text_blue, TextAlign::TOP_RIGHT, "%2.0f%%", id(bme280_humidity).state);
if ( !isnan( id(pms5003_1um).state ) ) {
it.printf(0, 40, id(roboto30), colour_text_gray, TextAlign::TOP_LEFT, "%2.0f", id(pms5003_1um).state);
if ( id(pms5003_2dot5um).state > 25 ) {
twodotfiveum_colour_text = colour_eu_aqi_poor;
} else if ( id(pms5003_2dot5um).state > 20 ) {
twodotfiveum_colour_text = colour_eu_aqi_moderate;
} else if ( id(pms5003_2dot5um).state > 10 ) {
twodotfiveum_colour_text = colour_eu_aqi_fair;
}
it.printf(100, 40, id(roboto30), twodotfiveum_colour_text, TextAlign::TOP_RIGHT, "%2.0f", id(pms5003_2dot5um).state);
if ( id(pms5003_10um).state > 50 ) {
tenum_colour_text = colour_eu_aqi_poor;
} else if ( id(pms5003_10um).state > 40 ) {
tenum_colour_text = colour_eu_aqi_moderate;
} else if ( id(pms5003_10um).state > 20 ) {
tenum_colour_text = colour_eu_aqi_fair;
}
it.printf(160, 40, id(roboto30), tenum_colour_text, TextAlign::TOP_RIGHT, "%2.0f", id(pms5003_10um).state);
}
switch:
- platform: gpio
pin: GPIO32
name: "LCD Backlight"
id: backlight