전자잉크 날씨 알리미 만들기 (e-ink ESL)
냉장고에 부착한 날씨 알리미들
아래쪽에 위치한 전자잉크 표시기는 마트에서 가격표로 사용하는 ESL(전자 가격 표시기) 인데 홈어시스턴트에서 날씨정보를 보내서 사용하고 있습니다.
준비물
- Gicisky 4.2인치 bluetooth ESL tag (4~5만원)
- ESP32-S3 N16R8 보드 (1만원)
- USB C 케이블과 연결할 컴퓨터
- Home Assistant
- 무선 홈 네트워크 (공유기)
- USB 충전기와 케이블
- 양면테이프 또는 자석
BLE ESL용 AP 만들기
ESP32-S3 보드를 PC 에 연결하고 아래 펌웨어 설치 페이지에서 BLE only AP 를 선택하고 설치합니다.
브라우저에서 시리얼 포트로 바로 연결하고 펌웨어 설치 진행. 문제가 생길 경우 장치관리자 등에서 ESP32 시리얼 포트를 확인해야 합니다.
설치 완료 후 ESP32가 받은 IP로 접근해보면 아래와 같은 화면 확인 가능합니다.
몇분동안 기다리면 ESL tag 가 인식되고 기본 컨텐츠 적용할 수 있습니다.
기타 설정이나 AP 펌웨어 OTA 업그레이드 기능 등등이 있으니 사용해보면 됩니다.
홈어시스턴트에 OpenEPaperLink 설치
홈어시스턴트 HACS 에서 OPenEPaperLink 찾아서 설치하면 됩니다.
설명 및 소스코드는 아래 링크 있습니다. 설치/재부팅 후 통합구성요소에 추가 해주면 됩니다.
https://github.com/OpenEPaperLink/Home_Assistant_Integration
날씨 정보 만들기
날씨 정보 표시하기
다른 사용자가 만든 코드를 참조해서 수정해서 사용중입니다.
원본은 아래 링크에 있습니다.
https://github.com/chunkysteveo/OpenEPaperLink-HA-Weatherman
저는 아래와 같이 수정해서 사용중입니다.
기본적으로 날씨는 담다날씨에서 가져오고, 풍향 풍속은 met 에서가져오고 이런식으로 짬뽕되어 있습니다.
이부분이 좀 귀찮은데 개인화가 필요한거라 한번 노가다 하는 방법밖에 없습니다.
표시하고 싶은 시간대, 간격, 날짜, 표기법, 풍향풍속 유무, 기타 문자열 표기 등등..
그리고 짧은 날씨 정보를 문자로 표시했는데 이건 다른 센서로 기상청 데이터 긁어온거라 생략하겠습니다.
( sensor.today_home_weather 와 sensor.today_weather_txt 항목 )
자동화 편집 시 yaml 모드로 할것 (변수가 있어서...)
위 github 에서 큰 변경점으로는 target 에 device_id 를 넣어줘야 합니다.
개발자 도구에서 OpenEPaperLink: Draw Custom Image 선택 -> 기기 에서 ESL 태그 선택 -> YAML 로 변경 해서 확인하면 됩니다.
target:
device_id: bbb79065b21976e867755ad10f1e8b6f
자동화 yaml
alias: EPaper Tags - 날씨 전자잉크 eink Data - 4.2
description: Created by @svenove, based on @chunkysteveo's Weatherman
triggers:
- minutes: "11"
trigger: time_pattern
conditions:
- condition: time
after: "05:00:00"
before: "23:00:00"
actions:
- data:
background: white
rotate: 0
dry-run: false
payload:
- type: icon
value: "{{ state_attr('sensor.weatherman_data_tag','moon_phase') | string }}"
x: 5
"y": 3
size: 24
color: black
- type: icon
value: blur
x: 8
"y": 124
size: 18
color: black
- type: text
value: "{{ states('sensor.today_weather_txt') }}"
font: ../../media/NotoSans-Bold.ttf
x: 8
"y": 278
size: 17
color: "{{'black'}}"
- type: text
value: "{{ states('sensor.today_home_weather') }}"
font: ../../media/NotoSans-Bold.ttf
x: 88
"y": 257
size: 17
color: "{{'black'}}"
- type: text
value: "{{ states('sensor.wn_seongseongdong_cai')| string }} "
font: ../../media/GothamRnd-Bold.ttf
x: 50
"y": 125
size: 18
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_0') | round }}{{
state_attr('sensor.weatherman_data_tag','temperature_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 140
"y": 80
size: 24
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_0') |
round > severe_temp_low else 'red' }}
anchor: mt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_0') |
string }}
x: 116
"y": 25
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_0') in
severe_weather else 'black' }}
- type: text
value: >-
{{ '' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_0') == 0
else state_attr('sensor.weatherman_data_tag','wm_precipitation_0') |
string + ' ' +
state_attr('sensor.weatherman_data_tag','precipitation_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 140
"y": 105
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_0') | int
< severe_precipitation_hour else 'red' }}
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_wind_speed_0') |
round }}
font: ../../media/GothamRnd-Bold.ttf
x: 130
"y": 125
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_wind_speed_0') | int <
severe_wind_speed else 'red' }}
anchor: mt
- type: icon
value: >-
{{ "%s" %
(["arrow-down","arrow-bottom-left","arrow-left","arrow-top-left","arrow-up","arrow-top-right","arrow-right",
"arrow-bottom-right","arrow-down"][(state_attr('sensor.weatherman_data_tag','wm_wind_dir_0')/45)
| round ]) }}
x: 140
"y": 122
size: 20
color: black
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_1') | string
}}{{ state_attr('sensor.weatherman_data_tag','temperature_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 216
"y": 80
size: 24
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_1') |
int > severe_temp_low else 'red' }}
anchor: mt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_1') |
string }}
x: 192
"y": 25
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_1') in
severe_weather else 'black' }}
- type: text
value: >-
{{ '' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_1') == 0
else state_attr('sensor.weatherman_data_tag','wm_precipitation_1') |
string + ' ' +
state_attr('sensor.weatherman_data_tag','precipitation_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 216
"y": 105
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_1') | int
< severe_precipitation_hour else 'red' }}
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_wind_speed_1') |
round }}
font: ../../media/GothamRnd-Bold.ttf
x: 206
"y": 125
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_wind_speed_1') | int <
severe_wind_speed else 'red' }}
anchor: mt
- type: icon
value: >-
{{ "%s" %
(["arrow-down","arrow-bottom-left","arrow-left","arrow-top-left","arrow-up","arrow-top-right","arrow-right",
"arrow-bottom-right","arrow-down"][(state_attr('sensor.weatherman_data_tag','wm_wind_dir_1')/45)
| round ]) }}
x: 216
"y": 122
size: 20
color: black
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_2') | string
}}{{ state_attr('sensor.weatherman_data_tag','temperature_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 292
"y": 80
size: 24
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_2') |
int > severe_temp_low else 'red' }}
anchor: mt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_2') |
string }}
x: 268
"y": 25
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_2') in
severe_weather else 'black' }}
- type: text
value: >-
{{ '' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_2') == 0
else state_attr('sensor.weatherman_data_tag','wm_precipitation_2') |
string + ' ' +
state_attr('sensor.weatherman_data_tag','precipitation_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 292
"y": 105
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_2') | int
< severe_precipitation_hour else 'red' }}
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_wind_speed_2') |
round }}
font: ../../media/GothamRnd-Bold.ttf
x: 282
"y": 125
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_wind_speed_2') | int <
severe_wind_speed else 'red' }}
anchor: mt
- type: icon
value: >-
{{ "%s" %
(["arrow-down","arrow-bottom-left","arrow-left","arrow-top-left","arrow-up","arrow-top-right","arrow-right",
"arrow-bottom-right","arrow-down"][(state_attr('sensor.weatherman_data_tag','wm_wind_dir_2')/45)
| round ]) }}
x: 292
"y": 122
size: 20
color: black
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_3') | string
}}{{ state_attr('sensor.weatherman_data_tag','temperature_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 368
"y": 80
size: 24
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_3') |
int > severe_temp_low else 'red' }}
anchor: mt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_3') |
string }}
x: 344
"y": 25
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_3') in
severe_weather else 'black' }}
- type: text
value: >-
{{ '' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_3') == 0
else state_attr('sensor.weatherman_data_tag','wm_precipitation_3') |
string + ' ' +
state_attr('sensor.weatherman_data_tag','precipitation_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 368
"y": 105
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_3') | int
< severe_precipitation_hour else 'red' }}
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_wind_speed_3') |
round }}
font: ../../media/GothamRnd-Bold.ttf
x: 358
"y": 125
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_wind_speed_3') | int <
severe_wind_speed else 'red' }}
anchor: mt
- type: icon
value: >-
{{ "%s" %
(["arrow-down","arrow-bottom-left","arrow-left","arrow-top-left","arrow-up","arrow-top-right","arrow-right",
"arrow-bottom-right","arrow-down"][(state_attr('sensor.weatherman_data_tag','wm_wind_dir_3')/45)
| round ]) }}
x: 368
"y": 122
size: 20
color: black
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_4_low') | string
}}
font: ../../media/GothamRnd-Bold.ttf
x: 43
"y": 232
size: 20
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_temp_4_low') | int >
severe_temp_low else 'red' }}
anchor: rt
- type: text
value: " | "
font: ../../media/GothamRnd-Bold.ttf
x: 50
"y": 230
size: 20
color: black
anchor: mt
- type: text
value: "{{ state_attr('sensor.weatherman_data_tag','wm_temp_4') | string }} "
font: ../../media/GothamRnd-Bold.ttf
x: 55
"y": 232
size: 20
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_4') |
int > severe_temp_low else 'red' }}
anchor: lt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_4') |
string }}
x: 24
"y": 175
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_4') in
severe_weather else 'black' }}
- type: text
value: >-
{{ '' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_4') == 0
else state_attr('sensor.weatherman_data_tag','wm_precipitation_4') |
string + ' ' +
state_attr('sensor.weatherman_data_tag','precipitation_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 48
"y": 259
size: 17
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_precipitation_4') | int
< severe_precipitation_day else 'red' }}
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_5_low') | string
}}
font: ../../media/GothamRnd-Bold.ttf
x: 143
"y": 232
size: 20
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_temp_5_low') | int >
severe_temp_low else 'red' }}
anchor: rt
- type: text
value: " | "
font: ../../media/GothamRnd-Bold.ttf
x: 150
"y": 230
size: 20
color: black
anchor: mt
- type: text
value: "{{ state_attr('sensor.weatherman_data_tag','wm_temp_5') | string }} "
font: ../../media/GothamRnd-Bold.ttf
x: 155
"y": 232
size: 20
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_5') |
int > severe_temp_low else 'red' }}
anchor: lt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_5') |
string }}
x: 124
"y": 175
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_5') in
severe_weather else 'black' }}
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_6_low') | string
}}
font: ../../media/GothamRnd-Bold.ttf
x: 243
"y": 232
size: 20
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_temp_6_low') | int >
severe_temp_low else 'red' }}
anchor: rt
- type: text
value: " | "
font: ../../media/GothamRnd-Bold.ttf
x: 250
"y": 230
size: 20
color: black
anchor: mt
- type: text
value: "{{ state_attr('sensor.weatherman_data_tag','wm_temp_6') | string }} "
font: ../../media/GothamRnd-Bold.ttf
x: 255
"y": 232
size: 20
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_6') |
int > severe_temp_low else 'red' }}
anchor: lt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_6') |
string }}
x: 224
"y": 175
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_6') in
severe_weather else 'black' }}
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_7_low') | string
}}
font: ../../media/GothamRnd-Bold.ttf
x: 342
"y": 232
size: 20
color: >-
{{'black' if
state_attr('sensor.weatherman_data_tag','wm_temp_7_low') | int >
severe_temp_low else 'red' }}
anchor: rt
- type: text
value: " | "
font: ../../media/GothamRnd-Bold.ttf
x: 350
"y": 230
size: 20
color: black
anchor: mt
- type: text
value: "{{ state_attr('sensor.weatherman_data_tag','wm_temp_7') | string }} "
font: ../../media/GothamRnd-Bold.ttf
x: 355
"y": 232
size: 20
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_7') |
int > severe_temp_low else 'red' }}
anchor: lt
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_7') |
string }}
x: 324
"y": 175
size: 54
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_7') in
severe_weather else 'black' }}
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_0') | string |
upper }}
font: ../../media/GothamRnd-Bold.ttf
x: 140
"y": 5
size: 24
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_1') | string |
upper }}
font: ../../media/GothamRnd-Bold.ttf
x: 216
"y": 5
size: 24
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_2') | string |
upper }}
font: ../../media/GothamRnd-Bold.ttf
x: 292
"y": 5
size: 24
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_3') | string |
upper }}
font: ../../media/GothamRnd-Bold.ttf
x: 368
"y": 5
size: 24
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_4') | string |
upper }}
font: ../../media/NotoSans-Bold.ttf
x: 50
"y": 154
size: 24
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_5') | string |
upper }}
font: ../../media/NotoSans-Bold.ttf
x: 150
"y": 154
size: 24
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_6') | string |
upper }}
font: ../../media/NotoSans-Bold.ttf
x: 250
"y": 154
size: 24
color: black
anchor: mt
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_time_7') | string |
upper }}
font: ../../media/NotoSans-Bold.ttf
x: 350
"y": 154
size: 24
color: black
anchor: mt
- type: line
fill: black
width: 2
x_start: 20
y_start: 144
x_end: 380
y_end: 144
- type: text
value: >-
{{ state_attr('sensor.weatherman_data_tag','wm_temp_now') | round
}}{{ state_attr('sensor.weatherman_data_tag','temperature_unit') }}
font: ../../media/GothamRnd-Bold.ttf
x: 52
"y": 94
size: 38
anchor: mt
color: >-
{{'black' if state_attr('sensor.weatherman_data_tag','wm_temp_now')
| round > severe_temp_low else 'red' }}
- type: icon
value: >-
weather-{{ state_attr('sensor.weatherman_data_tag','wm_cond_now') |
string }}
x: 6
"y": 2
size: 92
color: >-
{{'red' if state_attr('sensor.weatherman_data_tag','wm_cond_now') in
severe_weather else 'black' }}
target:
device_id: bbb79065b21976e867755ad10f1e8b6f
action: open_epaper_link.drawcustom
variables:
severe_weather:
- hail
- rainy
- snowy
- pouring
- lightning
- exceptional
severe_temp_low: 0
severe_wind_speed: 10
severe_precipitation_hour: 5
severe_precipitation_day: 10
mode: restart
configuration.yaml 추가
홈어시스턴트 templete.yaml에 아래와 같이 추가해서 10분마다 날씨 데이터 갱신 시키고 있습니다.
물론 configutaion.yaml 에서 templete.yaml 이 추가되어 있죠.
# Bundle up all the data to send over to Weatherman.
# Will auto-detect the weather integration entity to use.
# If that doesn't work, set the value for the forecast_entity variable manually.
- trigger:
platform: time_pattern
minutes: "/10"
variables:
forecast_entity: weather.forecast_home
forecast_kor: weather.damdanalssi_seongseongdong
action:
- service: weather.get_forecasts
target:
entity_id: "{{forecast_entity}}"
data:
type: hourly
response_variable: weather_home_hourly
- service: weather.get_forecasts
target:
entity_id: "{{forecast_entity}}"
data:
type: daily
response_variable: weather_home_daily
- service: weather.get_forecasts
target:
entity_id: "{{forecast_kor}}"
data:
type: hourly
response_variable: weather_kor_hourly
- service: weather.get_forecasts
target:
entity_id: "{{forecast_kor}}"
data:
type: daily
response_variable: weather_kor_daily
sensor:
- name: Weatherman Data Tag
state: "{{ now().isoformat() }}"
attributes:
moon_phase: >
{% set cond_moon = states('sensor.moon_phase') %}
{% if cond_moon == 'new_moon' %}
moon-new
{% elif cond_moon == 'full_moon' %}
moon-full
{% else %}
{{ "moon-" + cond_moon | replace("_", "-") }}
{%endif%}
sun_next_rising: >
{{ as_timestamp(state_attr("sun.sun", "next_rising")) | timestamp_custom('%-I:%M %p') }}
sun_next_setting: >
{{ as_timestamp(state_attr("sun.sun", "next_setting")) | timestamp_custom('%-I:%M %p') }}
temperature_unit: "{{ state_attr(forecast_kor,'temperature_unit') }}"
wind_speed_unit: "{{ state_attr(forecast_kor,'wind_speed_unit') }}"
precipitation_unit: "{{ state_attr(forecast_kor,'precipitation_unit') }}"
pressure_unit: "{{ state_attr(forecast_kor,'pressure_unit') }}"
wm_cond_now: >
{% set cond_now = states(forecast_kor) %}
{% if cond_now == 'partlycloudy' %}{% set cond_now = 'partly-cloudy' %}{% endif %}
{% if cond_now == 'clear-night' %}{% set cond_now = 'night' %}{% endif %}
{% if states('sun.sun') == 'below_horizon' %}
{% if cond_now == 'sunny' %} night {% elif cond_now == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond_now }} {% endif %}
{% else %}
{{ cond_now }}
{% endif %}
wm_temp_now: >
{{ state_attr(forecast_kor,'temperature') }}
wm_wind_speed_now: >
{{ state_attr(forecast_kor,'wind_speed') | round }}
wm_wind_dir_now: >
{{ state_attr(forecast_entity,'wind_bearing') | round }}
wm_dew_point_now: >
{{ state_attr(forecast_kor,'dew_point') }}
wm_humidity_now: >
{{ state_attr(forecast_kor,'humidity') }}
wm_cloud_coverage_now: >
{{ state_attr(forecast_entity,'cloud_coverage') }}
wm_pressure_now: >
{{ state_attr(forecast_kor,'pressure') }}
wm_cond_0: >
{% set cond0 = weather_kor_hourly[forecast_kor]['forecast'][0].condition %}
{% if cond0 == 'partlycloudy' %}{% set cond0 = 'partly-cloudy' %}{% endif %}
{% if cond0 == 'clear-night' %}{% set cond0 = 'night' %}{% endif %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond0_time = as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][0].datetime) %}
{% if states('sun.sun') == 'above_horizon' and cond0_time > next_setting %}
{% if cond0 == 'sunny' %} night {% elif cond0 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond0 }} {% endif %}
{% elif states('sun.sun') == 'below_horizon' and cond0_time < next_rising %}
{% if cond0 == 'sunny' %} night {% elif cond0 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond0 }} {% endif %}
{% else %}
{{ cond0 }}
{% endif %}
wm_temp_0: >
{{ weather_kor_hourly[forecast_kor]['forecast'][0].temperature | round }}
wm_precipitation_0: >
{{ weather_kor_hourly[forecast_kor]['forecast'][0].precipitation }}
wm_wind_speed_0: >
{{ weather_kor_hourly[forecast_kor]['forecast'][0].wind_speed | round }}
wm_wind_dir_0: >
{{ weather_home_hourly[forecast_entity]['forecast'][0].wind_bearing | round }}
wm_time_0: >
{{ as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][0].datetime) | timestamp_custom('%I') | int }} {{ as_timestamp(weather_home_hourly[forecast_entity]['forecast'][0].datetime) | timestamp_custom('%p') }}
wm_cond_1: >
{% set cond1 = weather_kor_hourly[forecast_kor]['forecast'][1].condition %}
{% if cond1 == 'partlycloudy' %}{% set cond1 = 'partly-cloudy' %}{% endif %}
{% if cond1 == 'clear-night' %}{% set cond1 = 'night' %}{% endif %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond1_time = as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][1].datetime) %}
{% if states('sun.sun') == 'above_horizon' and cond1_time > next_setting %}
{% if cond1 == 'sunny' %} night {% elif cond1 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond1 }} {% endif %}
{% elif states('sun.sun') == 'below_horizon' and cond1_time < next_rising %}
{% if cond1 == 'sunny' %} night {% elif cond1 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond1 }} {% endif %}
{% else %}
{{ cond1 }}
{% endif %}
wm_temp_1: >
{{ weather_kor_hourly[forecast_kor]['forecast'][1].temperature | round }}
wm_precipitation_1: >
{{ weather_kor_hourly[forecast_kor]['forecast'][1].precipitation }}
wm_wind_speed_1: >
{{ weather_kor_hourly[forecast_kor]['forecast'][1].wind_speed | round }}
wm_wind_dir_1: >
{{ weather_home_hourly[forecast_entity]['forecast'][1].wind_bearing | round }}
wm_time_1: >
{{ as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][1].datetime) | timestamp_custom('%I') | int }} {{ as_timestamp(weather_home_hourly[forecast_entity]['forecast'][3].datetime) | timestamp_custom('%p') }}
wm_cond_2: >
{% set cond2 = weather_kor_hourly[forecast_kor]['forecast'][4].condition %}
{% if cond2 == 'partlycloudy' %}{% set cond2 = 'partly-cloudy' %}{% endif %}
{% if cond2 == 'clear-night' %}{% set cond2 = 'night' %}{% endif %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond2_time = as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][4].datetime) %}
{% if states('sun.sun') == 'above_horizon' and cond2_time > next_setting %}
{% if cond2 == 'sunny' %} night {% elif cond2 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond2 }} {% endif %}
{% elif states('sun.sun') == 'below_horizon' and cond2_time < next_rising %}
{% if cond2 == 'sunny' %} night {% elif cond2 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond2 }} {% endif %}
{% else %}
{{ cond2 }}
{% endif %}
wm_temp_2: >
{{ weather_kor_hourly[forecast_kor]['forecast'][4].temperature | round }}
wm_precipitation_2: >
{{ weather_kor_hourly[forecast_kor]['forecast'][4].precipitation }}
wm_wind_speed_2: >
{{ weather_kor_hourly[forecast_kor]['forecast'][4].wind_speed | round }}
wm_wind_dir_2: >
{{ weather_home_hourly[forecast_entity]['forecast'][4].wind_bearing | round }}
wm_time_2: >
{{ as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][4].datetime) | timestamp_custom('%I') | int }} {{ as_timestamp(weather_home_hourly[forecast_entity]['forecast'][6].datetime) | timestamp_custom('%p') }}
wm_cond_3: >
{% set cond3 = weather_kor_hourly[forecast_kor]['forecast'][8].condition %}
{% if cond3 == 'partlycloudy' %}{% set cond3 = 'partly-cloudy' %}{% endif %}
{% if cond3 == 'clear-night' %}{% set cond3 = 'night' %}{% endif %}
{% set next_setting = as_timestamp(state_attr('sun.sun', 'next_setting')) %}
{% set next_rising = as_timestamp(state_attr('sun.sun', 'next_rising')) %}
{% set cond3_time = as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][8].datetime) %}
{% if states('sun.sun') == 'above_horizon' and cond3_time > next_setting %}
{% if cond3 == 'sunny' %} night {% elif cond3 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond3 }} {% endif %}
{% elif states('sun.sun') == 'below_horizon' and cond3_time < next_rising %}
{% if cond3 == 'sunny' %} night {% elif cond3 == 'partly-cloudy' %} night-partly-cloudy {% else %} {{ cond3 }} {% endif %}
{% else %}
{{ cond3 }}
{% endif %}
wm_temp_3: >
{{ weather_kor_hourly[forecast_kor]['forecast'][8].temperature | round }}
wm_precipitation_3: >
{{ weather_kor_hourly[forecast_kor]['forecast'][8].precipitation }}
wm_wind_speed_3: >
{{ weather_kor_hourly[forecast_kor]['forecast'][8].wind_speed | round }}
wm_wind_dir_3: >
{{ weather_home_hourly[forecast_entity]['forecast'][8].wind_bearing | round }}
wm_time_3: >
{{ as_timestamp(weather_kor_hourly[forecast_kor]['forecast'][8].datetime) | timestamp_custom('%I') | int }} {{ as_timestamp(weather_home_hourly[forecast_entity]['forecast'][8].datetime) | timestamp_custom('%p') }}
wm_cond_4: >
{% set cond4 = weather_kor_daily[forecast_kor]['forecast'][1].condition %}
{% if cond4 == 'partlycloudy' %}{% set cond4 = 'partly-cloudy'%}{% endif %}
{% if cond4 == 'clear-night' %}{% set cond4 = 'night' %}{% endif %}
{{ cond4 }}
wm_temp_4: >
{{ weather_kor_daily[forecast_kor]['forecast'][1].temperature | round }}
wm_precipitation_4: >
{{ weather_kor_daily[forecast_kor]['forecast'][1].precipitation }}
wm_temp_4_low: >
{{ weather_kor_daily[forecast_kor]['forecast'][1].templow | round }}
wm_wind_speed_4: >
{{ weather_kor_daily[forecast_kor]['forecast'][1].wind_speed | round }}
wm_wind_dir_4: >
{{ weather_home_daily[forecast_entity]['forecast'][1].wind_bearing | round }}
wm_time_4: >
{{ (as_timestamp(weather_kor_daily[forecast_kor]['forecast'][1].datetime) | timestamp_custom('%-d')) ~ " " ~ (["일","월","화","수","목","금","토"][as_timestamp(weather_kor_daily[forecast_kor]['forecast'][1].datetime) | timestamp_custom('%w') | int]) | string }}
wm_cond_5: >
{% set cond5 = weather_kor_daily[forecast_kor]['forecast'][2].condition %}
{% if cond5 == 'partlycloudy' %}{% set cond5 = 'partly-cloudy'%}{% endif %}
{% if cond5 == 'clear-night' %}{% set cond5 = 'night' %}{% endif %}
{{ cond5 }}
wm_temp_5: >
{{ weather_kor_daily[forecast_kor]['forecast'][2].temperature | round }}
wm_precipitation_5: >
{{ weather_kor_daily[forecast_kor]['forecast'][2].precipitation }}
wm_temp_5_low: >
{{ weather_kor_daily[forecast_kor]['forecast'][2].templow | round }}
wm_wind_speed_5: >
{{ weather_kor_daily[forecast_kor]['forecast'][2].wind_speed | round }}
wm_wind_dir_5: >
{{ weather_home_daily[forecast_entity]['forecast'][2].wind_bearing | round }}
wm_time_5: >
{{ (as_timestamp(weather_kor_daily[forecast_kor]['forecast'][2].datetime) | timestamp_custom('%-d')) ~ " " ~ (["일","월","화","수","목","금","토"][as_timestamp(weather_kor_daily[forecast_kor]['forecast'][2].datetime) | timestamp_custom('%w') | int]) | string }}
wm_cond_6: >
{% set cond6 = weather_kor_daily[forecast_kor]['forecast'][3].condition %}
{% if cond6 == 'partlycloudy' %}{% set cond6 = 'partly-cloudy'%}{% endif %}
{% if cond6 == 'clear-night' %}{% set cond6 = 'night' %}{% endif %}
{{ cond6 }}
wm_temp_6: >
{{ weather_kor_daily[forecast_kor]['forecast'][3].temperature | round }}
wm_precipitation_6: >
{{ weather_kor_daily[forecast_kor]['forecast'][3].precipitation }}
wm_temp_6_low: >
{{ weather_kor_daily[forecast_kor]['forecast'][3].templow | round }}
wm_wind_speed_6: >
{{ weather_kor_daily[forecast_kor]['forecast'][3].wind_speed | round }}
wm_wind_dir_6: >
{{ weather_home_daily[forecast_entity]['forecast'][3].wind_bearing | round }}
wm_time_6: >
{{ (as_timestamp(weather_kor_daily[forecast_kor]['forecast'][3].datetime) | timestamp_custom('%-d')) ~ " " ~ (["일","월","화","수","목","금","토"][as_timestamp(weather_kor_daily[forecast_kor]['forecast'][3].datetime) | timestamp_custom('%w') | int]) | string }}
wm_cond_7: >
{% set cond7 = weather_kor_daily[forecast_kor]['forecast'][4].condition %}
{% if cond7 == 'partlycloudy' %}{% set cond7 = 'partly-cloudy'%}{% endif %}
{% if cond7 == 'clear-night' %}{% set cond7 = 'night' %}{% endif %}
{{ cond7 }}
wm_temp_7: >
{{ weather_kor_daily[forecast_kor]['forecast'][4].temperature | round }}
wm_precipitation_7: >
{{ weather_kor_daily[forecast_kor]['forecast'][4].precipitation }}
wm_temp_7_low: >
{{ weather_kor_daily[forecast_kor]['forecast'][4].templow | round }}
wm_wind_speed_7: >
{{ weather_home_daily[forecast_entity]['forecast'][4].wind_speed | round }}
wm_wind_dir_7: >
{{ weather_home_daily[forecast_entity]['forecast'][4].wind_bearing | round }}
wm_time_7: >
{{ (as_timestamp(weather_kor_daily[forecast_kor]['forecast'][4].datetime) | timestamp_custom('%-d')) ~ " " ~ (["일","월","화","수","목","금","토"][as_timestamp(weather_kor_daily[forecast_kor]['forecast'][4].datetime) | timestamp_custom('%w') | int]) | string }}
wm_cond_8: >
{% set cond8 = weather_kor_daily[forecast_kor]['forecast'][5].condition %}
{% if cond8 == 'partlycloudy' %}{% set cond8 = 'partly-cloudy'%}{% endif %}
{% if cond8 == 'clear-night' %}{% set cond8 = 'night' %}{% endif %}
{{ cond8 }}
wm_temp_8: >
{{ weather_kor_daily[forecast_kor]['forecast'][5].temperature | round }}
wm_temp_8_low: >
{{ weather_kor_daily[forecast_kor]['forecast'][5].templow | round }}
wm_precipitation_8: >
{{ weather_kor_daily[forecast_kor]['forecast'][5].precipitation }}
wm_wind_speed_8: >
{{ weather_home_daily[forecast_entity]['forecast'][5].wind_speed | round }}
wm_wind_dir_8: >
{{ weather_home_daily[forecast_entity]['forecast'][5].wind_bearing | round }}
wm_time_8: >
{{ (as_timestamp(weather_kor_daily[forecast_kor]['forecast'][5].datetime) | timestamp_custom('%-d')) ~ " " ~ (["일","월","화","수","목","금","토"][as_timestamp(weather_kor_daily[forecast_kor]['forecast'][5].datetime) | timestamp_custom('%w') | int]) | string }}
험난한 산을 넘고 요렇게 정보를 가득 채운 날씨 알리미 창을 만들었습니다.
사담을 더 붙이자면 7인치 제품 사고싶은데 너무 비싸더군요.
openepaperlink 디스코드에서 보면 국산 solum 제품 중고로 구해서 많이들 쓰더라구요. 펌웨어도 다시 라이팅 하구요.
AP는 esp32-s3 + esp32-c6 로 만들구요.
아니면 타오바오에 hanshow(汉朔) 제품이 중고로 조금 있던데, 요녀석도 호환 펌웨어 만들어 놓은게 조금 있더라구요.
그런데 펌웨어 올리려면 부숴서 뜯어서 펌웨어 라이팅 위치 확인하고 뒷판 구멍만 살짝 뚫고 포고핀 만든거로 라이팅 하더랍니다.
한두개 쓰기에는 좀 안맞고 대여섯개 만들어야 하는데.... 어렵습니다. 나중에 도전해봐야겠어요.
참조 링크들
https://install.openepaperlink.de/
https://github.com/OpenEPaperLink/OpenEPaperLink/wiki
https://github.com/OpenEPaperLink/Home_Assistant_Integration
https://github.com/OpenEPaperLink/Home_Assistant_Integration/wiki
https://github.com/chunkysteveo/OpenEPaperLink-HA-Weatherman