실내 미세먼지의 관리 여부와 외부 마스크 착용 여부에 따라 '코'나 '목'의 (콧물, 가래나 불편함)상태가 바뀌는 것을 체감한 후부터는 항상 실내 이산화탄소와 미세먼지 수치를 관리하고 있습니다. 특히 실내 초미세와 미세먼지 수치는 5㎍/㎥ 미만으로 365일 24시간 관리하고 있습니다.
거실에 놓아둔 라즈베리파이 7인치 모니터로 Home Assistant가 표시되는 부모님 댁과 달리, 저는 컴퓨터나 스마트폰으로만 확인이 가능했는데, 잉여로 남아 돌던 e-ink 2.7인치에 표시해 보았습니다.
간단하지만 좋네요.
[사용 장치]
- 2.7인치 e-ink 디스플레이 : 원래 RPi용 HAT에 붙어 있던 것을 떼어 내어 이용(제품 설명)
- Waveshare e-Paper ESP8266 Driver Board(제품 설명)
[ESPHome 코드]
Home Assistant에 HACS를 통해 설치한 네이버 날씨 정보에서 외부 초미세먼지를 가져오고, ESP8266보드 기반 DIY로 만든 미세먼지센서(SDS021)와 이산화탄소센서(MH-Z19B)는 ESPHome을 통해 Home Assitant로 연결되어 있습니다.
ESP8266 Driver Board에 올린 ESPHome .YAML 파일 내용은 다음과 같습니다.
esphome:
name: epaper8266
esp8266:
board: nodemcu
# Enable logging
logger:
# Enable Home Assistant API
api:
password: ""
ota:
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.177
# 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
captive_portal:
time:
- platform: homeassistant
id: ntp
# Example configuration entry
font:
- file: "fonts/verdana.ttf"
id: font1
size: 36
glyphs: |-
!"%()+=,-_./:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz
spi:
clk_pin: D5
mosi_pin: D7
sensor:
- platform: homeassistant
entity_id: sensor.2_5um
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
id: co2
internal: true
display:
- platform: waveshare_epaper
cs_pin: D8
dc_pin: D2
busy_pin: D1
reset_pin: D4
model: 2.70in
rotation: 270
update_interval: 60s
lambda: |-
// position
#define xRes 264
#define yRes 176
#define pad 10
it.strftime(0 + pad, 0 + pad, id(font1), "%m-%d %H:%M", id(ntp).now());
it.printf(0 + pad, 0 + pad + 36, id(font1), TextAlign::TOP_LEFT, "0PM25: %.0f", id(outdoor_pm25).state);
it.printf(0 + pad, 0 + pad + 36 * 2, id(font1), TextAlign::TOP_LEFT, "IPM25: %.0f", id(indoor_pm25).state);
it.printf(0 + pad, 0 + pad + 36 * 3, id(font1), TextAlign::TOP_LEFT, "CO2: %.0f", id(co2).state);
아래는 7.5인치에 Waveshare ESP32 driver board로 구현한 것입니다. 이케아의 포토프레임에 넣어 보았습니다.
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.0.219
# Set this to the IP address of the router. Often ends with .1
# gateway: 192.168.0.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.pm_2_5mm # 초미세먼지(실내) DIY 센서
id: indoor_pm25
internal: true
- platform: homeassistant
entity_id: sensor.comisemeonji # 초미세먼지
id: outdoor_pm25
internal: true
- platform: homeassistant
entity_id: sensor.mh_z19_co2_value # 이산화탄소 DIY 센서
id: co2
internal: true
- platform: homeassistant
entity_id: sensor.misemeonji # 미세먼지
id: outdoor_pm10
internal: true
- platform: homeassistant
entity_id: sensor.hyeonjaeondo # 현재 온도
id: nowtemp
internal: true
- platform: homeassistant
entity_id: sensor.coegoondo # 오늘 최고 온도
id: todaymaxtemp
internal: true
- platform: homeassistant
entity_id: sensor.naeilcoegoondo # 내일최고온도
id: tomorrowmaxtemp
internal: true
- platform: homeassistant
entity_id: sensor.naeilcoejeoondo # 내일최저온도
id: tomorrowmintemp
internal: true
text_sensor:
- platform: homeassistant
entity_id: sensor.hyeonjaenalssi # 현재 날씨
id: nowweather
internal: true
- platform: homeassistant
entity_id: sensor.naeilojeonnalssi # 내일오전날씨
id: tomorrowweather1
internal: true
- platform: homeassistant
entity_id: sensor.naeilohunalssi # 내일오후날씨
id: tomorrowweather2
internal: true
- platform: homeassistant
entity_id: sensor.bisijagsiganoneul # 오늘 비시작 시간
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 # -bwr #7.50in-bv3
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 + 350, 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 + 350, 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 + 350, 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 + 350, 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,"✽✽ 잠시만 기다리세요... ✽✽");
}
에스홈: 이름: epaper8266 esp8266: 보드: nodemcu # 로깅 활성화 나무꾼: # 홈어시스턴트 API 활성화 API: 비밀번호: "" 오타: 비밀번호: "" 와이파이: ssid: !비밀 ssid 비밀번호: !비밀 비밀번호 도메인: !secret 도메인 manual_ip: # 이를 ESP의 IP로 설정합니다. 정적_IP: 192.168.1.177 # 라우터의 IP 주소로 설정합니다. 종종 .1로 끝납니다. 게이트웨이: 192.168.1.1 # 네트워크의 서브넷입니다. 255.255.255.0은 대부분의 홈 네트워크에서 작동합니다. 서브넷: 255.255.255.0 captive_portal: 시간: - 플랫폼: 홈어시스턴트 아이디 : ntp # 구성 항목 예시 세례반: - 파일: "fonts/verdana.ttf" ID: 글꼴1 사이즈: 36 글리프: |- !"%()+=,-_./:°0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz 스파이: clk_핀: D5 mosi_pin: D7 감지기: - 플랫폼: 홈어시스턴트 엔터티_ID: 센서.2_5um 아이디: Indoor_pm25 내부: 사실 - 플랫폼: 홈어시스턴트 엔터티_ID : 센서.naver_weather_ultrafinedust_1 아이디: Outdoor_pm25 내부: 사실 - 플랫폼: 홈어시스턴트 엔터티_ID: 센서.mh_z19_co2_value 아이디: co2 내부: 사실 표시하다: - 플랫폼: waveshare_epaper cs_핀: D8 dc_핀: D2 바쁜_핀: D1 재설정_핀: D4 모델: 2.70인치 회전: 270 업데이트 간격: 60초 람다: |- // 위치 #xRes 264 정의 #yRes 정의 176 #패드 10 정의 it.strftime(0 + 패드, 0 + 패드, id(font1), "%m-%d %H:%M", id(ntp).now()); it.printf(0 + 패드, 0 + 패드 + 36, id(font1), TextAlign::TOP_LEFT, "0PM25: %.0f", id(outdoor_pm25).state); it.printf(0 + 패드, 0 + 패드 + 36 * 2, id(font1), TextAlign::TOP_LEFT, "IPM25: %.0f", id(indoor_pm25).state); it.printf(0 + 패드, 0 + 패드 + 36 * 3, id(font1), TextAlign::TOP_LEFT, "CO2: %.0f", id(co2).state);
'홈어시스턴트 IoT' 카테고리의 다른 글
드리미 L10s Ultra 물걸레 로봇 청소기 홈어시스턴트 연결 (0) | 2023.08.25 |
---|---|
지그비 리모트 4버튼 스위치 - 홈어시스턴트와 Sonoff 지그비 동글 (0) | 2023.08.22 |
8x8 적외선 온도계 GY-MCU8833의 ESPHome 커스텀 센서 연동 (0) | 2023.07.23 |
구형에어컨 제습운전 자동화 홈어시스턴트 ESPHome DIY 적외선리모콘 (0) | 2023.07.22 |
가정 내 소비전력 모니터링 - 시하스 PMM-300-Z 지그비 (0) | 2023.07.05 |