YOGYUI

광교아이파크::가스 Apple 홈킷 연동 (2) 본문

홈네트워크(IoT)/광교아이파크

광교아이파크::가스 Apple 홈킷 연동 (2)

요겨 2021. 1. 6. 11:45
반응형

[2] Homebridge 연동

1. Homebridge Plug-in 설치

homebridge 플러그인 'valve' 키워드로 검색 후 @tommrodrigues의 homebridge-web-valve 플러그인 설치

(환기 때 사용한 web-fan 플러그인 개발자, API가 유사하여 선택)

https://www.npmjs.com/package/homebridge-web-valve

 

homebridge-web-valve

Homebridge plugin for a web-based valve

www.npmjs.com

환기와 유사하게 홈브릿지 액세서리 추가

        {
            "accessory": "WebValve",
            "name": "Kitchen Gas Valve",
            "apiroute": "http://localhost:9999/gasvalve",
            "valveType": 0,
            "pollInterval": 60,
            "listener": true,
            "port": 11000,
            "manufacturer": "Bestin",
            "serial": "yogyui Kitchen Valve",
            "model": "Bestin"
        }

속성 중에 valveType은 Home 앱에 표시될 아이콘을 결정한다고 하는데 (값 범위 = 0 ~ 3), 값을 바꿔가면서 확인해보니 아이콘은 2종류가 전부인 듯 하다 (수도꼭지 / 스프링클러)

2. Flask Server Code 수정

OOP 구현 과정에서 코드 코어 부분이 상당히 수정되었다

(액세서리 추가할 것들 다 한 뒤에 Git에 한번에 업로드할 예정)

# app.py
# gas-valve 연관 부분만 발췌
import time
import requests

class Device:
    name: str = 'Device'
    init: bool = False
    state: int = 0  # mostly, 0 is OFF and 1 is ON
    state_prev: int = 0
    packet_set_state_on: str = ''
    packet_set_state_off: str = ''
    packet_get_state: str = ''
    port_listener: int = 0  # http- plugin listening port 

    def __init__(self, name: str = 'Device', **kwargs):
        self.name = name
    
    def send_response_state(self):
        pass

class GasValve(Device):
    pass
   
gas_valve = GasValve(name='Gas Valve')
gas_valve.packet_set_state_off = '02 31 02 3C 00 00 00 00 00 11'
gas_valve.packet_get_state = '02 31 00 38 00 00 00 00 00 13'
gas_valve.port_listener = 11000

def parse_control_result(chunk: bytearray):
    if header == 0x31 and chunk[2] in [0x80, 0x82]:
        dev = gas_valve
        dev.state = chunk[5]
        # notification
        if dev.state != dev.state_prev or not dev.init:
            url = "http://0.0.0.0:{}/".format(dev.port_listener)
            params = "state?value={}".format(int(dev.state == 1))
            requests.get(url + params)
            dev.init = True
        dev.state_prev = dev.state

@app.route('/gasvalve/status', methods=['GET'])
def gasvalve_get_status():
    dev = gas_valve
    obj = {
        'currentState': int(dev.state == 1)
        }
    print('Response ({}): {}'.format(dev.name, obj))
    return jsonify(obj)

@app.route('/gasvalve/setState', methods=['GET'])
def gasvalve_set_state():
    dev = gas_valve
    value = request.args.get('value', default=0, type=int)
    if value == 0:  # 닫기 명령에 대해서만 반응
        while True:
            if dev.state in [value, 2]:
                break
            sendSerialControlPacket(dev.packet_set_state_off)
            time.sleep(0.5)
            if dev.state in [value, 2]:
                break
            sendSerialControlPacket(dev.packet_get_state)
            time.sleep(0.5)
        url_resp = "http://0.0.0.0:{}/".format(dev.port_listener)
        url_resp += "state?value={}".format(int(dev.state == 1))
        requests.get(url_resp)
    return ''

다른 액세서리들과의 차이는 현재 상태에 대한 응답을 모두 

state = int(dev.state == 1)

와 같이 구현했다는 점인데, 이는 밸브의 상태가 2일 경우 '움직이는 상태'라서 이 경우는 닫힌 상태로 표현하기 위함이다

3. 액세서리 등록 확인

액세서리 등록 확인

위치를 주방으로 옮기고 이름도 적절하게 바꿔주자

 

[시리즈 링크]

광교아이파크::가스 Apple 홈킷 연동 (1)

광교아이파크::가스 Apple 홈킷 연동 (2)

광교아이파크::가스 Apple 홈킷 연동 (3)

반응형