본문 바로가기
IoT

Yeelight BT 모델 무드등을 쓰기위한 튜닝 (rfkill)/ INTEL NUC J5005

by 도정진 ㅋㅋ잠자 2021. 7. 26.
728x90

안녕하세요? 

 

이라이트 블루트스 무드등을 쓰기 위해서 많은 노력을 했습니다.

그러나 아 참 이런 노력을 하기 전에 그냥 와이파이 모델을 주문했으면 완벽하게 해결되지 않았나 싶은데요.

그래도, 산 제품을 어떻게 하지 못하니, 해결을 해보겠습니다.

 

일단은 INTEL NUC J5005 에서는 BT 동작이 매우 불안전합니다. 드라이버가 제대로 동작되는게 없는 것 같아 보이네요. 그래서 일단은 하기와 같이 처리를 하기는 했습니다만, 중간 중간에 멈추는 일이 자주 발생합니다.

 

이런 문제 때문에 여러가지 짱구를 굴려보아 지금은 안정적으로 사용하고 있으나, BT 무드등만 사용하는 목적으로 BT를 사용하기 때문에 실제로 다른 BT 통신 애드온과는 호환성이 어떤지 잘 모르겠네요.

 

이력 기준으로 해결했던 글을 하기와 같이 나열하고 조금 더 수정하여 안정적으로 만드는 방법을 설명드리겠습니다.

https://www.youtube.com/watch?v=j8yV7jz4bwc&feature=youtu.be 

1. 블루투스 펌웨어 설치하기

https://blog.djjproject.com/725

상기의 방법으로 펌웨어를 설치하시면 블루투스가 동작은? 합니다.

아직 완벽한게 아닌것 같아서 hcitool 을 사용할 때 에러가 조금 있어요. 그러나 파이썬 bluepy 는 잘 동작합니다.

2. 억지로 무드등 연동하기

https://blog.djjproject.com/680

rytilahti 님 께서 만들어주신 모듈을 통해서 쉘 스크립트로 강제 연동을 해본것입니다.

이때에도 블루투스 커맨드가 실패하는 부분에서 재시도를 하는 코드를 억지로 추가하여 동작상에는 별 문제가 없으나 딜레이가 매우 심각한 문제가 있었습니다.

 

자동화를 통해서 전등이 꺼지거나 해가 under the horizon 이 되면 켜지는 자동화라 직접 컨트롤 하는 일이 없었어서 불편한 점은 없었습니다.

3. yeelight-bt 커스텀 컴포넌트 연동하기

https://blog.djjproject.com/747

커스텀 컴포넌트를 통해서 하기와 같이 완벽하게 연동이 되었습니다.

그러나 간혹 가다가 연결이 끊기는 경우가 많이 있었으며, 실제로 시간이 지나도 연결이 복구되지 않는 문제가 있었습니다.

4. 연결 문제 개선

상기 3의 경우처럼 에러가 발생하는 경우에는 어쩔 수 없이 rfkill 기능을 통해 on/off 를 하여야 하는데요. 실제로 rfkill 의 개념은 block / unblock 이 off / on 개념입니다.

실제로도 연결이 되지 않을 때 on / off 를 해주면 정상적으로 작동하였는데요.

 

일단 연결이 되지 않을 때에는 커널 로그에 하기 내용이 찍입니다. 블루투스 펌웨어 바이너리가 완벽하지 않은지 실제로 동작 중에 블루투스 칩이 죽게 되면 unexpected packet 이 오게 되어 드라이버가 거의 동작이 안되는 상태에 빠져버립니다.

[842502.820644] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820646] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820650] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820652] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820654] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820656] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820658] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820659] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820662] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820664] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820666] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820668] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842502.820675] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842506.445477] Bluetooth: hci0: command 0x200e tx timeout
[842508.461486] Bluetooth: hci0: command 0x0419 tx timeout
[842510.354572] Bluetooth: hci0: Received unexpected HCI Event 00000000
[842512.273509] Bluetooth: hci0: command 0x0419 tx timeout

이러한 부분을 해결하기 위해서는 리셋을 시키는게 맞는 방법인것으로 보여 하기 명령어를 입력 후에 다시 시도 해보면 무드등 컨트롤이 정상적으로 작동함을 알 수 있었습니다.

root@debian:~# rfkill block 0
root@debian:~# rfkill unblock 0

실제로 0번인지 아닌지 알기 위해서는 하기 위치로 이동하여 rfkill 인터페이스 상태를 봐야합니다.

root@debian:/sys/class/rfkill/rfkill0# cat name
hci0
root@debian:/sys/class/rfkill/rfkill1# cat name
phy0

실제로 장비마다 다르겠지만, 저는 0번이 블루투스, 1번이 와이파이로 보이네요. 이름은 phy0 라고 나와 있는데 속성들을 보면 wired ehternet 장비는 아닌 것 같습니다.

 

추가적으로 hci 의 경우 uart 인터페이스가 아닌 usb 인터페이스이기 때문에 따로 hciattach 과정이 필요업고 usb에 로딩된 클래스 드라이버를 통해서 bt칩과 통신하고 펌웨어 다운로드 하고 일반적인 상황이 되면 사용을 하면 되는 것입니다. 제네럴 하게 들어가 있는 hcd 커맨드 묶음이 약간 이 칩과 호환이 잘 안되는 것으로 보입니다.

root@debian:/sys/class/rfkill/rfkill1/device# dmesg | grep hci0
[    5.059837] Bluetooth: hci0: Bootloader revision 0.1 build 42 week 52 2015
[    5.060840] Bluetooth: hci0: Device revision is 2
[    5.060841] Bluetooth: hci0: Secure boot is enabled
[    5.060842] Bluetooth: hci0: OTP lock is enabled
[    5.060842] Bluetooth: hci0: API lock is enabled
[    5.060843] Bluetooth: hci0: Debug lock is disabled
[    5.060844] Bluetooth: hci0: Minimum firmware build 1 week 10 2014
[    5.064286] Bluetooth: hci0: Found device firmware: intel/ibt-17-16-1.sfi
[    6.508704] Bluetooth: hci0: Waiting for firmware download to complete
[    6.508816] Bluetooth: hci0: Firmware loaded in 1417599 usecs
[    6.508883] Bluetooth: hci0: Waiting for device to boot
[    6.521824] Bluetooth: hci0: Device booted in 12668 usecs
[    6.522033] Bluetooth: hci0: Found Intel DDC parameters: intel/ibt-17-16-1.ddc
[    6.528833] Bluetooth: hci0: Applying Intel DDC parameters completed

본래 블루투스 칩을 초기화 할때, rfkill 을 통해서 전원을 올려주고 (혹은 raw gpio 컨트롤) 

칩 정보를 읽은 다음에 해당하는 펌웨어 바이너리를 내려주면 됩니다. 음 이 펌웨어가 문제인지 특정 상황에서 복구가 안되는 문제가 있는데요.

 

제가 이 칩의 커맨드와 펌웨어를 정확하게 모르니, 어쩔 수 없이 그냥 리셋하는 것으로 만족합니다.

그러면 이 리셋 코드를 언제 넣느냐.. docker homeassistant 부팅할 때? 아니면 yeelight-bt 모듈 에서 리커버리가 돌아갈때? 이렇게 고민을 해보았습니다.

 

결국 하기와 같이 커스텀 컴포넌트를 수정하기로 했습니다.

root@debian:/opt/hass/config/custom_components/yeelight_bt# vi yeelightbt.py

def retry(ExceptionToCheck, tries=3, delay=0.1):
    """Retry calling the decorated function.

    :param ExceptionToCheck: the exception to check. may be a tuple of exceptions to
    check
    :type ExceptionToCheck: Exception or tuple
    :param tries: number of times to try (not retry) before giving up
    :type tries: int
    :param delay: initial delay between retries in seconds
    :type delay: int
    """

    def deco_retry(f):
        os.system("/usr/sbin/rfkill block 0; /usr/sbin/rfkill unblock 0;")
        @wraps(f)
        def f_retry(*args, **kwargs):
            mtries, mdelay = tries, delay
            while mtries > 0:
                try:
                    return f(*args, **kwargs)
                except ExceptionToCheck as e:
                    msg = f"Could not connect to lamp: error{e.__class__}({str(e)})"
                    if mtries > 1:
                        msg += f", Retrying in {mdelay} seconds..."
                        _LOGGER.warning(msg)
                        time.sleep(mdelay)
                        mtries -= 1
                    else:
                        _LOGGER.error(msg)
                        return False

        return f_retry  # true decorator

    return deco_retry

물론 상기 os 함수를 쓰려면, 상위에 import os 를 작성해야 사용이 가능합니다.

이렇게 간단 야매 1줄 코드 작성으로 이제는 실패하는 일이 없어졌네요. 굉장히 통신이 잘 됩니다.

 

감사합니다.

 

 

728x90

댓글1