7인치 라즈베리파이 모니터도 있기는 하지만, 벽에 매달아 놓아서 늘 참고할 수 있도록 만들어 보았습니다.
이케아 RIBBA 액자 13x18 안에 Waveshare 7.5inch E-Paper (B) Raw Display SPI without PCB와 Waveshare E-Paper ESP32 Driver Board 제품을 넣어서 만들었습니다.
원래는 아래 링크를 보고 시작했습니다.
Waveshare의 E-Paper ESP8266 Driver Board는 메모리 부족으로 작동이 안되어서 ESP32로 새로 구입해서 작동시켰습니다. E-Paper는 V3가 맞지만, 빨간색 표현은 ESPHome에서 지원이 아직 안되더군요.
전체적인 정보는 Home Assistant의 네이버 날씨(HACS를 통해 제공)를 바탕으로 하고, 실내 미세먼지와 이산화탄소 값은 PMS7003과 MH-Z19B 센서를 DIY로 만든 ESPHome장치를 Home Assistant와 연결하여 받고 있습니다.
ESPHome을 위해 작성한 esp32-eink75.yaml 파일은 다음과 같습니다. 나중에 좀 더 예쁘게 수정해 보겠습니다.
esphome:
name: esp32-eink75
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
password: ""
ota:
platform: esphome
password: ""
wifi:
ssid: !secret ssid
password: !secret password
# domain: !secret domain
manual_ip:
# Set this to the IP of the ESP
static_ip: 192.168.1.219
# Set this to the IP address of the router. Often ends with .1
gateway: 192.168.1.1
# The subnet of the network. 255.255.255.0 works for most home networks.
subnet: 255.255.255.0
ap:
ssid: "Esp32-Eink75 Fallback Hotspot"
password: "vzdz2ed5KqFN"
captive_portal:
time:
- platform: homeassistant
id: ntp
# ttf files are required
font:
- file: "NanumBarunGothic-YetHangul.ttf"
id: font1
size: 32
glyphs: |-
!"%()+=,-_./:°℃℉✽㎍[]0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz초미세먼지외부내이산화탄소
현재날씨정보온도오늘일최고저풍속강수확률습구름많음비안옴흐림눈나기시월분작후맑전잠만다리요실공질예가끔황
- file: "materialdesignicons-webfont.ttf"
id: mdi
size: 40
glyphs:
- "\U000F0590" # mdi-weather-cloudy
- "\U000F0F2F" # mdi-weather-cloudy-alert
- "\U000F0E6E" # mdi-weather-cloudy-arrow-right
- "\U000F0591" # mdi-weather-fog
- "\U000F0592" # mdi-weather-hail
- "\U000F0F30" # mdi-weather-hazy
- "\U000F0898" # mdi-weather-hurricane
- "\U000F0593" # mdi-weather-lightning
- "\U000F067E" # mdi-weather-lightning-rainy
- "\U000F0594" # mdi-weather-night
- "\U000F0F31" # mdi-weather-night-partly-cloudy
- "\U000F0595" # mdi-weather-partly-cloudy
- "\U000F0F32" # mdi-weather-partly-lightning
- "\U000F0F33" # mdi-weather-partly-rainy
- "\U000F0F34" # mdi-weather-partly-snowy
- "\U000F0F35" # mdi-weather-partly-snowy-rainy
- "\U000F0596" # mdi-weather-pouring
- "\U000F0597" # mdi-weather-rainy
- "\U000F0598" # mdi-weather-snowy
- "\U000F0F36" # mdi-weather-snowy-heavy
- "\U000F067F" # mdi-weather-snowy-rainy
- "\U000F0599" # mdi-weather-sunny
- "\U000F0F37" # mdi-weather-sunny-alert
- "\U000F14E4" # mdi-weather-sunny-off
- "\U000F059A" # mdi-weather-sunset
- "\U000F059B" # mdi-weather-sunset-down
- "\U000F059C" # mdi-weather-sunset-up
- "\U000F0F38" # mdi-weather-tornado
- "\U000F059D" # mdi-weather-windy
- "\U000F059E" # mdi-weather-windy-variant
- "\U000F17FF" # mdi-sun-wireless-outline
- "\U000F018C" # mdi-compass-outline
- "\U000F0D43" # mdi-air-filter
- "\U000F0D44" # mdi-air-purifier
- "\U000F1586" # mdi-face-mask
- "\U000F1587" # mdi-face-mask-outline
- "\U000F11DC" # mdi-window-open-variant
- "\U000F13E1" # mdi-umbrella-closed-outline
# Your sensor values of target Home Assistant
sensor:
- platform: homeassistant
entity_id: sensor.2_5um # 초미세먼지(실내) DIY 센서
id: indoor_pm25
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_ultrafinedust_1 # 초미세먼지
id: outdoor_pm25
internal: true
- platform: homeassistant
entity_id: sensor.mh_z19_co2_value # 이산화탄소 DIY 센서
id: co2
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_finedust_1 # 미세먼지
id: outdoor_pm10
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_nowtemp_1 # 현재 온도
id: nowtemp
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_todaymaxtemp_1 # 오늘 최고 온도
id: todaymaxtemp
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_tomorrowatemp_1 # 내일최고온도
id: tomorrowmaxtemp
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_tomorrowmtemp_1 # 내일최저온도
id: tomorrowmintemp
internal: true
text_sensor:
- platform: homeassistant
entity_id: sensor.naver_weather_nowweather_1 # 현재 날씨
id: nowweather
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_tomorrowmstate_1 # 내일오전날씨
id: tomorrowweather1
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_tomorrowastate_1 # 내일오후날씨
id: tomorrowweather2
internal: true
- platform: homeassistant
entity_id: sensor.naver_weather_rainystart_1 # 오늘 비시작 시간
id: todayraintime
internal: true
color:
- id: color_black
red: 0%
green: 0%
blue: 0%
white: 0%
- id: color_white
red: 0%
green: 0%
blue: 0%
white: 100%
- id: color_red
red: 100%
green: 0%
blue: 0%
white: 0%
spi:
clk_pin: GPIO13
mosi_pin: GPIO14
display:
- platform: waveshare_epaper
cs_pin: GPIO15
dc_pin: GPIO27
busy_pin: GPIO25
reset_pin: GPIO26
model: 7.50in-bv3 # 7.50in-bv3-bwr
rotation: 270
update_interval: 60s
lambda: |-
// https://github.com/Nerdiyde/ESPHomeSnippets
// Map weather states to MDI characters.
std::map<std::string, std::string> weather_icon_map
{
{"구름많음", "\U000F0590"},
{"안개", "\U000F0591"},
{"흐림", "\U000F0595"},
{"가끔비", "\U000F0F33"},
{"가끔눈", "\U000F0F34"},
{"가끔비눈", "\U000F0F35"},
{"폭우", "\U000F0596"},
{"비", "\U000F0597"},
{"눈", "\U000F0598"},
{"폭설", "\U000F0F36"},
{"비눈", "\U000F067F"},
{"맑음", "\U000F0599"},
};
std::map<std::string, std::string> etc_icon_map
{
{"airfilter", "\U000F0D43"},
{"airpurifier", "\U000F0D44"},
{"facemask", "\U000F1586"},
{"facemask_outline", "\U000F1587"},
{"window_open_variant", "\U000F11DC"},
{"umbrella_closed_outline", "\U000F13E1"},
};
// position
#define padx 24
#define pady 72
if(id(nowweather).state != "") {
it.strftime(padx, pady, id(font1), " %Y-%m-%d %a %H: %M", id(ntp).now());
it.printf(padx, pady + 36 * 2, id(font1), TextAlign::TOP_LEFT, "[ 외부 ]");
it.printf(padx, pady + 36 * 3, id(font1), TextAlign::TOP_LEFT, "✽ 미세먼지: %.0f㎍", id(outdoor_pm10).state);
if(id(outdoor_pm10).state > 15) {
it.printf(padx + 310, pady + 36 * 3, id(mdi), TextAlign::TOP_LEFT, "%s", etc_icon_map["facemask_outline"].c_str());
}
it.printf(padx, pady + 36 * 4, id(font1), TextAlign::TOP_LEFT, "✽ 초미세먼지: %.0f㎍", id(outdoor_pm25).state);
if(id(outdoor_pm25).state > 10) {
it.printf(padx + 310, pady + 36 * 4, id(mdi), TextAlign::TOP_LEFT, "%s", etc_icon_map["facemask_outline"].c_str());
}
it.printf(padx, pady + 36 * 5, id(font1), TextAlign::TOP_LEFT, "[ 실내 ]");
it.printf(padx, pady + 36 * 6, id(font1), TextAlign::TOP_LEFT, "✽ 초미세먼지: %.0f㎍", id(indoor_pm25).state);
if(id(indoor_pm25).state > 5) {
it.printf(padx + 350, pady + 36 * 6, id(mdi), TextAlign::TOP_LEFT, "%s", etc_icon_map["airfilter"].c_str());
}
it.printf(padx, pady + 36 * 7, id(font1), TextAlign::TOP_LEFT, "✽ 이산화탄소: %.0fppm", id(co2).state);
if(id(co2).state > 800) {
it.printf(padx + 350, pady + 36 * 7, id(mdi), TextAlign::TOP_LEFT, "%s", etc_icon_map["window_open_variant"].c_str());
}
it.printf(padx, pady + 36 * 8, id(font1), TextAlign::TOP_LEFT, "[ 오늘 ]");
it.printf(padx, pady + 36 * 9, id(font1), TextAlign::TOP_LEFT, "✽ 현재 날씨: %s", id(nowweather).state.c_str());
it.printf(padx + 240, pady + 36 * 9, id(mdi), color_red, TextAlign::TOP_LEFT, "%s", weather_icon_map[id(nowweather).state.c_str()].c_str());
it.printf(padx, pady + 36 * 10, id(font1), TextAlign::TOP_LEFT, "✽ 현재 온도: %.0f℃", id(nowtemp).state);
it.printf(padx, pady + 36 * 11, id(font1), TextAlign::TOP_LEFT, "✽ 최고 온도: %.0f℃", id(todaymaxtemp).state);
it.printf(padx, pady + 36 * 12, id(font1), TextAlign::TOP_LEFT, "✽ 비 시작: %s", id(todayraintime).state.c_str());
if(strcmp(id(todayraintime).state.c_str(), "비안옴") != 0) {
it.printf(padx + 240, pady + 36 * 12, id(mdi), TextAlign::TOP_LEFT, "%s", etc_icon_map["umbrella_closed_outline"].c_str());
}
it.printf(padx, pady + 36 * 13, id(font1), TextAlign::TOP_LEFT, "[ 내일 ]");
it.printf(padx, pady + 36 * 14, id(font1), TextAlign::TOP_LEFT, "✽ 오전 날씨: %s", id(tomorrowweather1).state.c_str());
it.printf(padx, pady + 36 * 15, id(font1), TextAlign::TOP_LEFT, "✽ 오후 날씨: %s", id(tomorrowweather2).state.c_str());
it.printf(padx, pady + 36 * 16, id(font1), TextAlign::TOP_LEFT, "✽ 최고 온도: %.0f℃", id(tomorrowmaxtemp).state);
it.printf(padx, pady + 36 * 17, id(font1), TextAlign::TOP_LEFT, "✽ 최저 온도: %.0f℃", id(tomorrowmintemp).state);
} else {
it.printf(padx, pady + 36 * 8, id(font1), TextAlign::TOP_LEFT,"✽✽ 잠시만 기다리세요... ✽✽");
}
아이콘이 모두 표시된 모습은 다음과 같습니다.
'DIY' 카테고리의 다른 글
FIREBAT T8 Pro Plus 분해 및 써멀 재도포 (0) | 2024.07.06 |
---|---|
벨츠에너지 태양광 인버터 RS-485 무선 Elfin EW11 이용 Home Assistant 연결 (0) | 2024.06.16 |
PETOI 구형 자동급식기 IoT(Home Assistant)가 되도록 개조 (1) | 2023.12.02 |
ASUS 공유기 방열팬 부착 후 CPU온도 85도에서 69도로 하강 (0) | 2023.10.20 |
근접 자동 열림 급식기 - auto pet feeder, ESPHome, Home Assistant, DIY (2) | 2023.10.11 |