Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Govee LED strips #40

Open
amaciuc opened this issue Sep 29, 2023 · 3 comments
Open

Support for Govee LED strips #40

amaciuc opened this issue Sep 29, 2023 · 3 comments
Labels
enhancement New feature or request

Comments

@amaciuc
Copy link

amaciuc commented Sep 29, 2023

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Would there be a chance to bring support for BLE Govee LED RGB strips ?
I own some strips with product model H6159, but there are many other models of strips with BLE.

Describe the solution you'd like
A clear and concise description of what you want to happen.

Additional context
Add any other context or screenshots about the feature request here.

@amaciuc amaciuc added the enhancement New feature or request label Sep 29, 2023
@amaciuc
Copy link
Author

amaciuc commented Oct 2, 2023

I think it has more sense this issue to be moved in govee-ble project.

I found on github a project where it has been implemented a library by using reverse engineering to control BLE RGB light bulb from Govee. It is using pygatt python library in order to interact with BLE adapter.

I gave it a chance to interact with H6159 and H6109 RGB LED strips (From what I can notice, it has support also for white control. I couldn't test it) and surprising, it works pretty well. That leads me to think that this project can support many others BLE LEDs devices from Govee.

I used an ASUS UB-BT500 BLE adapter in order to communicate with the devices.

I own 4 RGB LED strips: 3 strips with model H6159 and 1 strip H6109.

The github project offers a python script for testing. I made the following tests:

  • changing colors and brightness by running the script for each strip. I changed a little the testing script where I put the main functionality into an infinite loop (to test also the reliability of connection):
import time

from govee_btled import BluetoothLED, ConnectionTimeout

try:
    # Replace this with your LED's MAC address
    # led = BluetoothLED('A4:C1:38:47:95:79') # bedroom - short one
    led = BluetoothLED('A4:C1:38:9C:76:A0') # bedroom - long one
    # led = BluetoothLED('A4:C1:38:A6:3B:77') # living - short one
    # led = BluetoothLED('A4:C1:38:A6:AD:AC') # living - long one

    print('Switching on LED')
    led.set_state(True)
    time.sleep(.5)
    while True:
        print('Changing colors in RGB')
        for color in ['red', 'green', 'blue', 'purple', 'yellow', 'cyan', 'orange', 'white']:
            print(f'[*] {color}')
            led.set_color(color)
            time.sleep(.5)
        
        print('Changing brightness')
        for i in range(5+1):
            val = i/5
            print(f'[*] {int(val*100):03d}%')
            led.set_brightness(val)
            time.sleep(.5)
    
    # print('Changing colors in white-mode')
    # for i in range(-20, 20+1):
    #     val = i/20
    #     print(f'[*] {abs(int(val*100)):03d}% {"warm" if val <= 0 else "cold"} white')
    #     led.set_color_white(val)
    #     time.sleep(.2)
    
    # print('Switching off LED')
    # led.set_state(False)
    
except ConnectionTimeout as err:
    print(err)
except KeyboardInterrupt:
    print('Switching off LED')
    led.set_state(False)
    print('^C')
  • changing colors and brightness into a script where all 4 strips are connected & controlled simultaneously on threads:
import time

from govee_btled import BluetoothLED, ConnectionTimeout
from pygatt import exceptions as pygatt_e
import logging
from threading import Thread, current_thread
import time

def thread_led(mac_add):
    try:
        print(f'[{mac_add}] Connecting ...')
        led = BluetoothLED(mac_add)
        time.sleep(.5)

        print(f'[{mac_add}] Switching on LED')
        led.set_state(True)
        time.sleep(.5)

        th = current_thread()
        th.alive = True

        while th.alive:
            print(f'[{mac_add}] Changing colors in RGB')
            for color in ['red', 'green', 'blue', 'purple', 'yellow', 'cyan', 'orange', 'white']:
                print(f'[{mac_add}] [*] {color}')
                led.set_color(color)
                time.sleep(.5)
            
            print(f'[{mac_add}] Changing brightness')
            for i in range(5+1):
                val = i/5
                print(f'[{mac_add}] [*] {int(val*100):03d}%')
                led.set_brightness(val)
                time.sleep(.5)

        if not th.alive:
            print(f'[{mac_add}] Switching off LED')
            led.set_state(False)

    except ConnectionTimeout as err:
        print(f'[{mac_add}] {err}')
        
        # My LEDs don't have while mode #
        # print('Changing colors in white-mode')
        # for i in range(-20, 20+1):
        #     val = i/20
        #     print(f'[*] {abs(int(val*100)):03d}% {"warm" if val <= 0 else "cold"} white')
        #     led.set_color_white(val)
        #     time.sleep(.2)


# ---------------------- #
def main ():
    # BT lib is logging through log lib. Uncomment it if you want BT cmds #
    # logging.basicConfig(format="%(asctime)s: %(message)s", level=logging.INFO,
    #                     datefmt="%H:%M:%S")

    mac_adds_list = ['A4:C1:38:47:95:79', 'A4:C1:38:9C:76:A0', 'A4:C1:38:A6:3B:77', 'A4:C1:38:A6:AD:AC']
    # mac_adds_list = ['A4:C1:38:47:95:79', 'A4:C1:38:9C:76:A0']
    threads_list = []

    try:
        print("Creating threads ...")
        for mac in mac_adds_list:
            th = Thread(target = thread_led, args=(mac,))
            threads_list.append(th)

        print("Starting threads ...")
        for th in threads_list:
            th.start()

        print("Waiting to finish ...")
        for th in threads_list:
            th.join()
    except KeyboardInterrupt:
        print("Keyboard interrupt received. Stopping threads ...")
        for th in threads_list:
            th.alive = False
            th.join()


if __name__ == "__main__":
    main()

In this situation, I almost can say that it works, but there are some issues. I am not sure that this test on threads is so relevant for integration, I thought it maybe helps to see if USB adapter is reliable with multiple connection in the same time.

In all my tests I have monitored also the bluetooth events by using bluetoothctl. When I ran that script with 4 strips, the connections haven't established with success all the time. Sometimes only 3 connections have been established. Once a connection is established, I noticed that it is reliable. If a try a re connection, the pygatt lib is resetting the BLE adapter (I found that in the start() method from GATTToolBackend class of pygatt lib) and all the other established connection will be dead, therefore this problem could be from a lower level (not quite from this wrapper). As I mentioned above, I am not sure that this test is relevant. If it raises suspicions, I will try to deep into it.

As a conclusion, I found this python wrapper a robust one and it works well so far.

@bdraco, what do you think?

@bdraco
Copy link
Member

bdraco commented Oct 2, 2023

@amaciuc
Copy link
Author

amaciuc commented Oct 2, 2023

How fast you found it 😃
Around 2 weeks ago I had searched after an alternative to integrate Govee in hassio through BLE.

Anyway, I installed it and it works fine for the moment.

I think you can close it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants