async def test_autobrightness_restore_saved_values(mock_aiohttp, mock_never_lock): # arrange learning_storage = LearningStorage(copy.deepcopy(LEARNED_S100_G254)) # act async with Govee(API_KEY, learning_storage=learning_storage) as govee: # request devices list mock_aiohttp_responses.put( MockAiohttpResponse( json={"data": { "devices": [copy.deepcopy(JSON_DEVICE_H6163)] }}, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices", )) # call lamps, err = await govee.get_devices() # assert assert mock_aiohttp_responses.empty() assert not err assert len(lamps) == 1 assert learning_storage.read_test_data == { DUMMY_DEVICE_H6163.device: GoveeLearnedInfo( set_brightness_max=100, get_brightness_max=254, # this we learned from brightness state ) } assert learning_storage.read_call_count == 1 assert learning_storage.write_call_count == 0
async def turn_on_and_get_state(): async with Govee(API_KEY) as govee: # inject a device for testing govee._devices = {DUMMY_DEVICE_H6163.device: DUMMY_DEVICE_H6163} await govee.turn_on(DUMMY_DEVICE_H6163) # getting state to early (2s after switching) return await govee.get_states()
async def getDevices(): async with Govee(API_KEY) as govee: # inject devices for testing govee._devices = DUMMY_DEVICES # for dev in DUMMY_DEVICES: # results_per_device[dev], errors_per_device[dev] = await govee.get_state(dev) states = await govee.get_states() return states
async def get_devices(): async with Govee(API_KEY) as govee: assert govee.rate_limit_on == 5 assert govee.rate_limit_total == 100 assert govee.rate_limit_reset == 0 assert govee.rate_limit_remaining == 100 # first run uses defaults, so ping returns immediatly return await govee.get_devices()
async def test_turnonbeforebrightness_brightness0_setbrihtness0( mock_aiohttp, mock_never_lock): """ It's not possible to learn before_set_brightness_turn_on, but you can set this in the learning data. Setting brightness to 0 will still only send brightness 0. """ # arrange learning_storage = LearningStorage( copy.deepcopy(LEARNED_TURN_BEFORE_BRIGHTNESS)) # act async with Govee(API_KEY, learning_storage=learning_storage) as govee: # request devices list mock_aiohttp_responses.put( MockAiohttpResponse( json={"data": { "devices": [copy.deepcopy(JSON_DEVICE_H6163)] }}, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices", )) # call lamps, err = await govee.get_devices() # assert assert mock_aiohttp_responses.empty() assert not err assert len(lamps) == 1 # set brightness to 1 (minimum for turning on) # then it will set brightness mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json={ "code": 200, "message": "Success", "data": {} }, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/control" and kwargs["json"] == { "cmd": { "name": "brightness", "value": 0 }, "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", }, )) # call success, err = await govee.set_brightness(DUMMY_DEVICE_H6163.device, 0) # assert assert mock_aiohttp_responses.empty() assert success assert not err assert govee.device(DUMMY_DEVICE_H6163.device).power_state == False assert govee.device(DUMMY_DEVICE_H6163.device).brightness == 0
async def all_examples(api_key, your_learning_storage): ### using as async content manager async with Govee(api_key, learning_storage=your_learning_storage) as govee: # i will explain that learning_storage below. # check connection: never fails, just tells if we can connect the API. no auth needed. online = await govee.check_connection() # you may also register for an event, when api is going offline/online govee.events.online += lambda is_online: print( f"API is online: {is_online}") # you may also ask if the client was online the last time it tried to connect: last_online_state = govee.online # ping endpoint in Govee API (also uses no auth/api_key) ping_ms, err = await govee.ping() # get devices list - this is mandatory, you need to successfully get the devices first! devices, err = await govee.get_devices() # get states devices = ( await govee.get_states() ) # yes, states returns the same object containing device and state info # once you have called get_devices() once, you can get this list from cache: cache_devices = govee.devices # or a specific device from cache cache_device = govee.device( devices[0].device) # .device returns device-ID # turn a device on/off (using device-object or device-id works for all calls) success, err = await govee.turn_on(cache_device) success, err = await govee.turn_off(cache_device.device) # set brightness of a device (we scale all ranges to 0-254, Govee uses 0-100 sometimes) success, err = await govee.set_brightness(cache_device, 254) # set color temperature (2000-9000) success, err = await govee.set_color_temp(cache_device, 6000) # set color in RGB (each 0-255) red = 0 green = 0 blue = 255 success, err = await govee.set_color(cache_device, (red, green, blue)) ### rate limiting: # set requests left before the rate limiter stops us govee.rate_limit_on = 5 # 5 requests is the default current_rate_limit_on = govee.rate_limit_on # see also these properties: total = govee.rate_limit_total remaining = govee.rate_limit_remaining reset = govee.rate_limit_reset # ... or more readable: reset_seconds = govee.rate_limit_reset_seconds ### without async content manager: govee = await Govee.create(api_key, learning_storage=your_learning_storage) ping_ms, err = await govee.ping() # all commands as above # don't forget the mandatory get_devices! devices, err = await govee.get_devices() # let's turn off the light at the end success, err = await govee.turn_off(cache_device.device) await govee.close()
async def get_devices(): async with Govee(API_KEY) as govee: govee.rate_limit_on = 4 assert govee.rate_limit_on == 4 # set did work # first run uses defaults, so ping returns immediatly start = time() _, err1 = await govee.get_devices() delay1 = start - time() # second run, doesn't rate limit either _, err2 = await govee.get_devices() delay2 = start - time() return delay1, err1, delay2, err2
async def foo(api_key): # this is for testing bug #72 async with Govee(api_key) as govee: devices, err = await govee.get_devices() while True: for dev in devices: # configure each device to turn on before seting brightness dev.before_set_brightness_turn_on = True dev.learned_set_brightness_max = 100 # turn and set bright success, err = await govee.set_brightness(dev, 254) print("set") await asyncio.sleep(5)
async def validate_api_key(hass: core.HomeAssistant, user_input): """Validate the user input allows us to connect. Return info that you want to store in the config entry. """ api_key = user_input[CONF_API_KEY] async with Govee(api_key, learning_storage=GoveeNoLearningStorage()) as hub: _, error = await hub.get_devices() if error: raise CannotConnect(error) # Return info that you want to store in the config entry. return user_input
async def validate_input(hass: core.HomeAssistant, data): """Validate the user input allows us to connect. Return info that you want to store in the config entry. """ api_key = data[CONF_API_KEY] async with Govee(api_key) as hub: _, error = await hub.get_devices() if error: raise CannotConnect(error) # Return info that you want to store in the config entry. return data
async def validate_disabled_attribute_updates(hass: core.HomeAssistant, user_input): """Validate format of the ignore_device_attributes parameter string Return info that you want to store in the config entry. """ disable_str = user_input[CONF_DISABLE_ATTRIBUTE_UPDATES] if disable_str: # we have something to check, connect without API key async with Govee("", learning_storage=GoveeNoLearningStorage()) as hub: # this will throw an GoveeError if something fails hub.ignore_device_attributes(disable_str) # Return info that you want to store in the config entry. return user_input
async def get_devices(): async with Govee(API_KEY) as govee: assert govee.rate_limit_on == 5 assert govee.rate_limit_total == 100 assert govee.rate_limit_reset == 0 assert govee.rate_limit_remaining == 100 # first run uses defaults, so ping returns immediatly _, err1 = await govee.get_devices() assert mock_sleep.call_count == 0 assert govee.rate_limit_remaining == 5 assert govee.rate_limit_reset == sleep_until # second run, rate limit sleeps until the second is over _, err2 = await govee.get_devices() assert mock_sleep.call_count == 1 return err1, err2
async def some_light_commands(api_key: str, storage: GoveeAbstractLearningStorage): """We get the device list, set them to max brightness, sleep, get device state.""" async with Govee(api_key, learning_storage=storage) as govee: devices, err = await govee.get_devices() # once setting the state > 100 we learn if we need to set in the range of 0-254 or 0-100 for device in devices: success, err = await govee.set_brightness(device, 254) # we sleep to get a live status - client is blocking immediate status request after control # because they return invalid values. A calculated state is available before that. await asyncio.sleep(5) # once getting state we guess how to interpret the result. # if brightness reaches >100 one time we know we are in range of 0-254 instead of 0-100 # some devices do not support state, in this case every state is calculated from known values await govee.get_states() print(f"See {storage._filename} for leaned configuration.")
async def set_color(): async with Govee(API_KEY) as govee: # inject a device for testing govee._devices = {DUMMY_DEVICE_H6163.device: DUMMY_DEVICE_H6163} return await govee.set_color(DUMMY_DEVICE_H6163.device, (42, 43, 44))
async def getDevices(): async with Govee(API_KEY) as govee: return await govee.get_devices()
async def getDevices(): async with Govee(API_KEY) as govee: result, err = await govee.get_devices() assert not err cache = govee.devices return result, cache
async def getDevices(): async with Govee("INVALIDAPI_KEY") as govee: return await govee.get_devices()
async def test_globalOfflineIsOffConfig_off(mock_aiohttp, mock_never_lock): """ Device is on, and going offline. Computed state is configured to be OFF when offline. config_offline_is_off=True """ # arrange learning_storage = LearningStorage(copy.deepcopy(LEARNED_S100_G254)) # act async with Govee(API_KEY, learning_storage=learning_storage) as govee: # request devices list mock_aiohttp_responses.put( MockAiohttpResponse( json={"data": { "devices": [copy.deepcopy(JSON_DEVICE_H6163)] }}, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices", )) # call lamps, err = await govee.get_devices() # assert assert mock_aiohttp_responses.empty() assert not err assert len(lamps) == 1 ### set global config_offline_is_off govee.config_offline_is_off = True # turn on mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json={ "code": 200, "message": "Success", "data": {} }, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/control" and kwargs["json"] == { "cmd": { "name": "turn", "value": "on" }, "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", }, )) # call success, err = await govee.turn_on(DUMMY_DEVICE_H6163.device) # assert assert mock_aiohttp_responses.empty() assert success assert not err assert govee.device(DUMMY_DEVICE_H6163.device).power_state == True assert govee.device(DUMMY_DEVICE_H6163.device).online == True # get state - but device is offline mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json=copy.deepcopy(JSON_DEVICE_STATE_OFFLINE), check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/state" and kwargs[ "params"] == { "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", }, )) # call await govee.get_states() # assert assert mock_aiohttp_responses.empty() assert success assert not err assert govee.device(DUMMY_DEVICE_H6163.device).power_state == False assert govee.device(DUMMY_DEVICE_H6163.device).online == False
async def ping(): async with Govee(API_KEY) as govee: return await govee.ping()
async def test_autobrightness_set254_get100_get254(mock_aiohttp, mock_never_lock): # arrange learning_storage = LearningStorage(copy.deepcopy(LEARNED_NOTHING)) # act async with Govee(API_KEY, learning_storage=learning_storage) as govee: # request devices list mock_aiohttp_responses.put( MockAiohttpResponse( json={"data": { "devices": [copy.deepcopy(JSON_DEVICE_H6163)] }}, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices", )) # call lamps, err = await govee.get_devices() # assert assert mock_aiohttp_responses.empty() assert not err assert len(lamps) == 1 # set brightness to 142, which is OK for a 0-254 device mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json={ "code": 200, "message": "Success", "data": {} }, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/control" and kwargs["json"] == { "cmd": { "name": "brightness", "value": 142 }, "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", }, )) # call success, err = await govee.set_brightness(DUMMY_DEVICE_H6163.device, 142) # assert assert mock_aiohttp_responses.empty() assert success assert not err assert learning_storage.write_test_data == { DUMMY_DEVICE_H6163.device: GoveeLearnedInfo( set_brightness_max=254, # this we lerned y setting brightness get_brightness_max=None, ) } # get state # we get a state <= 100 (42 in this case), we assume get range is 0-100 and show a warning with instructions mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json={ "data": { "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", "properties": [ { "online": True }, { "powerState": "on" }, { "brightness": 42 }, { "color": { "r": 0, "b": 0, "g": 0 } }, ], }, "message": "Success", "code": 200, }, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/state" and kwargs[ "params"] == { "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163" }, )) # call states = await govee.get_states() # assert assert mock_aiohttp_responses.empty() assert states[0].source == "api" assert states[0].brightness == 42 * 254 // 100 assert learning_storage.write_test_data == { DUMMY_DEVICE_H6163.device: GoveeLearnedInfo( set_brightness_max=254, get_brightness_max= 100, # we assume this because we got no brightness state > 100 ) } # get state # we get a state > 100 (142 in this case), now we know the range is 0-254 mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json={ "data": { "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", "properties": [ { "online": True }, { "powerState": "on" }, { "brightness": 142 }, { "color": { "r": 0, "b": 0, "g": 0 } }, ], }, "message": "Success", "code": 200, }, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/state" and kwargs[ "params"] == { "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163" }, )) # call states = await govee.get_states() # assert assert mock_aiohttp_responses.empty() assert states[0].source == "api" assert states[0].brightness == 142 assert learning_storage.write_test_data == { DUMMY_DEVICE_H6163.device: GoveeLearnedInfo( set_brightness_max=254, get_brightness_max=254, ) }
async def test_autobrightness_set100_get254(mock_aiohttp, mock_never_lock): # arrange learning_storage = LearningStorage(copy.deepcopy(LEARNED_NOTHING)) # act async with Govee(API_KEY, learning_storage=learning_storage) as govee: # request devices list mock_aiohttp_responses.put( MockAiohttpResponse( json={"data": { "devices": [copy.deepcopy(JSON_DEVICE_H6163)] }}, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices", )) # call lamps, err = await govee.get_devices() # assert assert mock_aiohttp_responses.empty() assert not err assert len(lamps) == 1 # set brightness to 142, and fail because we set > 100 mock_aiohttp_responses.put( MockAiohttpResponse( status=400, text="Unsupported Cmd Value", check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/control" and kwargs["json"] == { "cmd": { "name": "brightness", "value": 142 }, "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", }, )) # then set brightness to 55 (142 * 100 // 254), with success mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json={ "code": 200, "message": "Success", "data": {} }, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/control" and kwargs["json"] == { "cmd": { "name": "brightness", "value": 55 }, "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", }, )) # call success, err = await govee.set_brightness(DUMMY_DEVICE_H6163.device, 142) # assert assert mock_aiohttp_responses.empty() assert success assert not err assert learning_storage.write_test_data == { DUMMY_DEVICE_H6163.device: GoveeLearnedInfo( set_brightness_max=100, # this we lerned y setting brightness get_brightness_max=None, ) } # get state # state returns a brightness of 142, we learn returning state is 0-254 mock_aiohttp_responses.put( MockAiohttpResponse( status=200, json={ "data": { "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163", "properties": [ { "online": True }, { "powerState": "on" }, { "brightness": 142 }, { "color": { "r": 0, "b": 0, "g": 0 } }, ], }, "message": "Success", "code": 200, }, check_kwargs=lambda kwargs: kwargs["url"] == "https://developer-api.govee.com/v1/devices/state" and kwargs[ "params"] == { "device": "40:83:FF:FF:FF:FF:FF:FF", "model": "H6163" }, )) # call states = await govee.get_states() # assert assert mock_aiohttp_responses.empty() assert states[0].source == "api" assert states[0].brightness == 142 assert learning_storage.write_test_data == { DUMMY_DEVICE_H6163.device: GoveeLearnedInfo( set_brightness_max=100, get_brightness_max=254, # this we learned from brightness state ) }
async def turn_on(): async with Govee(API_KEY) as govee: # inject a device for testing govee._devices = {DUMMY_DEVICE_H6163.device: DUMMY_DEVICE_H6163} return await govee.turn_on(DUMMY_DEVICE_H6163)
async def turn_off(): async with Govee(API_KEY) as govee: # inject a device for testing govee._devices = {DUMMY_DEVICE_H6163.device: DUMMY_DEVICE_H6163} # use device address here return await govee.turn_off(DUMMY_DEVICE_H6163.device)
async def set_brightness(): async with Govee(API_KEY) as govee: # inject a device for testing govee._devices = {DUMMY_DEVICE_H6163.device: DUMMY_DEVICE_H6163} return await govee.set_brightness(DUMMY_DEVICE_H6163, brightness)
async def set_brightness(): async with Govee(API_KEY) as govee: # inject a device for testing govee._devices = {DUMMY_DEVICE_H6163.device: DUMMY_DEVICE_H6163} success, err = await govee.set_brightness(DUMMY_DEVICE_H6163.device, 42) return success, err, govee.devices