1 """Support for Skybeacon temperature/humidity Bluetooth LE sensors."""
3 from __future__
import annotations
9 from pygatt
import BLEAddressType
10 from pygatt.backends
import Characteristic, GATTToolBackend
11 from pygatt.exceptions
import BLEError, NotConnectedError, NotificationTimeout
12 import voluptuous
as vol
15 PLATFORM_SCHEMA
as SENSOR_PLATFORM_SCHEMA,
22 EVENT_HOMEASSISTANT_STOP,
32 _LOGGER = logging.getLogger(__name__)
34 ATTR_DEVICE =
"device"
37 BLE_TEMP_HANDLE = 0x24
38 BLE_TEMP_UUID =
"0000ff92-0000-1000-8000-00805f9b34fb"
40 CONNECT_LOCK = threading.Lock()
43 DEFAULT_NAME =
"Skybeacon"
45 SKIP_HANDLE_LOOKUP =
True
47 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
49 vol.Required(CONF_MAC): cv.string,
50 vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
58 add_entities: AddEntitiesCallback,
59 discovery_info: DiscoveryInfoType |
None =
None,
61 """Set up the Skybeacon sensor."""
62 name = config.get(CONF_NAME)
63 mac = config.get(CONF_MAC)
64 _LOGGER.debug(
"Setting up")
70 def monitor_stop(_service_or_event):
71 """Stop the monitor thread."""
72 _LOGGER.debug(
"Stopping monitor for %s", name)
75 hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, monitor_stop)
80 """Representation of a Skybeacon humidity sensor."""
82 _attr_native_unit_of_measurement = PERCENTAGE
85 """Initialize a sensor."""
91 """Return the name of the sensor."""
92 return self.
_name_name
96 """Return the state of the device."""
97 return self.
monmon.data[
"humid"]
101 """Return the state attributes of the sensor."""
102 return {ATTR_DEVICE:
"SKYBEACON", ATTR_MODEL: 1}
106 """Representation of a Skybeacon temperature sensor."""
108 _attr_device_class = SensorDeviceClass.TEMPERATURE
109 _attr_native_unit_of_measurement = UnitOfTemperature.CELSIUS
112 """Initialize a sensor."""
118 """Return the name of the sensor."""
119 return self.
_name_name
123 """Return the state of the device."""
124 return self.
monmon.data[
"temp"]
128 """Return the state attributes of the sensor."""
129 return {ATTR_DEVICE:
"SKYBEACON", ATTR_MODEL: 1}
133 """Connection handling."""
136 """Construct interface object."""
137 threading.Thread.__init__(self)
142 self.
datadata = {
"temp": STATE_UNKNOWN,
"humid": STATE_UNKNOWN}
147 """Thread that keeps connection alive."""
148 cached_char = Characteristic(BLE_TEMP_UUID, BLE_TEMP_HANDLE)
149 adapter = GATTToolBackend()
152 _LOGGER.debug(
"Connecting to %s", self.
namenamename)
154 adapter.start(reset_on_start=
False)
157 device = adapter.connect(
158 self.
macmac, CONNECT_TIMEOUT, BLEAddressType.random
160 if SKIP_HANDLE_LOOKUP:
162 device._characteristics[
UUID(BLE_TEMP_UUID)] = cached_char
164 device.char_write_handle(0x1B, bytearray([255]),
False)
165 device.subscribe(BLE_TEMP_UUID, self.
_update_update)
166 _LOGGER.debug(
"Subscribed to %s", self.
namenamename)
169 device.char_read(BLE_TEMP_UUID, timeout=CONNECT_TIMEOUT)
170 self.
eventevent.wait(60)
172 except (BLEError, NotConnectedError, NotificationTimeout)
as ex:
173 _LOGGER.error(
"Exception: %s ",
str(ex))
178 """Notification callback from pygatt."""
180 "%s: %15s temperature = %-2d.%-2d, humidity = %3d",
187 self.
datadata[
"temp"] =
float(f
"{value[0]}.{value[2]}")
188 self.
datadata[
"humid"] = value[1]
191 """Signal runner to stop and join thread."""
193 self.
eventevent.set()
def _update(self, handle, value)
def __init__(self, hass, mac, name)
def __init__(self, name, mon)
def extra_state_attributes(self)
def extra_state_attributes(self)
def __init__(self, name, mon)
str|UndefinedType|None name(self)
def add_entities(account, async_add_entities, tracked)
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)