본문 바로가기

SmartHome. IoT/SmartHome 응용

[HA] 지하철 도착정보 불러오기 - 고도화

728x90
반응형

이걸 며칠 사용하면서 느낀건데, 약간 안 맞더라구요.

왜지? 하면서 봤더니...

호출된 데이터중 아래쪽에 있는 recptnDt 부분이 이 데이터를 생성한 시각인데, PC의 현재시각과 비교하면 약 18초 정도의 차이가 있습니다.

그리고 2호선의 경우 arvlMsg2 부분이 전역 진입 / 전역 도착 / 전역 출발 / x역 진입 등으로 표시되는데

다른 노선의 경우, 여기 표시가 다르더라구요.

그래서 방법이 없나? 생각하다가 데이터 생성시간과 현재시간, 도착까지의 남은시간(barvlDt) 를 활용해 보기로 합니다.

일단 해당 데이터를 불러오기 위해 원래 썼던 센서에 추가를 해줍니다.

 
  - sensor:
      name: Subway Arrival Messages_1
      command: curl -s 'http://swopenapi.seoul.go.kr/api/subway/535565705172617938346f756f4c4b/json/realtimeStationArrival/1/5/%EB%B4%89%EC%B2%9C' | jq -r '.realtimeArrivalList[] | select(.subwayId == "1002") | select(.ordkey | startswith("11"))'
      value_template: "{{ value_json.arvlMsg2 }}"
      json_attributes:
        - arvlMsg3
      scan_interval: 600  # 10 minutes (adjust as needed)

▼▼▼▼▼▼▼▼▼▼▼▼

  - sensor:
      name: Subway Arrival Messages_1
      command: curl -s 'http://swopenapi.seoul.go.kr/api/subway/535565705172617938346f756f4c4b/json/realtimeStationArrival/1/5/%EB%B4%89%EC%B2%9C' | jq -r '.realtimeArrivalList[] | select(.subwayId == "1002") | select(.ordkey | startswith("11"))'
      value_template: "{{ value_json.arvlMsg3 }}"
      json_attributes:
        - arvlMsg2
        - bstatnNm
        - barvlDt
        - recptnDt
        - arvlCd
      scan_interval: 600  # 10 minutes (adjust as needed)

(value 값과 첫줄의 속성 첫줄의 arvlMsg2를 변경했습니다. 이건 취향이니까요)

추가된 부분은

- bstatnNm > 해당 열차의 종착역(xx행)

- barvlDt > 도착까지 남은시간(초 단위)

- recptnDt > 데이터를 생성한 시간

- arvlCd > 열차 도착코드(0:당역진입, 1:당역도착, 2:당역출발, 3:전역출발, 4:전역진입, 5:전역도착, 99:운행중)

이렇게 입니다.

이걸 이용해서 실제로 도착하는 시간을 계산해 보겠습니다.

템플릿의 타임스탬프 항목을 활용할것 이므로, 템플릿 센서로 만들어도 되는데

저는 그냥 호출 문구에다가만 적용하겠습니다.

어차피 템플릿 건드릴 정도면 센서 만드는것 정도야 뭐..그냥 붙여넣기 하면 되는거니까요?

 

이번 열차는
{{ states('sensor.subway_arrival_messages_1') }}
 / {{ state_attr('sensor.subway_arrival_messages_1', 'arvlMsg2') }} 도착
다음 열차는
{{ states('sensor.subway_arrival_messages_2') }}
 / {{ state_attr('sensor.subway_arrival_messages_2', 'arvlMsg2') }} 도착

위 내용은 제가 사용중인 알림용 템플릿 문구 입니다.(지난 강좌와 순서가 약간 변경되었습니다. 센서를 조금 바꿔서요)

states로 센서 명 sensor.subway_arrival_messages_1의 상태를 표시합니다.

이 상태값은 arvlMsg3의 값으로, 데이터의 열차가 정차해 있는(혹은 막 출발한) 역을 의미합니다.

state_attr로 다음 센서의 속성에 대한 값을 표시할것이고 센서명은 동일, 속성은 arvlMsg2 입니다.

arvlMsg2는 남은시간, 전역출발 등의 데이터를 표시합니다.

자 여기까지는 괜찮았는데, 위쪽에서 캡쳐한것과 같이 발표시간과 현재시간의 차이로 인해 오차가 발생합니다.

그리고 일부 역은 arvlMsg2의 데이터가 또 다르더라구요. 그래서 tts나 알림등을 하는데 문구 설정하는게 어려운 경우가 있습니다.

그래서! 그냥 전역출발이나 뭐 그런건 어차피 데이터 생성 시간과 현재시간이 다르니까 신뢰하기 어렵고 다른걸 해보기로 합니다.

여기서 사용할 데이터가 바로 barvlDt 입니다. 도착까지 남은시간을 초 단위로 보여주는 부분 입니다.

데이터 생성시간 + 남은시간 = 실제 열차의 도착시간

열차 도착시간 - 현재시간 = 실제 열차 도착까지의 남은시간

 

{{ (as_timestamp(states.sensor.subway_arrival_messages_1.attributes.recptnDt)
 + (states.sensor.subway_arrival_messages_1.attributes.barvlDt | int )
 - as_timestamp(now()) ) | timestamp_custom("%M분 %S초", false) }}

 

{{

ㄴ 템플릿의 시작

(

ㄴ timestamp_custom 필터를 위한 괄호 시작

as_timestamp(states.sensor.subway_arrival_messages_1.attributes.recptnDt)

ㄴ as_timestamp로 다음 센서의 값을 timestamp 값으로 변환(년+월+일+시+분+초 를 초 단위로 표현하는 것)

+ (states.sensor.subway_arrival_messages_1.attributes.barvlDt | int )

ㄴ 위 값에 barvlDt의 값(도착까지의 남은 시간, 초) 를 더함 = 도착 예정시간의 timestamp가 완성됨

이 값은 문자열로 인식되기 때문에, 뒤에 | int로 정수로 변환함

- as_timestamp(now())

ㄴ 위 값에서 타임스탬프로 변환한 now() 를 뺌. now는 현재 시간을 의미 = 남은 시간이 초 단위로 표현됨

)

ㄴ timestamp_custom 필터를 위한 괄호 끝

| timestamp_custom("%M분 %S초", false)

ㄴ 위 괄호 내에서 계산된 모든 수식의 최종 결과값인 도착까지의 남은시간(초 단위) 를 x분 y초 형태로 표현

}}

ㄴ 템플릿 끝

자 여기까지가 이 값을 표현하기 위한 템플릿 입니다.

여기까지 보셨다면 충분하죠? 그럼 여기서 멈추세요!

그런데... 이렇게 하면, 100초 남은 경우 = 01분 40초 로 표현되는데

40초가 남았다면, 00분 40초로 표현됩니다.

앞에...00분 거슬려요..

 

{% set total = (as_timestamp(states.sensor.subway_arrival_messages_1.attributes.recptnDt)
  + (states.sensor.subway_arrival_messages_1.attributes.barvlDt | int )
  - as_timestamp(now())) %}
{% set min, sec = total // 60, total % 60 %}
{{ '%02d분 %02d초'|format(min, sec) if min > 0 else '%02d초'|format(sec) }}

그러면 set 을 써봅시다.

set 은 다음으로 지정하는 변수를 = 이 값으로 정한다 라고 설정하는겁니다.

{% set total = (as_timestamp(states.sensor.subway_arrival_messages_1.attributes.recptnDt)

+ (states.sensor.subway_arrival_messages_1.attributes.barvlDt | int )

- as_timestamp(now())) %}

이렇게 하면, 이 템플릿에서 total 이라는 단어가 쓰이면 = 수식을 계산하여 산출된 값으로 쓰인다 라고 보시면 됩니다.

일종의 사용자 지정 매크로 같은거죠.

total = 위에서 설명드린 도착까지의 남은시간을 계산합니다.

{% set min, sec = total // 60, total % 60 %}

min, sec = 이 변수는 위에서 설정한 total의 값을 60으로 나눈 몫을 min, 60으로 나눈 나머지를 sec로 정합니다.

{{ '%02d분 %02d초'|format(min, sec) if min > 0 else '%02d초'|format(sec) }}

이렇게 계산된 min값과 sec값을 표시합니다.

이때, min값이 0보다 크면 'xx분 yy초' 단위로 표현하고, 그렇지 않다면 'yy초' 로 표시합니다.

 

  {% set total = (as_timestamp(states.sensor.subway_arrival_messages_1.attributes.recptnDt)
  + (states.sensor.subway_arrival_messages_1.attributes.barvlDt | int )
  - as_timestamp(now())) %}
  {% set min, sec = total // 60, total % 60 %}
  {% set total_2 = (as_timestamp(states.sensor.subway_arrival_messages_2.attributes.recptnDt)
  + (states.sensor.subway_arrival_messages_2.attributes.barvlDt | int )
  - as_timestamp(now())) %}
  {% set min_2, sec_2 = total_2 // 60, total % 60 %}
    이번 열차: {{ states('sensor.subway_arrival_messages_1')  }} /
{{ '%02d분 %02d초'|format(min, sec) if min > 0 else '%02d초'|format(sec) }}후 도착


    다음 열차:{{ states('sensor.subway_arrival_messages_2')  }} /
{{ '%02d분 %02d초'|format(min_2, sec_2) if min_2 > 0 else '%02d초'|format(sec_2) }}후 도착

이걸 도착메세지 첫번째, 두번째 차량으로 만들어야 하므로, 변수 명을 조금 바꿔야 합니다.

동일 템플릿 이라, 같은 변수명 사용이 불가능하니 2번째 도착 차량의 변수는 _2를 붙여줬습니다.

total_2 / min_2 / sec_2 로 변경되었으며, 당연히 계산 및 표현에 사용되는 변수명도 변경해줘야 합니다.

템플릿 편집기에서 불러오면, 이렇게 표시가 됩니다.

이걸 기준으로 적당히 만져서 알림 자동화로 넣으면 됩니다!

전역출발, 전역도착 등으로 표현하는것도 직관적이긴 하지만,

데이터 생성 시간과의 차이를 고려하면 좀 애매해서 그냥 절대값에 가까운 도착 예정시간을 기준으로 했습니다.

자 이제 응용은 각자의 몫으로!

오늘 내용은 여기까지 입니다~

다음에 또 재미난거 들고올게요~

728x90
반응형