light.tuya#

Description#

Controls Tuya-based Wi-Fi light bulbs (Smart Life / Tuya Smart compatible devices) directly over the LAN, with no cloud dependency, through tinytuya.

Each device needs its IP address, device ID and local key. The easiest way to collect them is through the tinytuya wizard:

$ python -m tinytuya wizard

which requires the API credentials of a project created on the Tuya IoT platform and linked to your Smart Life/Tuya Smart app account. It generates a devices.json file that can be passed directly to this plugin through the devices_file configuration option. The cloud credentials are only needed for the initial keys extraction - all the control operations are performed locally.

Configuration#

light.tuya:
  # [Optional]
  # Static list of devices. It can either be a list of
  # dictionaries in the format
  # ``{"name": "...", "id": "...", "ip": "...", "key": "...",
  # "version": 3.x}`` (the same format generated by the tinytuya
  # wizard), or a ``name -> device info`` mapping. If not specified,
  # the devices will be loaded from ``devices_file`` (if provided and
  # it exists), or from the first file that exists among the default
  # locations (``~/.config/platypush/devices.json``).
  # devices:   # type=Iterable[dict] | Mapping[str, dict] | None

  # [Optional]
  # Optional ``group name -> [light names/IDs]`` mapping,
  # used to control multiple lights at once.
  # groups:   # type=Mapping[str, Iterable[str]] | None

  # [Optional]
  # Path to a ``devices.json`` file generated by the
  # tinytuya wizard.
  # devices_file:   # type=str | None

  # [Optional]
  # How often the plugin should poll the devices
  # for status updates and emit
  # `LightStatusChangeEvent <https://docs.platypush.tech/platypush/events/light.html#platypush.message.event.light.LightStatusChangeEvent>`_
  # events (default: 20 seconds). Set to 0/None to disable polling.
  # poll_interval: 20.0  # type=float | None

  # [Optional]
  # Timeout for the connection to the devices
  # (default: 5 seconds).
  # connect_timeout: 5.0  # type=float

  # [Optional]
  # How long we should wait for any running
  # threads/processes to stop before exiting (default: 5 seconds).
  # stop_timeout: 5  # type=float | None

  # [Optional]
  # If set to True then the plugin will not monitor
  # for new events. This is useful if you want to run a plugin in
  # stateless mode and only leverage its actions, without triggering any
  # events. Defaults to False.
  # disable_monitor: False  # type=bool

Dependencies#

pip

pip install tinytuya

Triggered events#

Actions#

Module reference#

class platypush.plugins.light.tuya.LightTuyaPlugin(*_, **__)[source]#

Bases: RunnablePlugin, LightEntityManager

Controls Tuya-based Wi-Fi light bulbs (Smart Life / Tuya Smart compatible devices) directly over the LAN, with no cloud dependency, through tinytuya.

Each device needs its IP address, device ID and local key. The easiest way to collect them is through the tinytuya wizard:

$ python -m tinytuya wizard

which requires the API credentials of a project created on the Tuya IoT platform and linked to your Smart Life/Tuya Smart app account. It generates a devices.json file that can be passed directly to this plugin through the devices_file configuration option. The cloud credentials are only needed for the initial keys extraction - all the control operations are performed locally.

__init__(devices: Iterable[dict] | Mapping[str, dict] | None = None, groups: Mapping[str, Iterable[str]] | None = None, devices_file: str | None = None, poll_interval: float | None = 20.0, connect_timeout: float = 5.0, **kwargs)[source]#
Parameters:
  • devices – Static list of devices. It can either be a list of dictionaries in the format {"name": "...", "id": "...", "ip": "...", "key": "...", "version": 3.x} (the same format generated by the tinytuya wizard), or a name -> device info mapping. If not specified, the devices will be loaded from devices_file (if provided and it exists), or from the first file that exists among the default locations (~/.config/platypush/devices.json).

  • groups – Optional group name -> [light names/IDs] mapping, used to control multiple lights at once.

  • devices_file – Path to a devices.json file generated by the tinytuya wizard.

  • poll_interval – How often the plugin should poll the devices for status updates and emit platypush.message.event.light.LightStatusChangeEvent events (default: 20 seconds). Set to 0/None to disable polling.

  • connect_timeout – Timeout for the connection to the devices (default: 5 seconds).

get_groups(*_, **__) → dict[source]#

Get the configured groups in the format {name: {"name": ..., "lights": [...], "state": {"any_on": ...}}} (compatible with the light panel frontend components).

get_lights(*_, **__) → dict[source]#

Get the configured lights in the format {id: {"name": ..., "state": {"on": ..., "bri": ..., "sat": ..., "hue": ..., "ct": ..., "xy": ...}}} (compatible with the light panel frontend components).

off(lights=None, groups=None, **_)[source]#

Turn lights/groups off.

Parameters:
  • lights – Lights to turn off (names, IDs or IPs). Default: all the configured lights.

  • groups – Groups to turn off. Default: all the configured groups.

on(lights=None, groups=None, **_)[source]#

Turn lights/groups on.

Parameters:
  • lights – Lights to turn on (names, IDs or IPs). Default: all the configured lights.

  • groups – Groups to turn on. Default: all the configured groups.

publish_entities(entities: Collection[Any] | None, callback: Callable[[Entity], Any] | None = None, **kwargs) → Collection[Entity]#

Publishes a list of entities. The downstream consumers include:

It also accepts an optional callback that will be called when each of the entities in the set is flushed to the database.

You usually don’t need to override this class (but you may want to extend transform_entities() instead if your extension doesn’t natively handle Entity objects).

set(entity: str, value: Any, **kwargs)#

Set the value of an entity.

Parameters:
  • entity – The entity to set the value for. It’s usually the ID of the entity provided by the plugin.

  • value – The value to set the entity to.

set_lights(lights=None, groups=None, *_, **kwargs)[source]#

Set a set of properties on a set of lights.

Parameters:
  • lights – List of lights to set. Each item can represent a light name, ID, IP or entity object. If neither lights nor groups are specified, the action is applied to all the configured lights.

  • groups – List of configured groups to set.

  • kwargs –

    key-value list of the parameters to set. Supported keys:

    • on (bool): Turn the lights on/off.

    • brightness (0-255): Set the brightness.

    • temperature/ct (153-500 mireds): Set the white colour temperature.

    • hue (0-360): Set the colour hue.

    • saturation/sat (0-100): Set the colour saturation.

    • xy ([x, y]): Set the colour by CIE 1931 coordinates.

    • rgb ([r, g, b]) or red/green/blue (0-255): Set the colour by RGB components.

    • mode (str): Set the working mode (white, colour, scene_1-scene_4, music).

    • scene (int): Set a scene by number.

Example call:

{
    "type": "request",
    "action": "light.tuya.set_lights",
    "args": {
        "lights": ["Bathroom Left", "Bathroom Right"],
        "xy": [0.6243, 0.3447],
        "brightness": 197
    }
}
status(*_, **__) → Iterable[Light][source]#

Get the current state of all the configured lights.

toggle(lights=None, groups=None, **_)[source]#

Toggle lights/groups.

Parameters:
  • lights – Lights to toggle (names, IDs or IPs). Default: all the configured lights.

  • groups – Groups to toggle. Default: all the configured groups.

transform_entities(entities: Collection[dict], **_) → Collection[Entity][source]#

This method takes a list of entities in any (plugin-specific) format and converts them into a standardized collection of Entity objects. Since this method is called by publish_entities() before entity updates are published, you may usually want to extend it to pre-process the entities managed by your extension into the standard format before they are stored and published to all the consumers.