diff --git a/README.md b/README.md index 1a346390aec33ec19f98ecd889ace07c1896eb5a..5a84cdb3e06de8327a991c14b4c639a449d2dee3 100644 --- a/README.md +++ b/README.md @@ -8,3 +8,27 @@ It is written in Python 3, originally for use with [Home Assistant](https://www. # Status This is currently pre-alpha status. It is not usable. + +# Usage + +## Scanning for Turn Touch devices + +```python +import turntouch + +# Example 1: Find all devices +devices = turntouch.scan() + +# Example 2: Find just one device +device = turntouch.scan(only_one=True)[0] + +# Example 3: Extend scan timeout to 60 seconds (default is 10) +devices = turntouch.scan(timeout=60) +``` + +`turntouch.scan()` returns a list of `turntouch.TurnTouch` objects. + +## Interacting with a Turn Touch device + +`turntouch.TurnTouch` is a subclass of +[`bluepy.btle.Peripheral`](http://ianharvey.github.io/bluepy-doc/peripheral.html). diff --git a/turntouch/__init__.py b/turntouch/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..791d2e38489afce1161f593e65cda660966f7c39 --- /dev/null +++ b/turntouch/__init__.py @@ -0,0 +1,65 @@ +""" Python library for the Turn Touch bluetooth smart home remote.""" +import logging +from bluepy import btle +from typing import List + + +TT_DEVICE_NAME = 'Turn Touch Remote' +TT_SHORT_DEVICE_NAME = 'Turn Touch Rem' +BLE_SHORT_DEVICE_NAME = 0x08 +BLE_COMPLETE_DEVICE_NAME = 0x09 +logger = logging.getLogger('TurnTouch') + + +class DeviceFoundException(Exception): + """Exception thrown when a device is found to abort further scanning.""" + pass + + +class ScanDelegate(btle.DefaultDelegate): + """Handle callbacks for devices discovered by a BLE scan.""" + only_one = False + + def __init__(self, only_one=False, *args, **kwargs): + self.only_one = only_one + super(ScanDelegate, self).__init__(*args, **kwargs) + + def handleDiscovery(self, device, is_new_device, is_new_data): + """When a Turn Touch device is discovered, log a message. + If only searching for one device, short-circuit the scan by raising + a DeviceFoundException once we've found a Turn Touch device.""" + if is_new_device and is_turn_touch(device): + logger.info("Discovered device {address}".format( + address=device.addr)) + if self.only_one: + raise DeviceFoundException() + + +class TurnTouch(btle.Peripheral): + """A Turn Touch smart home remote.""" + pass + + +def is_turn_touch(device: btle.ScanEntry) -> bool: + """Determine whether a device found by btle.Scanner is a Turn Touch.""" + short_name = device.getValueText(BLE_SHORT_DEVICE_NAME) + name = device.getValueText(BLE_COMPLETE_DEVICE_NAME) + return (name == TT_DEVICE_NAME or short_name == TT_SHORT_DEVICE_NAME) + + +def scan(device_index: int = 0, + timeout: float = 10, + only_one: bool = False) -> List[TurnTouch]: + """Scan for Turn Touch devices. + :param device_index int: Index of the bluetooth device (eg. 0 for hci0) + :param timeout float: Scanning timeout, in seconds + :param only_one float: Stop scanning after one Turn Touch is found + :return list: Found TurnTouch devices""" + scanner = btle.Scanner(device_index) + try: + scanner.withDelegate(ScanDelegate(only_one)).scan(timeout) + except DeviceFoundException: + pass + finally: + return [TurnTouch(device) for device in scanner.scanned.values() + if is_turn_touch(device)]