diff --git a/adafruit_ble/services/magic_light.py b/adafruit_ble/services/magic_light.py new file mode 100644 index 0000000..b4eb4c3 --- /dev/null +++ b/adafruit_ble/services/magic_light.py @@ -0,0 +1,90 @@ +# The MIT License (MIT) +# +# Copyright (c) 2019 Scott Shawcroft for Adafruit Industries +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +""" +:py:mod:`~adafruit_ble.services.magic_light` +==================================================== + +This module provides Services available on a Magic Light, BLE RGB light bulb. + +""" + +from . import Service +from ..uuid import VendorUUID +from ..characteristics import Characteristic + +__version__ = "0.0.0-auto.0" + +class MagicLightService(Service): + """Service for controlling a Magic Light RGB bulb.""" + + # These UUIDs actually use the standard base UUID even though they aren't standard. + uuid = VendorUUID("0000ffe5-0000-1000-8000-00805f9b34fb") + + _control = Characteristic(uuid=VendorUUID("0000ffe9-0000-1000-8000-00805f9b34fb"), max_length=7) + + def __init__(self, service=None): + super().__init__(service=service) + self._color = 0xffffff + self._buf = bytearray(7) + self._buf[0] = 0x56 + self._buf[6] = 0xaa + self._brightness = 1.0 + + def __getitem__(self, index): + if index > 0: + raise IndexError() + return self._color + + def __setitem__(self, index, value): + if index > 0: + raise IndexError() + if isinstance(value, int): + r = (value >> 16) & 0xff + g = (value >> 8) & 0xff + b = value & 0xff + else: + r, g, b = value + self._buf[1] = r + self._buf[2] = g + self._buf[3] = b + self._buf[4] = 0x00 + self._buf[5] = 0xf0 + self._control = self._buf + self._color = value + + def __len__(self): + return 1 + + # Brightness doesn't preserve the color so comment it out for now. There are many other + # characteristics to try that may. + # @property + # def brightness(self): + # return self._brightness + # + # @brightness.setter + # def brightness(self, value): + # for i in range(3): + # self._buf[i + 1] = 0x00 + # self._buf[4] = int(0xff * value) + # self._buf[5] = 0x0f + # self._control = self._buf + # self._brightness = value diff --git a/examples/ble_magic_light.py b/examples/ble_magic_light.py new file mode 100644 index 0000000..2666466 --- /dev/null +++ b/examples/ble_magic_light.py @@ -0,0 +1,53 @@ +"""This demo connects to a magic light and has it do a color wheel.""" +import adafruit_ble +import _bleio + +from adafruit_ble.advertising.standard import ProvideServicesAdvertisement +from adafruit_ble.services.magic_light import MagicLightService + +def find_connection(): + for connection in radio.connections: + if MagicLightService not in connection: + continue + return connection, connection[MagicLightService] + return None, None + +# Start advertising before messing with the display so that we can connect immediately. +radio = adafruit_ble.BLERadio() + +def wheel(pos): + # Input a value 0 to 255 to get a color value. + # The colours are a transition r - g - b - back to r. + if pos < 0 or pos > 255: + return (0, 0, 0) + if pos < 85: + return (255 - pos * 3, pos * 3, 0) + if pos < 170: + pos -= 85 + return (0, 255 - pos * 3, pos * 3) + pos -= 170 + return (pos * 3, 0, 255 - pos * 3) + +active_connection, pixels = find_connection() +current_notification = None +app_icon_file = None +while True: + if not active_connection: + print("Scanning for Magic Light") + for scan in radio.start_scan(ProvideServicesAdvertisement): + if MagicLightService in scan.services: + active_connection = radio.connect(scan) + try: + pixels = active_connection[MagicLightService] + except _bleio.ConnectionError: + print("disconnected") + continue + break + radio.stop_scan() + + i = 0 + while active_connection.connected: + pixels[0] = wheel(i % 256) + i += 1 + + active_connection = None