This is a library and tooling for Nanoleaf products.
The API is documented by Nanoleaf.
The goal is to provide a minimal thin layer to use these devices in Python,
with the help of the module requests.
The class NanoleafZeroconf helps to print device information
when discovered with the Python module zeroconf.
It can be integrated in an application as following:
import zeroconf
with zeroconf.Zeroconf() as zc:
zc.add_service_listener(NanoleafZeroconf.SERVICE, NanoleafZeroconf())Or it can be simply used as a tool without any argument:
./nanoleaf.py
The output includes the device name, the IP address with TCP port, the hardware model and the firmware version.
The Nanoleaf REST API is using a token in each HTTP request in order to authenticate a user of the device.
In order to get a new token, the device must be set in pairing state by holding the on/off button during 5-7 seconds. When the controller lights start flashing, a token can be requested within 30 seconds:
./nanoleaf.py 192.168.1.128
A token can be revoked by using the sign "minus" as a prefix:
./nanoleaf.py 192.168.1.128 -myc0mpl1c4tetok3n
When specifying the token without "minus" on the command line, some information is queried and the light is flashing:
./nanoleaf.py 192.168.1.128 myc0mpl1c4tetok3n
The main class of the library is Nanoleaf and requires two arguments:
- Target location (i.e. IP address and TCP port separated by a colon). If no port is specified, the default port is assumed.
- Authentication token (none when requesting one).
Note: the special methods __eq__ and __repr__ are implemented.
Once initialized, the Nanoleaf instance will use
a single session for all requests.
An exception is raised if an error occurs.
The API requests are implemented in more or less specialized class methods. Some methods are for exactly one specific request, while other methods are flexible thanks to some parameters:
- The methods
getandputare fully generic and called by other ones. - The methods
query,setandupdateare a bit more specialized for color states. They are used to implement some properties. - The method
identifyis only for flashing lights.
Most API endpoints are managed as properties:
poweris a boolean read/write property to manage on/off state.nanoleaf.power = True
color_modeis the read-only current mode. Its value is changed when setting other properties.ct,hue,satandbri(orbrightness) can be updated with the operators=,+=and-=. These properties have 3 members:min,maxandvaluewhich is implicitly returned when the property is converted asint.nanoleaf.hue += 300 print("hue: %d (max: %d)" % (nanoleaf.hue, nanoleaf.hue.max))
brightnessfading can be specified in seconds if assigned with a tuple(value, duration).nanoleaf.brightness = (50, 3)
effectsis the read-only list of available effects.effectis the current effect.nanoleaf.effect = nanoleaf.effects[3]
The
orientationof the controller is in counter clockwise degrees.
Some high-level events may be received slowly
by providing a callback function to the method listen_events.
The event messaging uses a Server-Sent Events (SSE) stream,
so it requires a dedicated Python module for receiving:
either sseclient or sseclient-py.
It is recommended to receive events in a daemon thread:
from threading import Thread
def print_event(event, nanoleaf, user_data):
print(event)
Thread(daemon=True, target=nanoleaf.listen_events,
args=(list(nanoleaf.EventType), print_event)).start()There are 4 types of events managed by this method:
EventType.STATEforEventState.EventType.LAYOUTforEventLayout.EventType.EFFECT.EventType.TOUCHforEventGesture.
A fifth type, EventTouch, is a low-level touch event type
which may be received fastly (with low latency)
by providing a callback function to the method listen_touch_events.
The touch events stream must be open before calling listen_events.
This condition can be checked with touch_events.is_open:
Thread(daemon=True, target=nanoleaf.listen_touch_events,
args=(print_event,)).start()
while not nanoleaf.touch_events.is_open():
time.sleep(0.1)