반응형

아파트 월패드용 스마트폰 어플이 있으나 도저히 사용할 수 없는 속도다.

프로그램 실행하는데 하세월 걸리고 버튼 누르고 변경되는걸 확인하는데도 몇초씩 걸린다.

 

불편함에 찾아보니 이미 선구자들이

월패드와 전등, 보일러 등 연결된 장치간 통신이 RS485 이며 해당 패킷을 분석하고 패킷을 보내서 제어를 하고 있다.

 

 

기본적으로 서버가 필요하며 라즈베리 파이나 도커 설치 가능한 NAS를 주로 사용한다.

 

RS485 제어 방법은 크게 아래 3가지다.

  • 서버에 직접 RS485-USB 장치를 연결 (패킷 제어 프로그램 필요. node.js나 파이썬 버전으로 제작되어있음)
  • RS485 to wifi 장치를 연결 (패킷 제어 프로그램 필요. node.js나 파이썬 버전으로 제작되어있음 )
  • ESPHome 장치를 이용한 제어 (Home assistant 플러그인 있음)

 

 

 

자세한 내용은 아래를 읽어보며 따라가면 된다.

 

cafe.naver.com/stsmarthome/12973

 

월패드 연동 ESPHOME RS485...

2020-04-01 업데이트 1. 체크섬 2byte 대응 checksum2 옵션 추가 (a...

cafe.naver.com

 

cafe.naver.com/stsmarthome/18238

 

[ESPHome] 현대통신 월패드 R...

대한민국 모임의 시작, 네이버 카페

cafe.naver.com

 

 

 

본인은 HA(Home assistant) 에서 가장 간편하게 사용 할 수 있는 ESPhome 버전으로 사용하고 있다.

사용을 위한 준비 과정을 요약하면 아래와 같다. 

1. 준비물

  • NAS (또는 라즈베리파이) 
  • Wemo d1 mini (RS8266 장치, 와이파이 가능한 프로그래밍 보드)
  • RS485 to UART
  • 납땜 장비, 소량의 전선
  • ESPeasy 펌웨어
  • HASS.io 설치 (home assistant 와 기타 애드온 관리 프로그램 통합된 버전)
  • 5V 1A 정도의 usb 충전기

2. 사용방법 요약

 

 

3. 사용중인 설정 내용

같은 imazu 여도 아파트마다 조금씩 패킷이 다르다. 참조할 것..

 

백업을 위해서 사용중인 esphome 데이터를 아래와 같이 붙여넣는다.

substitutions:
  node_name: rs485
  device_name: "RS485 Controller"
  
esphome:
  name: imazu_home_kks
  platform: esp8266
  board: d1_mini

wifi:
  ssid: "SSID"
  password: "PASSWORD"
  manual_ip:
    static_ip: 192.168.1.4 #(YOUR IP)
    gateway: 192.168.1.1
    subnet: 255.255.255.0
  reboot_timeout: 10min
  
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Fallback Hotspot"
    password: "FALLBACK HOTSPOT PASSWORD"

captive_portal:


debug:
# Enable logging
logger:
  baud_rate: 0
  level: DEBUG #기본값
  #level: VERBOSE #사용하지 않는 패킷만 출력
  #level: VERY_VERBOSE #전체 패킷 출력 (초기 설정시에 추천)

# Enable Home Assistant API
api:
  reboot_timeout: 0s

ota:
  password: "PASSWORD"

status_led:
  pin: 
    number: GPIO2
    inverted: True


# RS485 Component (for ttl to rs485 module)
#  - esp8266: UART0 (TX: GPIO1, RX: GPIO3)
#  - esp32: UART2 (TX: GPIO17, RX: GPIO16)
rs485:
  baud_rate: 9600 #Required
  data_bits: 8    #Option(default: 8)
  parity: 0       #Option(default: 0)
  stop_bits: 1    #Option(default: 1)
  
  rx_wait: 10     #Option(default: 10ms)  -> 수신 메시지 대기시간 (10ms 미만으로 수신된 메시지만 한 패킷으로 판단)
  tx_interval: 50 #Option(default: 50ms) -> 발신 메시지 전송 간격 (패킷 수신 후 50ms 대기 후 전송)
  tx_wait: 100    #Option(default: 100ms) -> 발신 메시지 Ack 대기시간
  tx_retry_cnt: 3 #Option(default: 3)     -> 발신 메시지 Ack 없을 경우 재시도 횟수
  prefix: [0xF7]  #Option -> 값 세팅시 모든 수신 패킷 Check, 발신 패킷에 Append
  suffix: [0xEE]  #Option -> 값 세팅시 모든 수신 패킷 Check, 발신 패킷에 Append

  checksum: True      #Option(default: False) -> 체크섬 사용여부 (lambda 사용시 세팅 불필요)
  # checksum_lambda: |- #Option -> Default(CheckSum8 Xor) 체크섬 아닐 경우 직접 로직 구현(아래 값은 Default 로직임)
  #   // @param: const uint8_t *data, const unsigned short len
  #   // @return: uint8_t
  #   uint8_t crc = 0xF7; // data 변수에는 prefix 제외되어 있음
  #   for(num_t i=0; i<len; i++)
  #     crc ^= data[i];
  #   return crc;
  
  checksum2: False  #Option(default: False) -> ADD 체크섬 사용여부
  # checksum2: !lambda |- #Option -> Default(CheckSum8 Add) 체크섬 아닐 경우 직접 로직 구현(아래 값은 Default 로직임)
  #   // @param: const uint8_t *data, const unsigned short len, const uint8_t checksum1
  #   // @return: uint8_t
  #   uint8_t crc = 0xF7; // data 변수에는 prefix 제외되어 있음
  #   for(num_t i=0; i<len; i++)
  #     crc += data[i];
  #   crc += checksum1; // 첫번째 체크섬 계산 결과
  #   return crc;
  
#  state_response: #Option -> 값 세팅시 response 패킷 수신 후에 명령 패킷 송신
#    data: [0x04]
#    offset: 3
#    and_operator: False #Option(default: False) 수신패킷의 offset 위치와 data[0] And 비트연산 (비트위치-1: 0x01, 2: 0x02, 3: 0x04, 4: 0x08, 5: 0x10, 6: 0x20, 7: 0x40, 8: 0x80)
#    inverted: False #Option(default: False) 결과 값 반전(일치하지 않을 경우 참)
    
    
#  packet_monitor: #Option -> 패킷 모니터: Array 없으면 전체 출력, 있을 경우 or 조건 (logger level DEBUG 추천)
#   - [0x0c, 0x01, 0x2b]  # offset: 0
#   - data: [0x19, 0x04, 0x40, 0x23]
#     offset: 2

# RS485 Device 셋팅 팁
# 1. 상태 확인용(수신) Schema
#   - 대상: device(Required), sub_device(Option), state*
#   - 조건: device and sub_device 일치할때만 해당 Device에 패킷 전달됨
#   - 예시:
#     device: 
#       offset: 0 # 수신 패킷 비교 위치 (prefix 제외)
#       data: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x23, 0x00] # hex array
#       and_operator: False # And 비트연산 사용여부
#       inverted: False #Option(default: False) 결과 값 반전 여부
#     #alias schema
#     device: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x23, 0x00] # offset: 0, data: hex array
#
# 2. 명령용(발신) Schema
#   - 대상: command*
#   - 예시:
#     command:
#       data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x21, 0x01, 0x00]  # prefix, checksum, suffix 제외
#       ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x21, 0x01, 0x01]   # prefix, checksum, suffix 제외
#     # Ack 없을 경우
#     command: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x21, 0x01, 0x00]
#     # Template(lambda): command_on, command_off
#     command_on: !lambda |-
#       uint8_t flag = id(balcony).state ? 0x02 : 0x01;
#       return {
#                 {0x0b, 0x01, 0x19, 0x02, 0x40, 0x23, flag, 0x00},
#                 {0x0b, 0x01, 0x19, 0x04, 0x40, 0x23, 0x01, 0x01}
#              };
#     command_off: !lambda |-
#       uint8_t flag = id(balcony).state ? 0x02 : 0x01;
#       return {
#                 {0x0b, 0x01, 0x19, 0x02, 0x40, 0x23, flag, 0x00},
#                 {0x0b, 0x01, 0x19, 0x04, 0x40, 0x23, 0x02, 0x02}
#              };
#     # 상태확인 요청 (Sensor 포함 모든 Device에 사용 가능)
#     command_state: [0x0B, 0x01, 0x19, 0x01, 0x40, 0x23, 0x00, 0x00] #Option
#     update_interval: 30s #Option(default: 60s)
#
# 3. Automation Schema
#   - rs485.write:
#       data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x23, 0x01, 0x00]
#       ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x23, 0x01, 0x01]
#   - rs485.write: !lambda return {{0x0b, 0x01, 0x19, 0x02, 0x40, 0x23, 0x01, 0x00}, {0x0b, 0x01, 0x19, 0x04, 0x40, 0x23, 0x01, 0x01}};
#   # Ack 없는 경우
#   - rs485.write: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x23, 0x01, 0x00]
#   - rs485.write: !lambda return {{0x0b, 0x01, 0x19, 0x02, 0x40, 0x23, 0x01, 0x00}, {}};



# RS485 Sensor

globals:
  - id: EV_CALL_COUNT
    type: int
    initial_value: '0'
  - id: EV_CALLING
    type: bool
    initial_value: 'false'

sensor:
  #엘리베이터 방향 정보
  - platform: rs485
    id: EV_ARRIVE
    device: [0x0D, 0x01, 0x34, 0x01, 0x41, 0x10, 0x00]
    #device: [0x0D, 0x01, 0x34, 0x01, 0x41, 0x10, 0x00]  kks 
    data:
      offset: 7
      length: 1
    on_value:
      then:
        - text_sensor.template.publish:
            id: EV_DIRECTION
            state: !lambda |-
              if (x == 0x01) return "도착";
              else if (x == 0xA6) return "UP";
              else if (x == 0xB6) return "DOWN";
              else return "";
  # 엘리베이터 층수 정보
  - platform: rs485
    id: EV
    device: [0x0D, 0x01, 0x34, 0x01, 0x41, 0x10, 0x00]
    #device: [0x0D, 0x01, 0x34, 0x01, 0x41, 0x10, 0x00]  kks
    lambda: !lambda |-
      if(len < 9) return {};
      char buf[3];
      sprintf(buf, "%02X ", data[8]);
      if(buf[0] == 'F')
        if(buf[1] == 'F') return -1.0;
        else return -2.0;
      else
        return atof(buf);
    on_value:
      then:
        - text_sensor.template.publish:
            id: EV_TEXT
            state: !lambda |-
              char result[10];
              if(x == 0) sprintf(result, "");
              else if(x > 0) sprintf(result, "%1.0f층", x);
              else sprintf(result, "지하 %1.0f층", -x);
              return result;

text_sensor:
  - platform: homeassistant
    name: Google Home mini TTS state
    icon: "mdi:speaker"
    entity_id: sensor.tts_state
    id: TTS_STATE

  # 엘리베이터 층수 정보
  - platform: template
    name: Elevator Floor
    icon: "mdi:elevator"
    id: EV_TEXT
    on_value:
      then:
        - if:
            condition:
              lambda: |-
                return ( "" != id(EV_TEXT).state );
            then:
              # 층수 정보가 업데이트 될 경우 엘리베이터 호출에 성공한 것으로 판단
              - globals.set:
                  id: EV_CALLING
                  value: 'false'
              # TTS로 엘리베이터 층수 방송
              - if:
                  condition:
                    lambda: |-
                      return ( "off" == id(TTS_STATE).state );
                  then:
                    - homeassistant.service:
                        service: media_player.turn_on
                        data:
                          entity_id: media_player.sigtagyeop
              - homeassistant.service:
                  service: tts.google_say
                  data:
                    entity_id: media_player.sigtagyeop
                    message: !lambda 'return id(EV_TEXT).state;'

  # 엘리베이터 방향(UP/DOWN/도착) 정보
  - platform: template
    name: Elevator Direction
    icon: "mdi:elevator"
    id: EV_DIRECTION
    on_value:
      - if:
          condition:
            text_sensor.state:
              id: EV_DIRECTION
              state: '도착'
          then:
            # 방향 정보가 업데이트 될 경우 엘리베이터 호출에 성공한 것으로 판단
            - globals.set:
                id: EV_CALLING
                value: 'false'
            - delay: 5s
            - homeassistant.service:
                service: media_player.turn_off
                data:
                  entity_id: media_player.sigtagyeop


switch:
    
  # 안방1 콘센트
  # 켜기
  #  0xf7 0x0b 0x01 0x1f 0x02 0x40 0x21 0x01 0x00 0x80 0xee
  #  0xf7 0x0b 0x01 0x1f 0x04 0x40 0x21 0x01 0x01 0x87 0xee (ack)
  # 끄기
  #  0xf7 0x0b 0x01 0x1f 0x02 0x40 0x21 0x02 0x00 0x83 0xee
  #  0xf7 0x0b 0x01 0x1f 0x04 0x40 0x21 0x02 0x02 0x87 0xee (ack)
  # 켜기상태-> 0xF7 0x12 0x01 0x1F 0x04 0x40 0x21 0x00 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x9E 0xEE
  # 끄기상태-> 0xF7 0x12 0x01 0x1F 0x04 0x40 0x21 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x9D 0xEE

  - platform: template
    name: Elevator Call
    icon: "mdi:elevator"
    turn_on_action:
      # 엘리베이터 호출 cmd는 최대 30번
      # 점검 등의 사유로 호출이 안될 경우 중단을 위해 최대 카운트 설정
      - globals.set:
          id: EV_CALL_COUNT
          value: '25'
      # 엘리베이터 호출에 성공할 경우 cmd 보내는 것을 중지하기 위한 변수
      # 층수 정보(EV_TEXT)가 업데이트 될 경우 엘리베이터 호출에 성공한 것으로 판단
      - globals.set:
          id: EV_CALLING
          value: 'true'
      # TTS로 엘리베이터 호출 방송
      - homeassistant.service:
          service: media_player.turn_on
          data:
            entity_id: media_player.sigtagyeop
      - homeassistant.service:
          service: tts.google_say
          data:
            entity_id: media_player.sigtagyeop
            message: 엘리베이터를 호출합니다.
      # TTS 방송이 완료될 때 까지 대기
      # 대기하지 않을 경우 층수 정보(EV_TEXT) 방송에 의해 호출 방송이 중단 됨
      - delay: 2s
      # 반복문
      - while:
          # 엘리베이터 호출에 성공하거나, 최대 30번까지만 cmd를 전송
          condition:
            lambda: |-
              return ( 0 < id(EV_CALL_COUNT) ) && ( true == id(EV_CALLING) );
          # 1초마다 한번씩 cmd를 전송
          # cmd를 전송할 때 마다 카운트 변수를 1씩 차감
          then:
            - rs485.write: [0x0B, 0x01, 0x34, 0x04, 0x41, 0x10, 0x00, 0x06]
            #- rs485.write: [0x0B, 0x01, 0x34, 0x04, 0x41, 0x10, 0x00, 0x06]  kks 
            - lambda: |-
                id(EV_CALL_COUNT) -= 1;
            - delay: 1s
      # 엘리베이터 호출에 실패할 경우 TTS로 호출 실패 방송
      - if:
          condition:
            lambda: |-
              return ( 0 == id(EV_CALL_COUNT) );
          then:
            - homeassistant.service:
                service: tts.google_say
                data:
                  entity_id: media_player.sigtagyeop
                  message: 엘리베이터 호출에 실패했습니다.
            - delay: 3s
            - homeassistant.service:
                service: media_player.turn_off
                data:
                  entity_id: media_player.sigtagyeop
 
  - platform: rs485
    name: "Bedroom Power Socket 1"
    icon: "mdi:power-socket-eu"
    device: [0x25, 0x01, 0x1F, 0x04, 0x40, 0x20, 0x00]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x21, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x21, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x21, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x21, 0x02, 0x02]
    #command_state: [0x0B, 0x01, 0x1f, 0x01, 0x40, 0x20, 0x00, 0x00] #Option
    #update_interval: 997s #Option(default: 60s)
    
  # 안방2 콘센트
  - platform: rs485
    name: "Bedroom Power Socket 2"
    icon: "mdi:power-socket-eu"
    device: [0x25, 0x01, 0x1F, 0x04, 0x40, 0x20, 0x00]
    state_on:
      offset: 17
      data: [0x01]
    state_off:
      offset: 17
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x22, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x22, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x22, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x22, 0x02, 0x02]

  # 안방3 콘센트
  - platform: rs485
    name: "Bedroom Power Socket 3"
    icon: "mdi:power-socket-eu"
    device: [0x25, 0x01, 0x1F, 0x04, 0x40, 0x20, 0x00]
    state_on:
      offset: 26
      data: [0x01]
    state_off:
      offset: 26
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x23, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x23, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x23, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x23, 0x02, 0x02]
      
  # 거실1 콘센트
  - platform: rs485
    name: "Livingroom Power Socket 1"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x10]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x11, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x11, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x11, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x11, 0x02, 0x02]
    #command_state: [0x0B, 0x01, 0x1f, 0x01, 0x40, 0x10, 0x00, 0x00] #Option
    #update_interval: 991s #Option(default: 60s)


  # 거실2 콘센트
  - platform: rs485
    name: "Livingroom Power Socket 2"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x10]
    state_on:
      offset: 17
      data: [0x01]
    state_off:
      offset: 17
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x12, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x12, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x1f, 0x02, 0x40, 0x12, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x1f, 0x04, 0x40, 0x12, 0x02, 0x02]


  # 컴퓨터방 콘센트1
  # 켜기
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x02, 0x40, 0x41, 0x01, 0x00, 0xE0, 0xEE
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x04, 0x40, 0x41, 0x01, 0x01, 0xE7, 0xEE  ack
  # 끄기
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x02, 0x40, 0x41, 0x02, 0x00, 0xE3, 0xEE
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x04, 0x40, 0x41, 0x02, 0x02, 0xE7, 0xEE
  
  - platform: rs485
    name: "Computer Room Power Socket 1"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x40, 0x00]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x41, 0x01, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x41, 0x01, 0x01]
    command_off:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x41, 0x02, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x41, 0x02, 0x02]
    #command_state: [0x0B, 0x01, 0x1f, 0x01, 0x40, 0x40, 0x00, 0x00] #Option
    #update_interval: 983s #Option(default: 60s)

  # 컴퓨터방 콘센트2
  # 켜기
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x02, 0x40, 0x42, 0x01, 0x00, 0xE3, 0xEE
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x04, 0x40, 0x42, 0x01, 0x01, 0xE4, 0xEE  ack
  # 끄기
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x02, 0x40, 0x42, 0x02, 0x00, 0xE0, 0xEE
  #, 0xF7, 0x0B, 0x01, 0x1F, 0x04, 0x40, 0x42, 0x02, 0x02, 0xE4, 0xEE


  - platform: rs485
    name: "Computer Room Power Socket 2"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x40, 0x00]
    state_on:
      offset: 17
      data: [0x01]
    state_off:
      offset: 17
      data: [0x02]
    command_on:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x42, 0x01, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x42, 0x01, 0x01]
    command_off:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x42, 0x02, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x42, 0x02, 0x02]

  # 작은방 콘센트1

  - platform: rs485
    name: "Room3 Power Socket 1"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x30, 0x00]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x31, 0x01, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x31, 0x01, 0x01]
    command_off:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x31, 0x02, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x31, 0x02, 0x02]
    #command_state: [0x0B, 0x01, 0x1f, 0x01, 0x40, 0x30, 0x00, 0x00] #Option
    #update_interval: 977s #Option(default: 60s)
    
    
  # 작은방 콘센트2

  - platform: rs485
    name: "Room3 Power Socket 2"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x30, 0x00]
    state_on:
      offset: 17
      data: [0x01]
    state_off:
      offset: 17
      data: [0x02]
    command_on:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x32, 0x01, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x32, 0x01, 0x01]
    command_off:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x32, 0x02, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x32, 0x02, 0x02]

  # 주방 콘센트1

  - platform: rs485
    name: "Kitchen Power Socket 1"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x50, 0x00]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x51, 0x01, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x51, 0x01, 0x01]
    command_off:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x51, 0x02, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x51, 0x02, 0x02]
    #command_state: [0x0B, 0x01, 0x1f, 0x01, 0x40, 0x50, 0x00, 0x00] #Option
    #update_interval: 971s #Option(default: 60s)
    
    
  # 주방 콘센트2
  - platform: rs485
    name: "Kitchen Power Socket 2"
    icon: "mdi:power-socket-eu"
    device: [0x1C, 0x01, 0x1F, 0x04, 0x40, 0x50, 0x00]
    state_on:
      offset: 24
      data: [0x01]
    state_off:
      offset: 24
      data: [0x02]
    command_on:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x52, 0x01, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x52, 0x01, 0x01]
    command_off:
      data: [0x0B, 0x01, 0x1F, 0x02, 0x40, 0x52, 0x02, 0x00]
      ack: [0x0B, 0x01, 0x1F, 0x04, 0x40, 0x52, 0x02, 0x02]


# RS485 Light(like Binary Light)
light:
  # [안방1]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x21, 0x00, 0x01, 0x80, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x21, 0x00, 0x02, 0x83, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x21, 0x01, 0x00, 0x86, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x21, 0x02, 0x00, 0x85, 0xee
  - platform: rs485
    name: "Bedroom 1"
    device: [0x0c, 0x01, 0x19, 0x04, 0x40, 0x20, 0x00]
    state_on:
      offset: 7
      data: [0x01]
    state_off:
      offset: 7
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x21, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x21, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x21, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x21, 0x02, 0x02]
#    command_state: [0x0B, 0x01, 0x19, 0x01, 0x40, 0x20, 0x00, 0x00] #Option
#    update_interval: 101s #Option(default: 60s)
    
  # [안방2]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x22, 0x00, 0x01, 0x83, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x22, 0x00, 0x02, 0x80, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x22, 0x01, 0x00, 0x85, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x22, 0x02, 0x00, 0x86, 0xee
  - platform: rs485
    name: "Bedroom 2"
    device: [0x0c, 0x01, 0x19, 0x04, 0x40, 0x20, 0x00]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x22, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x22, 0x01, 0x01]
    command_off: 
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x22, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x22, 0x02, 0x02]


  # [거실1]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x11, 0x00, 0x01, 0xb0, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x11, 0x00, 0x02, 0xb3, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x11, 0x01, 0x00, 0xb6, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x11, 0x02, 0x00, 0xb5, 0xee
  - platform: rs485
    name: "Livingroom 1"
    device: [0x0D, 0x01, 0x19, 0x04, 0x40, 0x10, 0x00]
    state_on:
      offset: 7
      data: [0x01]
    state_off:
      offset: 7
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x11, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x11, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x11, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x11, 0x02, 0x02]
#    command_state: [0x0B, 0x01, 0x19, 0x01, 0x40, 0x10, 0x00, 0x00] #Option
#    update_interval: 103s #Option(default: 60s)
 

  # [거실2]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x12, 0x00, 0x01, 0xb3, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x12, 0x00, 0x02, 0xb0, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x12, 0x01, 0x00, 0xb5, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x12, 0x02, 0x00, 0xb6, 0xee
  - platform: rs485
    name: "Livingroom 2"
    device: [0x0D, 0x01, 0x19, 0x04, 0x40, 0x10, 0x00]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x12, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x12, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x12, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x12, 0x02, 0x02]



  # [발코니]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x13, 0x00, 0x01, 0xb2, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x13, 0x00, 0x02, 0xb1, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x13, 0x01, 0x00, 0xb4, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x13, 0x02, 0x00, 0xb7, 0xee
  - platform: rs485
    name: "Livingroom 3"
    device: [0x0D, 0x01, 0x19, 0x04, 0x40, 0x10, 0x00]
    state_on:
      offset: 9
      data: [0x01]
    state_off:
      offset: 9
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x13, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x13, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x13, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x13, 0x02, 0x02]


  # [작은방]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x31, 0x01, 0x01, 0x91, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x31, 0x02, 0x02, 0x91, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x31, 0x01, 0x00, 0x96, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x31, 0x02, 0x00, 0x95, 0xee
  - platform: rs485
    name: "Room 3"
    device: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x30, 0x00]
    state_on:
      offset: 7
      data: [0x01]
    state_off:
      offset: 7
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x31, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x31, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x31, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x31, 0x02, 0x02]
#    command_state: [0x0B, 0x01, 0x19, 0x01, 0x40, 0x30, 0x00, 0x00] #Option
#    update_interval: 107s #Option(default: 60s)
    
      
  # [컴퓨터방]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x41, 0x01, 0x01, 0xe1, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x41, 0x02, 0x02, 0xe1, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x41, 0x01, 0x00, 0xe6, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x41, 0x02, 0x00, 0xe5, 0xee
  - platform: rs485
    name: "Computer Room"
    device: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x40, 0x00]
    state_on:
      offset: 7
      data: [0x01]
    state_off:
      offset: 7
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x41, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x41, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x41, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x41, 0x02, 0x02]
#    command_state: [0x0B, 0x01, 0x19, 0x01, 0x40, 0x40, 0x00, 0x00] #Option
#    update_interval: 109s #Option(default: 60s)

      
  # [주방]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x51, 0x01, 0x01, 0xf1, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x51, 0x02, 0x02, 0xf1, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x51, 0x01, 0x00, 0xf6, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x51, 0x02, 0x00, 0xf5, 0xee
  - platform: rs485
    name: "Kitchen"
    device: [0x0C, 0x01, 0x19, 0x04, 0x40, 0x50, 0x00]
    state_on:
      offset: 7
      data: [0x01]
    state_off:
      offset: 7
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x51, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x51, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x51, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x51, 0x02, 0x02]
#    command_state: [0x0B, 0x01, 0x19, 0x01, 0x40, 0x50, 0x00, 0x00] #Option
#    update_interval: 113s #Option(default: 60s)
      
      
  # [식탁]
  # 켜짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x52, 0x01, 0x01, 0xf2, 0xee
  # 꺼짐 상태-> 0xf7, 0x0b, 0x01, 0x19, 0x04, 0x40, 0x52, 0x02, 0x02, 0xf2, 0xee
  # 켜짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x52, 0x01, 0x00, 0xf5, 0xee
  # 꺼짐 명령-> 0xf7, 0x0b, 0x01, 0x19, 0x02, 0x40, 0x52, 0x02, 0x00, 0xf6, 0xee
  - platform: rs485
    name: "Table"
    device: [0x0C, 0x01, 0x19, 0x04, 0x40, 0x50, 0x00]
    state_on:
      offset: 8
      data: [0x01]
    state_off:
      offset: 8
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x52, 0x01, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x52, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x19, 0x02, 0x40, 0x52, 0x02, 0x00]
      ack: [0x0b, 0x01, 0x19, 0x04, 0x40, 0x52, 0x02, 0x02]


# RS485 Fan
fan:
  # [환기]
  # 켜짐(강) 상태-> 0xf7, 0x0c, 0x01, 0x2b, 0x04, 0x42, 0x11, 0x07, 0x01, 0x07, 0x87, 0xee
  # 켜짐(중) 상태-> 0xf7, 0x0c, 0x01, 0x2b, 0x04, 0x42, 0x11, 0x03, 0x01, 0x03, 0x87, 0xee
  # 켜짐(약) 상태-> 0xf7, 0x0c, 0x01, 0x2b, 0x04, 0x42, 0x11, 0x01, 0x01, 0x01, 0x87, 0xee
  # 꺼짐     상태-> 0xf7, 0x0c, 0x01, 0x2b, 0x04, 0x40, 0x11, 0x02, 0x02, 0x01, 0x85, 0xee
  # 켜짐(강) 명령-> 0xf7, 0x0b, 0x01, 0x2b, 0x02, 0x42, 0x11, 0x07, 0x00, 0x80, 0xee
  # 켜짐(중) 명령-> 0xf7, 0x0b, 0x01, 0x2b, 0x02, 0x42, 0x11, 0x03, 0x00, 0x84, 0xee
  # 켜짐(약) 명령-> 0xf7, 0x0b, 0x01, 0x2b, 0x02, 0x42, 0x11, 0x01, 0x00, 0x86, 0xee
  # 꺼짐     명령-> 0xf7, 0x0b, 0x01, 0x2b, 0x02, 0x40, 0x11, 0x02, 0x00, 0x87, 0xee
  - platform: rs485
    name: "Ventilation"
    device: [0x0c, 0x01, 0x2b, 0x04, 0x40, 0x11, 0x00]
    state_on:
      offset: 7
      data: [0x01]
    state_off:
      offset: 7
      data: [0x02]
    command_on:
      data: [0x0b, 0x01, 0x2b, 0x02, 0x40, 0x11, 0x01, 0x00]
#      ack: [0x0c, 0x01, 0x2b, 0x04, 0x41, 0x2b, 0x04, 0x40, 0x11, 0x00, 0x01]
      ack: [0x0c, 0x01, 0x2b, 0x04, 0x40, 0x11, 0x01, 0x01, 0x01]
    command_off:
      data: [0x0b, 0x01, 0x2b, 0x02, 0x40, 0x11, 0x02, 0x00]
      ack: [0x0c, 0x01, 0x2b, 0x04, 0x40, 0x11, 0x02, 0x02, 0x01]
    speed: #Option(high, medium, low) -> 없으면 Binary Fan
      high:
        state:
          offset: 7
          data: [0x01, 0x07]
#          data: [0x07, 0x01, 0x07]
        command:
          data: [0x0b, 0x01, 0x2b, 0x02, 0x42, 0x11, 0x07, 0x00]
  #        data: [0x0c, 0x01, 0x2b, 0x04, 0x42, 0x11, 0x07, 0x01, 0X07 ]
          ack: [0x0c, 0x01, 0x2b, 0x04, 0x40, 0x11, 0x00, 0x01, 0x07]
      medium:
        state:
          offset: 7
          data: [0x01, 0x03]
        command:
#          data: [0x0b, 0x01, 0x2b, 0x02, 0x42, 0x11, 0x03, 0x00, 0x84
          data: [0x0b, 0x01, 0x2b, 0x02, 0x42, 0x11, 0x03, 0x00]
          ack: [0x0c, 0x01, 0x2b, 0x04, 0x40, 0x11, 0x00, 0x01, 0x03]
      low:
        state:
          offset: 7
          data: [0x01, 0x01, 0x01]
        command:
          data: [0x0b, 0x01, 0x2b, 0x02, 0x42, 0x11, 0x01, 0x00]
          ack: [0x0c, 0x01, 0x2b, 0x04, 0x40, 0x11, 0x00, 0x01, 0x01]
 #   command_state: [0x0B, 0x01, 0x2b, 0x01, 0x40, 0x11, 0x00, 0x00] #Option
#    update_interval: 107s #Option(default: 60s)


# RS485 Climate
climate:
  # [거실 난방] 0x11
  # 상태 요청: 0xF7, 0x0B, 0x01, 0x18, 0x01, 0x45, 0x11, 0x00, 0x00, 0xB0, 0xEE
  # 켜짐 상태: 0xF7, 0x0D, 0x01, 0x18, 0x04, 0x45, 0x11, 0x00, (0x01, 0x1B, 0x17), 0xBE, 0xEE (상태, 현재온도, 설정온도)
  # 꺼짐 상태: 0xF7, 0x0D, 0x01, 0x18, 0x04, 0x45, 0x11, 0x00, (0x04, 0x1B, 0x17), 0xBB, 0xEE (상태, 현재온도, 설정온도)
  # 외출 상태: 0xF7, 0x0D, 0x01, 0x18, 0x04, 0x45, 0x11, 0x00, (0x07, 0x1B, 0x17), 0xB9, 0xEE
  # 켜짐 명령: 0xF7, 0x0B, 0x01, 0x18, 0x02, 0x46, 0x11, 0x01, 0x00, 0xB1, 0xEE
  #      ACK: 0xF7, 0x0D, 0x01, 0x18, 0x04, 0x46, 0x11, 0x01, 0x01, 0x1B, 0x17, 0xBC, 0xEE
  # 꺼짐 명령: 0xF7, 0x0B, 0x01, 0x18, 0x02, 0x46, 0x11, 0x04, 0x00, 0xB4, 0xEE
  #      ACK: 0xF7, 0x0D, 0x01, 0x18, 0x04, 0x46, 0x11, 0x04, 0x04, 0x1B, 0x17, 0xBC, 0xEE
  # 온도 조절: 0xF7, 0x0B, 0x01, 0x18, 0x02, 0x45, 0x11, (0x18), 0x00, 0xA7, 0xEE (온도 24도 설정)
  #      ACK: 0xF7, 0x0D, 0x01, 0x18, 0x04, 0x45, 0x11, (0x18), 0x01, (0x1A, 0x18), 0xA8, 0xEE
  - platform: rs485
    name: "Livingroom Heater"
    visual:
      min_temperature: 10 °C
      max_temperature: 40 °C
      temperature_step: 1 °C
    device: [0x22, 0x01, 0x18, 0x04, 0x46, 0x10, 0x00]
    state_current: #Required (현재온도 State, RS485 Sensor 설정 참고, sensor:로 대체 가능)
      offset: 8
      length: 1
      precision: 0
    state_target: #Required (설정온도 State)
      offset: 9
      length: 1
      precision: 0
    state_off: #Required (끄기 상태)
      offset: 7
      data: [0x04]
    state_heat: #Option (난방모드, 냉방모드: state_cool, 자동모드: state_auto)
      offset: 7
      data: [0x01]
    state_away: #Option (외출모드)
      offset: 7
      data: [0x07]
    command_off: #Required (끄기 명령)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x11, 0x04, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x11, 0x04, 0x04]
    command_heat: #Option (난방모드 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x11, 0x01, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x11, 0x01, 0x01]
    command_away: #Option (외출 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x11, 0x07, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x11, 0x07, 0x07]
    command_temperature: !lambda |-  #Required (온도 조절)
      // @param: const float x
      return {
                {0x0B, 0x01, 0x18, 0x02, 0x46, 0x11, (uint8_t)x, 0x00},
                {0x0D, 0x01, 0x18, 0x04, 0x46, 0x11, (uint8_t)x, 0x01}
             };
             
#    command_state: [0x0B, 0x01, 0x18, 0x01, 0x46, 0x11, 0x00, 0x00] #Option
#    update_interval: 701s #Option(default: 60s)
 #0xF7, 0x0B, 0x01, 0x18, 0x01, 0x46, 0x10, 0x00, 0x00, 0xB2, 0xEE
 #0xF7, 0x22, 0x01, 0x18, 0x04, 0x46, 0x10, 0x00, 0x01, 0x15, 0x15, 0x01, 0x15, 0x16, 0x04, 0x13, 0x17, 0x04, 0x16, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0


  # [안방] 0x12
  # (현재온도 외부 센서 사용 샘플)
  - platform: rs485
    name: "Bedroom Heater"
    visual:
      min_temperature: 10 °C
      max_temperature: 40 °C
      temperature_step: 1 °C
    device: [0x22, 0x01, 0x18, 0x04, 0x46, 0x10, 0x00]
    state_current: #Required (현재온도 State, RS485 Sensor 설정 참고, sensor:로 대체 가능)
      offset: 11
      length: 1
      precision: 0
    state_target:
      offset: 12
      length: 1
      precision: 0
    state_off:
      offset: 10
      data: [0x04]
    state_heat:
      offset: 10
      data: [0x01]
    state_away:
      offset: 10
      data: [0x07]
    command_off: #Required (끄기 명령)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x12, 0x04, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x12, 0x04, 0x04]
    command_heat: #Option (난방모드 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x12, 0x01, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x12, 0x01, 0x01]
    command_away: #Option (외출 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x12, 0x07, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x12, 0x07, 0x07]
    command_temperature: !lambda |-  #Required (온도 조절)
      // @param: const float x
      return {
                {0x0B, 0x01, 0x18, 0x02, 0x46, 0x12, (uint8_t)x, 0x00},
                {0x0D, 0x01, 0x18, 0x04, 0x46, 0x12, (uint8_t)x, 0x01}
             };
#    command_state: [0x0B, 0x01, 0x18, 0x01, 0x46, 0x12, 0x00, 0x00] #Option
#    update_interval: 709s #Option(default: 60s)

  # [작은방] 0x14
  - platform: rs485
    name: "Room3 Heater"
    visual:
      min_temperature: 10 °C
      max_temperature: 40 °C
      temperature_step: 1 °C
    device: [0x22, 0x01, 0x18, 0x04, 0x46, 0x10, 0x00]
    state_current: #Required (현재온도 State, RS485 Sensor 설정 참고, sensor:로 대체 가능)
      offset: 14
      length: 1
      precision: 0
    state_target:
      offset: 15
      length: 1
      precision: 0
    state_off:
      offset: 13
      data: [0x04]
    state_heat:
      offset: 13
      data: [0x01]
    state_away:
      offset: 13
      data: [0x07]
    command_off: #Required (끄기 명령)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x13, 0x04, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x13, 0x04, 0x04]
    command_heat: #Option (난방모드 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x13, 0x01, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x13, 0x01, 0x01]
    command_away: #Option (외출 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x13, 0x07, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x13, 0x07, 0x07]
    command_temperature: !lambda |-  #Required (온도 조절)
      // @param: const float x
      return {
                {0x0B, 0x01, 0x18, 0x02, 0x46, 0x13, (uint8_t)x, 0x00},
                {0x0D, 0x01, 0x18, 0x04, 0x46, 0x13, (uint8_t)x, 0x01}
             };
#    command_state: [0x0B, 0x01, 0x18, 0x01, 0x46, 0x13, 0x00, 0x00] #Option
#    update_interval: 719s #Option(default: 60s)

  # [컴퓨터방] 0x13
  - platform: rs485
    name: "Computer Room Heater"
    visual:
      min_temperature: 10 °C
      max_temperature: 40 °C
      temperature_step: 1 °C
    device: [0x22, 0x01, 0x18, 0x04, 0x46, 0x10, 0x00]
    state_current:
      offset: 17
      length: 1
      precision: 0
    state_target:
      offset: 18
      length: 1
      precision: 0
    state_off:
      offset: 16
      data: [0x04]
    state_heat:
      offset: 16
      data: [0x01]
    state_away:
      offset: 16
      data: [0x07]
    command_off: #Required (끄기 명령)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x14, 0x04, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x14, 0x04, 0x04]
    command_heat: #Option (난방모드 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x14, 0x01, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x14, 0x01, 0x01]
    command_away: #Option (외출 켜기)
      data: [0x0B, 0x01, 0x18, 0x02, 0x46, 0x14, 0x07, 0x00]
      ack: [0x0D, 0x01, 0x18, 0x04, 0x46, 0x14, 0x07, 0x07]
    command_temperature: !lambda |-  #Required (온도 조절)
      // @param: const float x
      return {
                {0x0B, 0x01, 0x18, 0x02, 0x45, 0x14, (uint8_t)x, 0x00},
                {0x0D, 0x01, 0x18, 0x04, 0x45, 0x14, (uint8_t)x, 0x01}
             };
#    command_state: [0x0B, 0x01, 0x18, 0x01, 0x46, 0x14, 0x00, 0x00] #Option
#    update_interval: 727s #Option(default: 60s)
반응형
반응형

시놀로지 라우터를 위한 스크립트 모음이 있다.

사용을 위해서는 라우터에 usb 나 sdcard 와 같은 메모리가 ext3 format 으로 사용중이어야 한다.

 

아래 링크에서 확인하면 된다.

https://gitlab.com/Kendek/syno-router-scripts/-/blob/master/README.md#wireguard_installsh

 

 

 

1. 설치

라우터에서 ssh 접속이 가능하도록 한 후

ssh 로 접속한다.

로그인은 root 계정으로 한다. (admin 계정이 아님!! 암호는 admin 계정과 동일)

 

로그인 후 아래 내용을 입력하면 자동으로 설치 스크립트 창이 뜬다.

sh -c "$(wget -O- goo.gl/Pkyohd)"

 

 

 

WireGuard VPN 설치를 위해서 먼저 사용 할 수 있는 환경을 설치해야 하는데

1번 entware나 2번 ubuntu 아무거나 설치해도 된다.

설치 후 5번 wireguard 를 눌러서 설치하면 된다.

 

 

 

2. 라우터 방화벽 설정

wiregurad 사용을 위해서는 시놀로지 라우터에서 방화벽 설정을 아래와 같이 해주어야 한다.

Necessary firewall rule for connection:

Protocol Source IP Source port Destination IP Destination port Action

UDP All All SRM 51820 Allow

Necessary firewall rule for access to local network:

Protocol Source IP Source port Destination IP Destination port Action

TCP/UDP 10.7.0.0/255.255.255.0 All All All Allow

 

 

3. client 용 설정 파일, QR code 확인

다시 스크립트 접속 후 5번 메뉴 wireguard 에 들어가서 client 추가를 하면 자동으로 설정 및 qrcode 생성이 된다.

생성된 설정 파일 및 QR code는 라우터에 저장되며 라우터 file station 또는 다른 방식으로 접근해서 확인하면 된다.

 

 

 

4. VPN client 설정

안드로이드는 구글 스토어에서 wireguard 를 설치하고 위에서 만든 QR코드를 리딩하기만 하면 자동으로 추가된다.

그리고 바로 사용 가능하다.

윈도우의 경우에는 위에서 만든 컨피그 파일을 불러오면 된다.

참조를 위해 아래 링크도 남겨놓는다.

 

 

 

 

참조할만한 링크

https://golb.hplar.ch/2019/07/wireguard-windows.html

 

Setting up WireGuard on Windows

A few months ago, I wrote a tutorial on how to install WireGuard, a simple, fast, and modern VPN, on Linux and open a VPN connection from an Android device. Because I work most time on Windows I was also especially interested in connecting my computer to a

golb.hplar.ch

https://serversideup.net/generating-wireguard-qr-codes-for-fast-mobile-deployments/

 

Generating Wireguard QR codes for fast mobile deployments - Server Side Up

Supporting mobile devices with Wireguard VPN can be dramatically easier by using a QR code. Learn how to generate a Wireguard QR code for your clients in just a few minutes.

serversideup.net

https://serversideup.net/how-to-configure-a-wireguard-ios-client/

 

How to configure a Wireguard iOS client - Server Side Up

This is a coniutation of my free “mini-course” called Gain Flexibility & Increase Privacy with Wireguard VPN. Start there if you are new to Wireguard. What you’ll achieve We will have our iPhone client connecting to our Wireguard VPN server This is w

serversideup.net

https://serversideup.net/how-to-configure-a-wireguard-android-vpn-client/

 

How to configure a Wireguard Android VPN Client - Server Side Up

Learn how to easily configure a Wireguard Android client. Using QR codes, I'll show you how you to easily configure a remote device in minutes.

serversideup.net

 

https://ziwon.github.io/post/wireguard/

 

WireGuard 설치 및 방화벽 설정 | ziwon.github.io

WireGuard 소개 WireGuard는 임베디드 인터페이스와 슈퍼 컴퓨터를 위한 범용 VPN로, 최첨단 암호화 기술을 사용하며 단순하고 빠르고 현대적인 VPN이다. IPsec보다 더 간단하며 더 빠르고, OpenVPN보다 성�

ziwon.github.io

 

https://www.wireguard.com/quickstart/

 

Quick Start - WireGuard

Quick Start You'll first want to make sure you have a decent grasp of the conceptual overview, and then install WireGuard. After that, read onwards here. Side by Side Video Before explaining the actual comands in detail, it may be extremely instructive to

www.wireguard.com

 

반응형
반응형

ssh로 접속 후 wireguard 설치

repository가 등록되어 있지 않아서 아래와 같이 추가하여 설치하자 

sudo add-apt-repository ppa:wireguard/wireguard

 

sudo apt install wireguard

 

서버 공개키 개인키 생성

sudo mkdir -p /etc/wireguard/server; wg genkey | sudo tee /etc/wireguard/server/server.key | wg pubkey | sudo tee /etc/wireguard/server/server.key.pub

서버 공개키 출력

 

 

공개키 개인키 재확인

cat /etc/wireguard/server/server.key.pub
cat /etc/wireguard/server/server.key

 

서버 설정파일 제작 

sudo nano /etc/wireguard/wg0.conf

 

[Interface]
Address = 192.168.2.1/32
PrivateKey = Server_private_key
ListenPort = 1194

[Peer]
PublicKey = Client_1_public_key
AllowedIPs = 192.168.2.2/32
  • Address: VPN 접속시 서버 IP 주소
  • PrivateKey: 서버의 개인키
  • ListenPort: 사용 포트 (방화벽 에서 열어줘야함, 공유기 사용시 포트포워딩 필요)
  • PublicKey: 접속에 사용하는 client(PC나 모바일폰)의 PublicKey
  • AllowedIPs: client 할당 IP

 

모바일용 QR 코드 제작을 위한 설정

 

qrencode 설치

sudo apt install qrencode

 

QR코드용 공개키 개인키 생성 후 확인

sudo mkdir -p /etc/wireguard/clients; wg genkey | sudo tee /etc/wireguard/clients/mobile.key | wg pubkey | sudo tee /etc/wireguard/clients/mobile.key.pub
cat /etc/wireguard/clients/mobile.key

위쪽 박스: 공개키

아래쪽 박스: 개인키

 

 

QR코드용 설정파일 제작

sudo nano /etc/wireguard/clients/mobile.conf
[Interface]
PrivateKey = Mobile_Private_key
Address = 192.168.2.3/24
DNS = 1.1.1.1, 1.0.0.1

[Peer]
PublicKey = YOUR_SERVER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0
Endpoint = YOUR_SERVER_WAN_IP:1194
  • Endpoint: 서버IP (또는 DDNS 주소 사용 가능)

 

서버 설정파일에 Peer 추가

sudo nano /etc/wireguard/wg0.conf
[Interface]
Address = 192.168.2.1/32
PrivateKey = Server_private_key
ListenPort = 1194

[Peer]
PublicKey = Client_1_public_key
AllowedIPs = 192.168.2.2/32

[Peer]
PublicKey = Mobile_public_key
AllowedIPs = 192.168.2.3/32

 

QR 코드 생성

qrencode -t ansiutf8 < /etc/wireguard/clients/mobile.conf

 

Wireguard 실행

wg-quick up wg0

 

이제 생성된 QR 코드를 소중하게 잘 보관하고 wireguard android 앱에서 QR스캔하면 접속 가능!

 

 

 

 

Wireguard 가 실행되어 있을 경우에는 아래와 같이 재시작 필요

wg-quick down wg0 && wg-quick up wg0

 

시스템 재시작시 자동 실행 등록

sudo systemctl enable wg-quick@wg0

Synology NAS의 경우 제어판-작업스케줄러에 시작시 아래와 같이 실행하도록 설정

sleep 60
wg-quick up wg0
sleep 5
wg-quick down wg0
sleep 5
wg-quick up wg0

 

 

 

 

 

 

 

윈도우에서는 아래와 같이 설정되어야 함 참조하여 윈도우 client 셋팅하고 서버 설정파일에 키를 잘 넣어주자.

 

이상 끝

 

 

참조할만한 링크

https://golb.hplar.ch/2019/07/wireguard-windows.html

 

Setting up WireGuard on Windows

A few months ago, I wrote a tutorial on how to install WireGuard, a simple, fast, and modern VPN, on Linux and open a VPN connection from an Android device. Because I work most time on Windows I was also especially interested in connecting my computer to a

golb.hplar.ch

https://serversideup.net/generating-wireguard-qr-codes-for-fast-mobile-deployments/

 

Generating Wireguard QR codes for fast mobile deployments - Server Side Up

Supporting mobile devices with Wireguard VPN can be dramatically easier by using a QR code. Learn how to generate a Wireguard QR code for your clients in just a few minutes.

serversideup.net

https://serversideup.net/how-to-configure-a-wireguard-ios-client/

 

How to configure a Wireguard iOS client - Server Side Up

This is a coniutation of my free “mini-course” called Gain Flexibility & Increase Privacy with Wireguard VPN. Start there if you are new to Wireguard. What you’ll achieve We will have our iPhone client connecting to our Wireguard VPN server This is w

serversideup.net

https://serversideup.net/how-to-configure-a-wireguard-android-vpn-client/

 

How to configure a Wireguard Android VPN Client - Server Side Up

Learn how to easily configure a Wireguard Android client. Using QR codes, I'll show you how you to easily configure a remote device in minutes.

serversideup.net

 

https://ziwon.github.io/post/wireguard/

 

WireGuard 설치 및 방화벽 설정 | ziwon.github.io

WireGuard 소개 WireGuard는 임베디드 인터페이스와 슈퍼 컴퓨터를 위한 범용 VPN로, 최첨단 암호화 기술을 사용하며 단순하고 빠르고 현대적인 VPN이다. IPsec보다 더 간단하며 더 빠르고, OpenVPN보다 성�

ziwon.github.io

 

https://www.wireguard.com/quickstart/

 

Quick Start - WireGuard

Quick Start You'll first want to make sure you have a decent grasp of the conceptual overview, and then install WireGuard. After that, read onwards here. Side by Side Video Before explaining the actual comands in detail, it may be extremely instructive to

www.wireguard.com

 

 

사족. 서버와 라우터의 방화벽 설정을 잘 해야 한다. 해당 포트들 오픈이 안되있으면 연결이 안됨

반응형

+ Recent posts