/ adafruit_lifx.py
adafruit_lifx.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2019 Brent Rubell for Adafruit Industries
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  """
 23  `adafruit_lifx`
 24  ================================================================================
 25  
 26  A CircuitPython/Python library for communicating with the LIFX HTTP Remote API.
 27  
 28  * Author(s): Brent Rubell for Adafruit Industries
 29  
 30  Implementation Notes
 31  --------------------
 32  
 33  **Software and Dependencies:**
 34  
 35  * Adafruit CircuitPython firmware for the supported boards:
 36    https://github.com/adafruit/circuitpython/releases
 37  
 38  * Adafruit ESP32SPI or ESP_ATcontrol library:
 39      https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI
 40      https://github.com/adafruit/Adafruit_CircuitPython_ESP_ATcontrol
 41  """
 42  
 43  __version__ = "0.0.0-auto.0"
 44  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_lifx.git"
 45  
 46  LIFX_URL = "https://api.lifx.com/v1/lights/"
 47  
 48  
 49  class LIFX:
 50      """
 51      HTTP Interface for interacting with the LIFX API
 52      """
 53  
 54      def __init__(self, wifi_manager, lifx_token):
 55          """
 56          Creates an instance of the LIFX HTTP API client.
 57          :param wifi_manager wifi_manager: WiFiManager from ESPSPI_WiFiManager/ESPAT_WiFiManager
 58          :param str lifx_token: LIFX API token (https://api.developer.lifx.com/docs/authentication)
 59          """
 60          wifi_type = str(type(wifi_manager))
 61          if "ESPSPI_WiFiManager" in wifi_type or "ESPAT_WiFiManager" in wifi_type:
 62              self._wifi = wifi_manager
 63          else:
 64              raise TypeError("This library requires a WiFiManager object.")
 65          self._lifx_token = lifx_token
 66          self._auth_header = {
 67              "Authorization": "Bearer %s" % self._lifx_token,
 68          }
 69  
 70      @staticmethod
 71      def _parse_resp(response):
 72          """Parses and returns the JSON response returned
 73          from the LIFX HTTP API.
 74          """
 75          if response.status_code == 422:
 76              raise Exception(
 77                  "Error: light(s) could not be toggled: " + response["error"]
 78              )
 79          try:
 80              for res in response.json()["results"]:
 81                  return res["status"]
 82          except KeyError:
 83              raise KeyError(response.json()["error"])
 84  
 85      # HTTP Requests
 86      def _post(self, path, data):
 87          """POST data to the LIFX API.
 88          :param str path: Formatted LIFX API URL
 89          :param json data: JSON data to POST to the LIFX API.
 90          """
 91          response = self._wifi.post(path, json=data, headers=self._auth_header)
 92          response = self._parse_resp(response)
 93          return response
 94  
 95      def _put(self, path, data):
 96          """PUT data to the LIFX API.
 97          :param str path: Formatted LIFX API URL
 98          :param json data: JSON data to PUT to the LIFX API.
 99          """
100          response = self._wifi.put(path, json=data, headers=self._auth_header)
101          response = self._parse_resp(response)
102          return response
103  
104      def _get(self, path, data):
105          """GET data from the LIFX API.
106          :param str path: Formatted LIFX API URL
107          :param json data: JSON data to GET from the LIFX API.
108          """
109          response = self._wifi.get(path, json=data, headers=self._auth_header)
110          return response.json()
111  
112      def toggle_light(self, selector, all_lights=False, duration=0):
113          """Toggles current state of LIFX light(s).
114          :param dict selector: Selector to control which lights are requested.
115          :param bool all: Toggle all lights at once. Defaults to false.
116          :param double duration: Time (in seconds) to spend performing a toggle. Defaults to 0.
117          """
118          if all_lights:
119              selector = "all"
120          data = {"duration": duration}
121          return self._post(LIFX_URL + selector + "/toggle", data)
122  
123      def move_effect(self, selector, move_direction, period, power_on):
124          """Performs a linear move effect on a light, or lights.
125          :param str move_direction: Move direction, forward or backward.
126          :param double period: Time in second per effect cycle.
127          :param bool power_on: Turn on a light before performing the move.
128          """
129          data = {"direction": move_direction, "period": period, "power_on": power_on}
130          return self._post(LIFX_URL + selector + "/effects/move", data)
131  
132      def effects_off(self, selector, power_off=False):
133          """Turns off any running effects on the selected device.
134          :param dict selector: Selector to control which lights are requested.
135          :param bool power_off: If true, the devices will also be turned off.
136          """
137          data = {"power_off", power_off}
138          return self._post(LIFX_URL + selector + "/effects/off", data)
139  
140      def set_brightness(self, selector, brightness):
141          """Sets the state of the lights within the selector.
142          :param dict selector: Selector to control which lights are requested.
143          :param double brightness: Brightness level of the light, from 0.0 to 1.0.
144          """
145          data = {"brightness": brightness}
146          return self._put(LIFX_URL + selector + "/state", data)
147  
148      def set_color(self, selector, **kwargs):
149          """Sets the state of the light's color within the selector.
150          Valid arguments: https://api.developer.lifx.com/docs/set-state
151          """
152          return self._put(LIFX_URL + selector + "/state", kwargs)
153  
154      def list_lights(self):
155          """Enumerates all the lights associated with the LIFX Cloud Account
156          """
157          response = self._wifi.get(url=LIFX_URL + "all", headers=self._auth_header)
158          resp = response.json()
159          response.close()
160          return resp