xled 0.7.0
Python library and command line interface to control Twinkly - Smart Decoration LED lights for Christmas.
License: MIT license
Requires Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2,!=3.3,!=3.4,!=3.5
Keywords: xled,twinkly

==================================================================
XLED - unofficial control of Twinkly - Smart Decoration LED lights
==================================================================

XLED is a python library and command line interface (CLI) to control
`Twinkly`_ - Smart Decoration LED lights for Christmas.

Official materials says:

    Twinkly is a LED light device that you can control via smartphone. It
    allows you to play with colouful and animated effects, or create new ones.
    Decoration lights, not suitable for household illumination.

Since its `Kickstarter project`_ in 2016 many products were introduced with
varying properties and features. Most notably products released since September
2019 are identified as Generation II. Older products are since then referred as
Generation I.

Library and CLI are free software available under MIT license.


Installation
------------

Both library and CLI tool are supported on Linux, primarily Fedora.

1. First make sure that you have `pip installed`_. E.g. for Fedora:

.. code-block::

    $ sudo dnf install python3-pip python3-wheel

2. You might want to `create and activate a virtual environment`_. E.g.:

.. code-block::

    $ mkdir -p ~/.virtualenvs
    $ python3 -m venv ~/.virtualenvs/xled
    $ source ~/.virtualenvs/xled/bin/activate

3. Install `xled from PyPI`_:

.. code-block::

   $ python3 -m pip install --upgrade xled

Usage
-----

If you have installed the project into virtual environment, activate it first. E.g.

.. code-block::

    $ source ~/.virtualenvs/xled/bin/activate

Use of the library:

.. code-block:: python

    >>> import xled
    >>> discovered_device = xled.discover.discover()
    >>> discovered_device.id
    'Twinkly_33AAFF'
    >>> control = xled.ControlInterface(discovered_device.ip_address, discovered_device.hw_address)
    >>> control.set_mode('movie')
    <ApplicationResponse [1000]>
    >>> control.get_mode()['mode']
    'movie'
    >>> control.get_device_info()['number_of_led']
    210

`Documentation for the library can be found online`_.

Use of the CLI:

.. code-block:: console

    $ xled on
    Looking for any device...
    Working on device: Twinkly_33AAFF
    Turned on.

For more commands and options see `xled --help`.


Why?
----

My first Twinkly was 105 LEDs starter light set. That was the latest available
model in 2017: TW105S-EU. As of December 2017 there are only two ways to
control lights: mobile app on Android or iOS or hardware button on the cord.

Android application didn't work as advertised on my Xiaomi Redmi 3S phone. On
first start it connected and disconnected in very fast pace (like every 1-2
seconds) to the hardware. I wasn't able to control anything at all. Later I
wanted to connect it to my local WiFi network. But popup dialog that shouldn't
have appear never did so.

Public API was `promised around Christmas 2016`_ for next season. Later update
from October 2016 it seems `API won't be available any time soon`_:

    API for external control are on our dev check list, we definitely need some
    feedback from the community to understand which could be a proper core set
    to start with.

It turned out that application uses HTTP to control lights. I ended up with
capturing network traffic and `documented this private API`_. In the end I'm
able to configure the device pretty easilly.

As of 2020 Twinkly devices can be controlled by Amazon Alexa and Google
Assistant as well. Mobile application now requires an account to operate lights
even locally. No sign of public API for local devices though. Therefore with my
second device - Twinkly 210 RGB+W Wall I keep improving this library and CLI
documentation to be able to operate my devices locally and not rely on
availability of manufacturer's servers.

References
----------

Unofficial documentation of private protocol and API is `available online`_.

There are other projects that might be more suitable for your needs:

* `Twinkly integration in Home Assistant`_
* SmartThings:

  * `Twinkly integration in SmartThings by StevenJonSmith`_
  * `Twinkly integration in SmartThings by Dameon87`_

* `TwinklyTree Binding`_ for openHAB
* `Twinkly HomeKit Hub for Mongoose OS`_ using `Twinkly library for Mongoose OS`_
* `TwinklyWPF`_ - .net 5 GUI and API library
* `ioBroker.twinkly`_ - twinkly adapter for ioBroker to communicate with the Twinkly lights
* `Twinkly.vb for HomeSeer`_
* `thingzi-logic-twinkly`_ - Twinkly lights integration for node red
* Python class to interact with generation I device and IDA Pro loader of firmware binary in `Twinkly Twinkly Little Star by F-Secure LABS`_.

Credits
---------

This package was created with Cookiecutter_ and the
`audreyr/cookiecutter-pypackage`_ project template.

.. _`Twinkly`: https://www.twinkly.com/
.. _`Kickstarter project`: https://www.kickstarter.com/projects/twinkly/twinkly-smart-decoration-for-your-christmas
.. _`available online`: https://xled-docs.readthedocs.io
.. _`documented this private API`: https://xled-docs.readthedocs.io
.. _`promised around Christmas 2016`: https://www.kickstarter.com/projects/twinkly/twinkly-smart-decoration-for-your-christmas/comments?cursor=15497325#comment-15497324
.. _`API won't be available any time soon`: https://www.kickstarter.com/projects/twinkly/twinkly-smart-decoration-for-your-christmas/comments?cursor=14619713#comment-14619712
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`documented this private API`: https://xled-docs.readthedocs.io
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
.. _`Twinkly library for Mongoose OS`: https://github.com/d4rkmen/twinkly
.. _`Twinkly HomeKit Hub for Mongoose OS`: https://github.com/d4rkmen/twinkly-homekit
.. _`TwinklyWPF`: https://github.com/MarkAlanJones/TwinklyWPF
.. _`Twinkly integration in Home Assistant`: https://www.home-assistant.io/integrations/twinkly/
.. _`ioBroker.twinkly`: https://www.npmjs.com/package/iobroker.twinkly
.. _`Twinkly.vb for HomeSeer`: https://forums.homeseer.com/forum/developer-support/scripts-plug-ins-development-and-libraries/script-plug-in-library/1348314-twinkly-vb-christmas-tree-lights-with-predefined-and-custom-animations
.. _`TwinklyTree Binding`: https://github.com/mvanhulsentop/openhab-addons/tree/twinklytree/bundles/org.openhab.binding.twinklytree
.. _`Twinkly Twinkly Little Star by F-Secure LABS`: https://labs.f-secure.com/blog/twinkly-twinkly-little-star/
.. _`Twinkly integration in SmartThings by StevenJonSmith`: https://github.com/StevenJonSmith/SmartThings
.. _`Twinkly integration in SmartThings by Dameon87`: https://github.com/Dameon87/SmartThings
.. _`thingzi-logic-twinkly`: https://www.npmjs.com/package/thingzi-logic-twinkly
.. _`pip installed`: https://packaging.python.org/guides/installing-using-linux-tools/
.. _`create and activate a virtual environment`: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments
.. _`xled from PyPI`: https://pypi.org/project/xled/
.. _`Documentation for the library can be found online`: https://xled.readthedocs.io

.. image:: https://badges.gitter.im/xled-community/chat.svg
   :alt: Join the chat at https://gitter.im/xled-community/chat
   :target: https://gitter.im/xled-community/chat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge


=======
History
=======

0.7.0 (2021-11-28)
------------------
* Major changes:

  * Add realtime UDP protocol including unit tests
  * Add several missing rest calls in ControlInterface
  * Unit test all methods in ControlInterface

* Other bugfixes and improvements:

  * Provide a short guide how to install packages from PyPI
  * Provide `python_requires` in setup.py
  * Add project URLs to metadata
  * Corrected import of security, and removed some old comments
  * Make encrypt_wifi_password work also with python3
  * More flexible parameters to set_mqtt_config
  * Enable options in set_network_mode_ap and _station
  * Enable relative values in set_brightness
  * Make firmware_update compatible with Generation II
  * Fix error in `python setup.py install` (fix #82)
  * Use generic Exception in discover module
  * On Python 2.7 ignore VCR deprecation warning
  * On Python 2.7 ignore cryptography deprecation warning
  * Fix dependencies for python 2.7
  * Don't debug log reapped devices
  * Time format as hardcoded value instead of locale specific
  * Raise an exception with a error message firmware update failed
  * Get MAC address from gestalt API call
  * Always UTF-8 decode response from JOINED event in discovery
  * Log instead of print in discovery interface and return on unknown event
  * If hw_address wasn't possible to resolve don't use None as a peer
  * Configure all loggers used by CLI with cli_log.basic_config()
  * Make response assertions less strict
  * Reformat setup py so tox tests pass

* Documentation updates:

  * Update example in README to use reflect change in API
  * Add Gitter badge
  * Update of xled and xled-docs should be done hand in hand
  * Remove Enhancement section from Contributing as there is no such thing
  * Write down support for OS, devices, python and guide to CLI
  * Rewrite README file
  * Fix documentation for set_led_movie_config

* Changes in CI/CD:

  * Run linters as GitHub action
  * Use generic python3 in black pre-commit config
  * Configure pytest to collect tests only from tests/
  * Use GitHub action for PyPI publish
  * Update URL for CI from Travis to GitHub actions
  * One more place to update supported python versions
  * Make Travis environment python again
  * Remove non-deploy section from travis.yml
  * Fix typo in travis.yml dep install
  * Ignore Flake8 error on Sphinx configuration file
  * Run pytest directly from Tox
  * Add bug report template for GitHub issues and reference it
  * Switch to token authentication for deployment to pypi through Travis

* Changes in dependencies and python versions:

  * Add 3.10 to supported Python versions
  * Update coverage from 4.4.2 to 5.5
  * Update pip from 20.2.3 to 21.1
  * Update travis.yaml: remove python 3.5 and add 3.8 and 3.9
  * Add 3.9 to supported Python versions
  * Drop Python 3.5 support
  * Drop compatibility code for Python version 3.4
  * Add Python 3.8 as a supported language
  * Update pip from 19.0.3 to 20.2.3
  * Update sphinx from 1.6.5 to 3.0.4

0.6.1 (2020-01-17)
------------------
* Make tests with tox pass again so release can be automatically deployed:

  * Add Black reformatter to tox linter envs
  * Tox config: new linters env to run Flake8
  * Tox config update: Flake8 against tests/ and setup.py as well
  * Make xled.compat pass Flake8 for F821 undefined names
  * Refactor beacon processing of seen/new peer into separate methods
  * Reformat test_control test with black
  * Make tox install test-only requires
  * Use conditional deployment to pypi with travis only from master

0.6.0 (2020-01-15)
------------------
* Drop support for python 3.4
* Explicitly specify Linux as only operating system
* Automatically refresh token if expired
* Add brightness management
* Check response is OK before trying to decode JSON from body
* Use id instead of name in discovery
* Device class representing the device
* Get network status in control interface
* Use response from alive device to check if we reached discover timeout
* Provide generator xdiscover() to return all or specific devices
* Support timeout for discovery
* When agent stops stop ping task and processing responses
* Provide close() for UDPClient and use it on DiscoveryInterface.stop()
* Do not continue receiving more data if UDP recv timeouts
* Other bugfixes and improvements:

  * Fix assertions
  * Expose HighControlInterface on package level
  * If ApplicationError is raised, store value of response attribute
  * Allow disable/enable of brightness without value change
  * Update wheel from 0.30.0 to 0.33.1
  * Update pip from 9.0.1 to 19.0.3
  * Add python 3.6 and 3.7 to Travis config

0.5.0 (2018-12-09)
------------------

* CLI to update firmware
* Example of library call and CLI usage
* Option to select device by hostname in CLI and ping in discovery
* New HighControlInterface() to aggregate and abstract low-level calls
* CLI and HighControlInterface way to set static single color
* Other bugfixes and improvements:

  * Fix typo in CLI error message
  * Print message before discovery on CLI
  * Refactor: join consecutive strings on same line
  * Print better message after device has been discovered over CLI
  * Regenerate documentation index of a package
  * Fix typo in control.set_mode() documentation
  * Return named tuple in discover.discover()
  * Use discovery and named tuple in example of library use
  * Do not assert return value in ControlInterface.set_led_movie_full()
  * Return ApplicationResponse for ControlInterface.set_led_movie_config()
  * Return ApplicationResponse for control.ControlInterface.led_reset()
  * Remove unneeded debug message from DiscoveryInterface.__init__()

0.4.0 (2018-12-03)
------------------

* Support Python 3.6 and 3.7 including tests and documentation
* Python 3 support with pyzmq >= 17.0 and Tornado 5
* Remove redundant udplib
* Other Python 3 compatibility:

  * In Python 3+ import Mapping from collections.abc
  * Python 3 compatible encoding of discovered IP and HW address and name
  * Make xled.security.xor_strings() compatible with Python 2 and 3
  * Treat PING_MESSAGE as bytes to simplify handling Python 2 and 3

* Other bugfixes and improvements:

  * Remove mention of PyPy from docs as it wasn't ever tested on it
  * Improve robustness with sending messages from agent to interface
  * Escape display of binary challenge in debug log of xled.auth
  * Ignore (usually own) PING_MESSAGE on network when handling responses

0.3.1 (2018-11-27)
------------------

* Update changelog for version 0.3.0
* Update description in setup.py to refer to CLI
* Fix JSON payload sent to server for firmware update.

0.3.0 (2018-11-27)
------------------

* CLI interface
* Discovery interface - currently works only on Python 2
* Add support for API led/movie/full and corresponding CLI upload-movie
* New Authentication mechanism - use session
* Rename authentication module from long challenge_response_auth to auth
* Change interface of ApplicationResponse to collections.Mapping
* Python files reformatted with Black
* Other bugfixes and improvements:

  * Really show ApplicationResponse status in repr() when available
  * Catch JSONDecodeError in Python 3.5+ in ApplicationResponse
  * New shortcut method ok() of ApplicationResponse
  * Make ApplicationResponse's attribute status_code @property
  * Improve error reporting during parsing of ApplicationResponse
  * If repr() of ApplicationResponse is called parse response first
  * Check status of underlying requests' Response if requested
  * Accept requests' response as attribute to class ApplicationResponse
  * Move generate_challenge to security module
  * Unit tests for control interface
  * Run unit tests on supported python versions with tox and Travis
  * Configuration for pre-commit-hooks
  * Initial pyup configuration
  * Don't run Tox on Travis on Python 3.3
  * Update coverage

0.2.1 (2018-01-02)
------------------

* Add missing MANIFEST.in
* Configure Travis for automatic deployment to PyPI

0.2.0 (2018-01-02)
------------------

* First Python control interface.

0.1.0 (2017-12-17)
------------------

* Low level control interface.