Skip to content

Commit

Permalink
pass bledevice to Lamp instead of mac
Browse files Browse the repository at this point in the history
  • Loading branch information
hcoohb committed Aug 6, 2022
1 parent f837630 commit c6a84f9
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 30 deletions.
18 changes: 14 additions & 4 deletions custom_components/yeelight_bt/config_flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from homeassistant.const import CONF_NAME, CONF_MAC
import voluptuous as vol
from homeassistant.helpers import device_registry as dr
from homeassistant.components import bluetooth

from .const import DOMAIN, CONF_ENTRY_METHOD, CONF_ENTRY_SCAN, CONF_ENTRY_MANUAL

Expand Down Expand Up @@ -49,17 +50,26 @@ async def async_step_scan(self, user_input=None):
errors = {}
if user_input is None:
return self.async_show_form(step_id="scan")
_LOGGER.debug("Starting a scan for Yeelight Bt devices")
scanner = bluetooth.async_get_scanner(self.hass)
_LOGGER.debug("Preparing for a scan")
# first we check if scanner from HA bluetooth is enabled
try:
devices = await discover_yeelight_lamps()
devs=scanner.discovered_devices # raises Attribute errors if bluetooth not configured
_LOGGER.debug(f"Using HA scanner {scanner}")
except AttributeError:
scanner = None
_LOGGER.debug(f"Using bleak scanner directly")
try:
_LOGGER.debug("Starting a scan for Yeelight Bt devices")
ble_devices = await discover_yeelight_lamps(scanner)
except BleakError as err:
_LOGGER.error(f"Bluetooth connection error while trying to scan: {err}")
errors["base"] = "BleakError"
return self.async_show_form(step_id="scan", errors=errors)

if not devices:
if not ble_devices:
return self.async_abort(reason="no_devices_found")
self.devices = [f"{dev['mac']} ({dev['model']})" for dev in devices]
self.devices = [f"{dev['ble_device'].address} ({dev['model']})" for dev in ble_devices]
# TODO: filter existing devices ?

return await self.async_step_device()
Expand Down
27 changes: 22 additions & 5 deletions custom_components/yeelight_bt/light.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
import logging
import asyncio

from homeassistant.components import bluetooth
from homeassistant.components.bluetooth import (
DOMAIN as DOMAIN_BT
)
import homeassistant.helpers.config_validation as cv
import voluptuous as vol
from homeassistant.const import CONF_NAME, CONF_MAC, EVENT_HOMEASSISTANT_STOP
Expand Down Expand Up @@ -30,7 +34,7 @@
color_RGB_to_hs,
)

from .yeelightbt import Lamp, MODEL_CANDELA, BleakError
from .yeelightbt import Lamp, MODEL_CANDELA, BleakError, find_device_by_address

PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
{
Expand Down Expand Up @@ -67,17 +71,30 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
)
name = config_entry.data.get(CONF_NAME) or DOMAIN
mac = config_entry.data.get(CONF_MAC)
entity = YeelightBT(name, mac)
address = mac

# try to get ble_device using HA scanner first
ble_device = bluetooth.async_ble_device_from_address(hass, address.upper())
_LOGGER.debug(f"BLE device through HA bt: {ble_device}")
if ble_device is None:
# if bluetooth not enabled, we get ble_device from bleak directly
ble_device = await find_device_by_address(address.upper())
_LOGGER.debug(f"BLE device through bleak directly: {ble_device}")
if not ble_device:
raise ConfigEntryNotReady(
f"Could not find Yeelight with address {address}"
)
entity = YeelightBT(name, ble_device)
async_add_entities([entity])


class YeelightBT(LightEntity):
"""Represenation of a light."""

def __init__(self, name, mac):
def __init__(self, name, ble_device):
"""Initialize the light."""
self._name = name
self._mac = mac
self._mac = ble_device.address
self.entity_id = generate_entity_id(ENTITY_ID_FORMAT, self._name, [])
self._is_on = None
self._rgb = None
Expand All @@ -88,7 +105,7 @@ def __init__(self, name, mac):
self._available = False

_LOGGER.info(f"Initializing YeelightBT Entity: {self.name}, {self._mac}")
self._dev = Lamp(self._mac)
self._dev = Lamp(ble_device)
self._dev.add_callback_on_state_changed(self._status_cb)
self._prop_min_max = self._dev.get_prop_min_max()
self._min_mireds = kelvin_to_mired(
Expand Down
4 changes: 2 additions & 2 deletions custom_components/yeelight_bt/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"config_flow": true,
"documentation": "https://github.com/hcoohb/hass-yeelightbt",
"issue_tracker": "https://github.com/hcoohb/hass-yeelightbt/issues",
"dependencies": [],
"codeowners": ["@hcoohb"],
"requirements": ["bleak>=0.14.3"],
"dependencies": ["bluetooth"],
"requirements": ["bleak>=0.15.0"],
"version": "1.0.1",
"iot_class": "local_polling",
"loggers": ["bleak"]
Expand Down
64 changes: 46 additions & 18 deletions custom_components/yeelight_bt/yeelightbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

# 3rd party imports
from bleak import BleakClient, BleakError
from bleak.backends.device import BLEDevice

NOTIFY_UUID = "8f65073d-9f57-4aaa-afea-397d19d5bbeb"
CONTROL_UUID = "aa7d3f34-2d4f-41e0-807f-52fbf8cf7443"
Expand Down Expand Up @@ -60,10 +61,11 @@ class Lamp:
MODE_WHITE = 0x02
MODE_FLOW = 0x03

def __init__(self, mac_address):
_LOGGER.debug(f"Initializing Yeelight Lamp {mac_address}")
self._client = BleakClient(mac_address, timeout=10)
self._mac = mac_address
def __init__(self, ble_device: BLEDevice):
self._client: BleakClient | None = None
self._ble_device = ble_device
self._mac = self._ble_device.address
_LOGGER.debug(f"Initializing Yeelight Lamp {self._ble_device.name} ({self._mac})")
self._is_on = False
self._mode = None
self._rgb = None
Expand Down Expand Up @@ -124,9 +126,12 @@ async def connect(self, num_tries=3):
try:
if i>0:
_LOGGER.debug(f"Connect retry {i}")
await self.disconnect()
self._client = BleakClient(self._mac, timeout=10)
await self._client.connect()
if self._client:
await self.disconnect()
self._client = BleakClient(self._ble_device)
_LOGGER.debug(f"Connecting now:...")
await self._client.connect(timeout=10)
_LOGGER.debug(f"Connected yeah")
self._conn = Conn.UNPAIRED
_LOGGER.debug(f"Connected: {self._client.is_connected}")
self._client.set_disconnected_callback(self.diconnected_cb)
Expand Down Expand Up @@ -371,22 +376,29 @@ def notification_handler(self, cHandle, data):
_LOGGER.info(f"Lamp {self._mac} exposes serial:{self.serial}")


async def discover_yeelight_lamps():
async def find_device_by_address(address: str, timeout:float=20.0):
from bleak import BleakScanner
return await BleakScanner.find_device_by_address(address.upper(), timeout=timeout)


async def discover_yeelight_lamps(scanner = None):
"""Scanning feature
Scan the BLE neighborhood for an Yeelight lamp
This method requires the script to be launched as root
Returns the list of nearby lamps
"""
lamp_list = []
from bleak import BleakScanner
if scanner is None:
from bleak import BleakScanner
scanner = BleakScanner

devices = await BleakScanner.discover()
devices = await scanner.discover()
for d in devices:
if d.name.startswith("XMCTD"):
lamp_list.append({"mac": d.address, "model": MODEL_BEDSIDE})
lamp_list.append({"ble_device":d, "model": MODEL_BEDSIDE})
_LOGGER.info(f"found {MODEL_BEDSIDE} with mac: {d.address}, details:{d.details}")
if "yeelight_ms" in d.name:
lamp_list.append({"mac": d.address, "model": MODEL_CANDELA})
lamp_list.append({"ble_device":d, "model": MODEL_CANDELA})
_LOGGER.info(f"found {MODEL_CANDELA} with mac: {d.address}, details:{d.details}")
return lamp_list

Expand All @@ -404,14 +416,30 @@ async def discover_yeelight_lamps():
# start discovery:
# lamp_list = asyncio.run(discover_yeelight_lamps())
# _LOGGER.info("YEELIGHT_BT scanning ends")
lamp_list = [{"mac":"F8:24:41:E6:3E:39", "model":MODEL_BEDSIDE}]

# now try to connect to the lamp
if not lamp_list:
exit
# from bleak import BleakScanner
# device = asyncio.run( BleakScanner.find_device_by_address("F8:24:41:E6:3E:39", timeout=20.0))
# print("DEVICE:")
# print(device)
# print("DEVICE END")
# lamp_list = [device]

# # now try to connect to the lamp
# if not lamp_list:
# exit

async def test_light():
yee = Lamp(lamp_list[0]["mac"])



from bleak import BleakScanner
device = await find_device_by_address("F8:24:41:E6:3E:39")
print("DEVICE:")
print(device)
print("DEVICE END")
lamp_list = [{"ble_device": device, "model": MODEL_BEDSIDE}]


yee = Lamp(lamp_list[0]["ble_device"])
await yee.connect()
await asyncio.sleep(2.0)
await yee.turn_on()
Expand Down
2 changes: 1 addition & 1 deletion hacs.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "Yeelight bluetooth",
"render_readme": true,
"homeassistant": "0.109.0"
"homeassistant": "2022.8.0"
}

0 comments on commit c6a84f9

Please # to comment.