IoT 랜이

똑똑한 IoT를 추구합니다.

IT Info/IoT

[RS485] 월패드를 시리얼포트로 제어하기2(환기장치 제어 추가)

Rangee 2019. 6. 11. 21:33

 

 

담다패드 - 월패드만 있으면 우리집은 이미 스마트홈?!

담다패드 - 월패드만 있으면 우리집은 이미 스마트홈?! 스마트폰, 스마트전구, IoT가전제품, AI스피커 ...... 스마트한 세상에 살고계신 여러분. 월패드가 있는 우리집이 이미 스마트홈 이라는

mscg.kr

 

피바로 홈센터3 - 월패드(RS485) 연동

피바로 홈센터3 - 월패드(RS485) 연동 홈센터3 개봉기에서 이미 언급했지만 새롭게 스마트홈(혹은 상업공간)을 구축할 예정이거나 기존의 플랫폼에 한계를 느낀다면 홈센터3를 강력 추천. (인테

mscg.kr

 

 

 

준비물

Node.js 가 실행되는 라즈베리파이 등(ex: 아두이노)

USB to RS485 3개. (월패드1개, 환기장치2개)

 

수정

엘레베이터 호출 추가

환기장치 연동


 

 

 

 

안녕하세요. 랜이입니다.

 

앞전에 올렸던 글에서 그렉스 환기장치를 연동하게 되어서 설정기와 자바스크립트 파일을 공유하려합니다.

=> [RS485] 월패드를 시리얼포트로 제어하기

 

 

내용을 시작하기에 앞서 우리집의 환기장치에 대해서 먼저 설명할게요.

 

 

환기장치 제어기는 1초에 4~5회 정도 환기장치에게 현재 모드에 대한 신호를 보냅니다.

 

현재 "자동" 모드이면  자동~~~~~~~

현재 "취침" 모드이면  취침~~~~~~~

현재 "수동1단" 모드이면  수동1~~~~~~

 

이런식으로요.

 

그러면 GREX환기장치는  신호에 대해서 모드를 바꾸고 제어기 신호에 대해 1:1 응답을 합니다.

 

1:1 응답을 못하는 경우 환기장치 제어기는 "통신에러"를 뿜어내죠.

 

여기에서 문제가 하나 발생합니다.

 

아래와 같이 RS485 연결을 해서 패킷신호를 보내서 작동을 하려해도

 

환기장치 제어기가 신호를 지속적으로 보내기 때문에  환기장치 제어기의 신호로 덮어씌워지게 됩니다.

 

 

 

 

그렇기 때문에 아래와 같이 작동을 해야 할 필요성이 있었습니다.

 

라즈베라파이에  시리얼포트를 2개를 OPEN 하고

 

라즈베리파이가  환기장치 제어기의 지속적인 신호에 FAKE 응답을 보내고

라즈베리파이가  GREX 환기장치에 별도의 제어신호를 주게 하는것이죠.

 

 

이렇게 할 경우

 

수동제어와 스마트제어 모두 가능해집니다.

 

수동제어를 할 경우

> 라즈베리파이에서 환기장치에 신호 전송.

> GREX 환기장치의 응답 패킷을 제어기에 발송.

> GREX 환기장치의 응답을 HA로 전송.

 

스마트제어를 할 경우

> 원하는 모드를 GREX 환기장치에 전송.

> GREX 환기장치의 응답을 HA로 전송.

> 제어기에는 FAKE 패킷을 전송하여 통신에러를 방지

 

중요한점은 제어기와 환기장치의 변수를 따로 구분해서 통신에러가 발생하지 않도록 하는것이죠.

 

 

그래서.. 환기장치를 위한 "USB to RS485"가 2개 필요하고

 

월패드를 위해서 1개.  총 3개의 "USB to RS485"가 필요하네요.

 

이상 GREX 환기장치에 대한 설명이었습니다.

(환기장치를 추가하시기 전에  패킷을 꼭 분석하셔야합니다!)

 

 

kocom.js
0.03MB

 

아래는 HA에서 월패드와 환기장치 제어하기 위한 소스입니다.

 

 

HA - automations.yaml

- id: command_airgrex_automation
  alias: 환기장치 이산화탄소 자동화
  trigger:
  - platform: state
    entity_id: sensor.awair_co2_bedroom
  - platform: state
    entity_id: sensor.awair_co2_livingroom
  - platform: state
    entity_id: input_select.air_grex_mode
    to: "이산화탄소"
  condition: 
  - condition: template
    value_template: '{% if states("input_select.air_grex_mode") == "이산화탄소" %}true{% endif %}'
  action:
  - data:
      entity_id: timer.airgrex_timer
    service: timer.cancel
  - entity_id: timer.airgrex_delay_timer
    service: timer.cancel
  - service: mqtt.publish
    data_template:
      topic: "kocom/air/grex/mode/command"
      payload_template: >
        {% if states("input_select.air_grex_mode") == "이산화탄소" and (states("sensor.awair_co2_bedroom")|int + states("sensor.awair_co2_livingroom")|int)/2|float - states("input_number.air_grex_automation_co2")|float > 100 %}수동3단
        {% elif states("input_select.air_grex_mode") == "이산화탄소" and (states("sensor.awair_co2_bedroom")|int + states("sensor.awair_co2_livingroom")|int)/2|float - states("input_number.air_grex_automation_co2")|float > 0 %}수동2단
        {% else %}정지
        {% endif %}
      retain: true
- id: set_airgrex
  alias: 환기장치 수동작동
  trigger:
  - platform: state
    entity_id: sensor.grexmode
  - platform: state
    entity_id: sensor.grexspeed
  condition:
  - condition: template
    value_template: '{% if states("input_select.air_grex_mode") != "이산화탄소" and states("input_select.air_grex_mode") != "대기" %}true{% endif %}'
  action:
  - service: homeassistant.turn_off
    entity_id: automation.hwangijangci_jagdong
  - service: input_select.select_option
    data_template:
      entity_id: input_select.air_grex_mode
      option: >
        {% if states("sensor.grexmode") == "수동" %}{{ states("sensor.grexmode") }}{{ states("sensor.grexspeed") }}
        {% elif states("sensor.grexmode") == "수동" and states("sensor.grexspeed") == "0단" %}대기
        {% elif states("sensor.grexmode") == "자동" or states("sensor.grexmode") == "취침" %}{{ states("sensor.grexmode") }}
        {% endif %}
  - service: homeassistant.turn_on
    entity_id: automation.hwangijangci_jagdong
- id: command_airgrex
  alias: 환기장치 작동
  trigger:
  - platform: state
    entity_id: input_select.air_grex_mode
  condition: 
  - condition: template
    value_template: '{% if trigger.to_state.state != "이산화탄소" and trigger.to_state.state != "대기" %}true{% endif %}'
  action:
  - service: mqtt.publish
    data_template:
      topic: "kocom/air/grex/mode/command"
      payload_template: '{{ states("input_select.air_grex_mode") }}'
      retain: true
- id: command_airgrex_timer_start
  alias: 환기장치 타이머 시작
  trigger:
  - platform: state
    entity_id: input_select.air_grex_mode
    to: '수동1단'
  - platform: state
    entity_id: input_select.air_grex_mode
    to: '수동2단'
  - platform: state
    entity_id: input_select.air_grex_mode
    to: '수동3단'
  - platform: state
    entity_id: input_select.air_grex_mode
    to: '자동'
  - platform: state
    entity_id: input_select.air_grex_mode
    to: '취침'
  - platform: state
    entity_id: input_number.air_grex_manual_minute_per_hour
  condition:
  - condition: template
    value_template: '{% if states("input_number.air_grex_manual_minute_per_hour") | int != 60 and (trigger.to_state.state == "수동1단" or trigger.to_state.state == "수동2단" or trigger.to_state.state == "수동3단" or trigger.to_state.state == "자동" or trigger.to_state.state == "취침" or (trigger.entity_id == "input_number.air_grex_manual_minute_per_hour" and (states("input_select.air_grex_mode") == "수동1단" or states("input_select.air_grex_mode") == "수동2단" or states("input_select.air_grex_mode") == "수동3단"))) %}true{% endif %}'
  action:
  - service: timer.cancel
    entity_id: timer.airgrex_delay_timer
  - service: timer.cancel
    entity_id: timer.airgrex_timer
  - service: timer.start
    entity_id: timer.airgrex_timer
    data_template:
      duration: '00:{% if trigger.to_state.state == "수동1단" or trigger.to_state.state == "수동2단" or trigger.to_state.state == "수동3단" or (trigger.entity_id == "input_number.air_grex_manual_minute_per_hour" and (states("input_select.air_grex_mode") == "수동1단" or states("input_select.air_grex_mode") == "수동2단" or states("input_select.air_grex_mode") == "수동3단")) %}{{ states("input_number.air_grex_manual_minute_per_hour") | int }}{% elif trigger.to_state.state == "자동" %}30{% elif trigger.to_state.state == "취침" %}15{% endif %}:00'
- id: command_airgrex_timer_cancel
  alias: 환기장치 타이머 취소
  trigger:
  - platform: state
    entity_id: input_select.air_grex_mode
    to: '정지'
  - platform: state
    entity_id: sensor.grexmode
  - platform: state
    entity_id: sensor.grexspeed
  - platform: state
    entity_id: input_number.air_grex_manual_minute_per_hour
  condition:
  - condition: template
    value_template: '{% if trigger.entity_id == "input_select.air_grex_mode" or (trigger.entity_id == "input_number.air_grex_manual_minute_per_hour" and states("input_number.air_grex_manual_minute_per_hour") | int == 60) %}true{% endif %}'
  action:
  - data:
      entity_id: timer.airgrex_timer
    service: timer.cancel
  - entity_id: timer.airgrex_delay_timer
    service: timer.cancel
- id: command_airgrex_timer_finish
  alias: 환기장치 타이머 완료
  trigger:
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.airgrex_timer
  condition: []
  action:
  - service: input_select.select_option
    data_template:
      entity_id: input_select.air_grex_mode_copy
      option: '{{ states("input_select.air_grex_mode") }}'
  - service: mqtt.publish
    data_template:
      topic: "kocom/air/grex/mode/command"
      payload_template: >
        {% if states("input_select.air_grex_mode") == "자동" %}자동0단
        {% elif states("input_select.air_grex_mode") == "취침" %}취침0단
        {% elif states("input_select.air_grex_mode") == "수동1단" or states("input_select.air_grex_mode") == "수동2단" or states("input_select.air_grex_mode") == "수동3단" %}수동0단
        {% endif %}
      retain: true
  - service: timer.start
    entity_id: timer.airgrex_delay_timer
    data_template:
      duration: '00:{% if (is_state("input_select.air_grex_mode", "수동1단") or is_state("input_select.air_grex_mode", "수동2단") or is_state("input_select.air_grex_mode", "수동3단")) %}{{ 60 - states("input_number.air_grex_manual_minute_per_hour") | int }}{% elif is_state("input_select.air_grex_mode", "자동") %}30{% elif is_state("input_select.air_grex_mode", "취침") %}45{% endif %}:00'
- id: command_airgrex_delay_timer_finish
  alias: 환기장치 딜레이 타이머 완료
  trigger:
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.airgrex_delay_timer
  condition: []
  action:
  - service: mqtt.publish
    data_template:
      topic: "kocom/air/grex/mode/command"
      payload_template: '{{ states("input_select.air_grex_mode_copy") }}'
      retain: true
  - service: timer.start
    entity_id: timer.airgrex_timer
    data_template:
      duration: '00:{% if (is_state("input_select.air_grex_mode", "수동1단") or is_state("input_select.air_grex_mode", "수동2단") or is_state("input_select.air_grex_mode", "수동3단")) %}{{ states("input_number.air_grex_manual_minute_per_hour") | int }}{% elif is_state("input_select.air_grex_mode", "자동") %}30{% elif is_state("input_select.air_grex_mode", "취침") %}15{% endif %}:00'

 

HA - input_select.yaml

air_grex_mode:
  name: 환기장치 모드
  options:
   - 정지
   - 자동
   - 취침
   - 수동1단
   - 수동2단
   - 수동3단
   - 이산화탄소
   - 대기
  initial: 정지
air_grex_mode_copy:
  name: 환기장치 모드 카피
  options:
   - 정지
   - 자동
   - 취침
   - 수동1단
   - 수동2단
   - 수동3단
   - 이산화탄소
   - 대기
  initial: 정지

 

HA - input_number.yaml

air_grex_manual_minute_per_hour:
  name: 환기장치 수동작동
  min: 5
  max: 60
  step: 5
air_grex_automation_co2:
  name: CO2 자동화
  min: 500
  max: 1200
  step: 50

 

HA - sensors.yaml

- platform: mqtt
  state_topic: "kocom/air/grex/state"
  name: "GrexMode"
  value_template: >
    {% if value_json.mode == "0000" %}정지
    {% elif value_json.mode == "0100" %}자동
    {% elif value_json.mode == "0200" %}수동
    {% elif value_json.mode == "0300" %}취침
    {% endif %}
  icon: mdi:format-list-bulleted
- platform: mqtt
  state_topic: "kocom/air/grex/state"
  name: "GrexSpeed"
  value_template: >
    {% if value_json.speed == "0000" %}0단
    {% elif value_json.speed == "0101" %}1단
    {% elif value_json.speed == "0202" %}2단
    {% elif value_json.speed == "0303" %}3단
    {% endif %}
  icon: mdi:speedometer

 

HA - timer.yaml

airgrex_timer:
  name: AirGrex Timer
airgrex_delay_timer:
  name: AirGrex Delay Timer

 

HA - switchs.yaml

# 엘레베이터

- platform: mqtt
  name: elevator
  command_topic: "kocom/elevator/ev/call/command"
  state_topic: "kocom/elevator/ev/state"
  value_template: "{{ value_json.call }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true

# 아래는 전등제어

- platform: mqtt
  name: livingroom_light1
  command_topic: "kocom/livingroom/light/1/command"
  state_topic: "kocom/livingroom/light/state"
  value_template: "{{ value_json.light1 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true
- platform: mqtt
  name: livingroom_light2
  command_topic: "kocom/livingroom/light/2/command"
  state_topic: "kocom/livingroom/light/state"
  value_template: "{{ value_json.light2 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true
- platform: mqtt
  name: livingroom_light3
  command_topic: "kocom/livingroom/light/3/command"
  state_topic: "kocom/livingroom/light/state"
  value_template: "{{ value_json.light3 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true

- platform: mqtt
  name: kitchen_light1
  command_topic: "kocom/kitchen/light/1/command"
  state_topic: "kocom/kitchen/light/state"
  value_template: "{{ value_json.light1 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true
- platform: mqtt
  name: kitchen_light2
  command_topic: "kocom/kitchen/light/2/command"
  state_topic: "kocom/kitchen/light/state"
  value_template: "{{ value_json.light2 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true
- platform: mqtt
  name: kitchen_light3
  command_topic: "kocom/kitchen/light/3/command"
  state_topic: "kocom/kitchen/light/state"
  value_template: "{{ value_json.light3 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true

- platform: mqtt
  name: bedroom_light1
  command_topic: "kocom/bedroom/light/1/command"
  state_topic: "kocom/bedroom/light/state"
  value_template: "{{ value_json.light1 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true
- platform: mqtt
  name: bedroom_light2
  command_topic: "kocom/bedroom/light/2/command"
  state_topic: "kocom/bedroom/light/state"
  value_template: "{{ value_json.light2 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true

- platform: mqtt
  name: room1_light1
  command_topic: "kocom/room1/light/1/command"
  state_topic: "kocom/room1/light/state"
  value_template: "{{ value_json.light1 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true
- platform: mqtt
  name: room1_light2
  command_topic: "kocom/room1/light/2/command"
  state_topic: "kocom/room1/light/state"
  value_template: "{{ value_json.light2 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true

- platform: mqtt
  name: room2_light1
  command_topic: "kocom/room2/light/1/command"
  state_topic: "kocom/room2/light/state"
  value_template: "{{ value_json.light1 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true
- platform: mqtt
  name: room2_light2
  command_topic: "kocom/room2/light/2/command"
  state_topic: "kocom/room2/light/state"
  value_template: "{{ value_json.light2 }}"
  payload_on: "on"
  payload_off: "off"
  qos: 0
  retain: true

 

HA - climate.yaml

- platform: mqtt
  name: "Livingroom Thermo"
  mode_state_topic: "kocom/livingroom/thermo/state"
  mode_command_topic: "kocom/livingroom/thermo/heat_mode/command"
  mode_state_template: "{{ value_json.heat_mode }}"
  temperature_state_topic: "kocom/livingroom/thermo/state"
  temperature_command_topic: "kocom/livingroom/thermo/set_temp/command"
  temperature_state_template: "{{ value_json.set_temp }}"
  current_temperature_topic: "kocom/livingroom/thermo/state"
  current_temperature_template: "{{ value_json.cur_temp }}"
  modes:
    - "off"
    - "away"
    - "on"
  min_temp: 5
  max_temp: 40
- platform: mqtt
  name: "Bedroom Thermo"
  mode_state_topic: "kocom/bedroom/thermo/state"
  mode_command_topic: "kocom/bedroom/thermo/heat_mode/command"
  mode_state_template: "{{ value_json.heat_mode }}"
  temperature_state_topic: "kocom/bedroom/thermo/state"
  temperature_command_topic: "kocom/bedroom/thermo/set_temp/command"
  temperature_state_template: "{{ value_json.set_temp }}"
  current_temperature_topic: "kocom/bedroom/thermo/state"
  current_temperature_template: "{{ value_json.cur_temp }}"
  modes:
    - "off"
    - "away"
    - "on"
  min_temp: 5
  max_temp: 40
- platform: mqtt
  name: "Room1 Thermo"
  mode_state_topic: "kocom/room1/thermo/state"
  mode_command_topic: "kocom/room1/thermo/heat_mode/command"
  mode_state_template: "{{ value_json.heat_mode }}"
  temperature_state_topic: "kocom/room1/thermo/state"
  temperature_command_topic: "kocom/room1/thermo/set_temp/command"
  temperature_state_template: "{{ value_json.set_temp }}"
  current_temperature_topic: "kocom/room1/thermo/state"
  current_temperature_template: "{{ value_json.cur_temp }}"
  modes:
    - "off"
    - "away"
    - "on"
  min_temp: 5
  max_temp: 40
- platform: mqtt
  name: "Room2 Thermo"
  mode_state_topic: "kocom/room2/thermo/state"
  mode_command_topic: "kocom/room2/thermo/heat_mode/command"
  mode_state_template: "{{ value_json.heat_mode }}"
  temperature_state_topic: "kocom/room2/thermo/state"
  temperature_command_topic: "kocom/room2/thermo/set_temp/command"
  temperature_state_template: "{{ value_json.set_temp }}"
  current_temperature_topic: "kocom/room2/thermo/state"
  current_temperature_template: "{{ value_json.cur_temp }}"
  modes:
    - "off"
    - "away"
    - "on"
  min_temp: 5
  max_temp: 40