pyziggy.util

Utility classes and functions that may come handy for building automations.

class pyziggy.util.LightWithDimmingScalable(light: LightWithDimming)

Bases: Scalable

Wrapper for a pyziggy.device_bases.LightWithDimming object that implements the pyziggy.util.Scalable interface. This wrapper can then be added to a pyziggy.util.ScaleMapper.

get_normalized() float

Final overriden base function. Called by pyziggy.util.ScaleMapper.

set_normalized(value: float)

Final overriden base function. Called by pyziggy.util.ScaleMapper.

class pyziggy.util.RunThenExit(devices: DevicesClient, callback: Callable[[], Any])

Bases: object

class pyziggy.util.Scalable

Bases: object

Base class for types that you want to pass into a pyziggy.util.ScaleMapper as a parameter. For passing pyziggy.device_bases.LightWithDimming objects into a pyziggy.util.ScaleMapper, use the pyziggy.util.LightWithDimmingScalable subclass of this type.

abstractmethod get_normalized() float

Function called by pyziggy.util.ScaleMapper. Override this function in subclasses.

Returns:

a value in the [0, 1] range

abstractmethod set_normalized(value: float) None

Function called by pyziggy.util.ScaleMapper. Override this function in subclasses.

Parameters:

value – a value in the [0, 1] range.

class pyziggy.util.ScaleMapper(adjustables: ~typing.List[~typing.Tuple[~pyziggy.util._util.Scalable, float, float]], barriers: list[float] = [], barrier_activation_callback: ~typing.Callable[[], ~typing.Any] = <function ScaleMapper.<lambda>>)

Bases: object

Caution

This class is still a work in progress, although I’m using it daily and is probably the single most useful automation we have.

Maps multiple numeric parameters onto a single scale between 0 and 1.

Behaves as a single numeric parameter that you can set to a value between 0 and 1. You can specify any number of numeric parameters, and associate each with a range inside the ScaleMapper ‘s global [0, 1] range.

This class was written for our home automation to control multiple lights with a single rotary dial.

This way you can control e.g. three light bulbs as one. The first one turns on gradually when the ScaleMapper passes through the [0, 0.3] range. If you keep increasing the ScaleMapper ‘s value, the second bulb turns on, and it’s brightness keeps increasing, reaching its maximum when the ScaleMapper reaches the value 0.6. Meanwhile, the first bulb remains at maximum brightness. Finally, the third bulb turns on at 0.6, and when the ScaleMapper reaches 1.0 all three bulbs are at maximum brightness.

To achieve this, you’d use the following code:

ScaleMapper(
    [
        (L2S(devices.standing_lamp), 0.0, 0.3),
        (L2S(devices.couch), 0.3, 0.6),
        (L2S(devices.color_bulb), 0.6, 1.0),
    ]
)

The ranges for the devices can overlap.

Parameters:
  • adjustables – List of tuples. Each element should contain a Scalable, and two numbers marking the sub-range inside the ScaleMapper ‘s [0, 1] range, where the scalable should be mapped.

  • barriers – An optional list of floats in the range [0, 1]. When increasing or decreasing the meta-parameter value, and it passes through any one of these values, the ScaleMapper becomes inactive for half a second, ignoring parameter change requests for this duration. It also calls the barrier_activation_callback if specified.

  • barrier_activation_callback – A callback that can be used to e.g. emit a sound when a barrier is hit.

add(increment: float) None

Add the specified value to the ScaleMapper meta-parameter.

The resulting value will be clamped to the permitted range.

class pyziggy.util.TimedRunner(client: DevicesClient)

Bases: object

Inherit from this class and override the run method to have a one-shot timed script.

The TimedRunner will run all commands in sequence waiting for the specified interval between each code block. After the last block has been executed, it will call pyziggy.message_loop.MessageLoop.stop().

You need to use a list of if statements exactly as in the example:

from pyziggy_autogenerate.available_devices import AvailableDevices

devices = AvailableDevices()

class Test(TimedRunner):
    @override
    def run(self):
        if self.wait(2):
            devices.kitchen_light.brightness.set_normalized(1)
            devices.kitchen_light.color_temp.set(454)

        if self.wait(1):
            devices.kitchen_light.state.set(1)

        if self.wait(1):
            devices.kitchen_light.state.set(0)

        if self.wait(1):
            devices.kitchen_light.color_temp.set(179)

        if self.wait(1):
            devices.kitchen_light.state.set(1)

        if self.wait(1):
            devices.kitchen_light.color_temp.set(255)

        if self.wait(1):
            devices.kitchen_light.brightness.query_device()

_ = Test(devices)
abstractmethod run()

Override this method with the timed script contents you need.

set_stop_message_loop_when_done(should_stop: bool)

Sets whether to stop the message loop when done.

The default setting is True.

wait(seconds)

Waits for the specified amount of time relative to the previous invocation of wait() in the run() function.

pyziggy.util.clamp(value: float, low: float, high: float) float

Clamps a value to the range [low, high].

pyziggy.util.map_linear(value: float, low: float, high: float) float

Maps a value from the range [0, 1] to the range [low, high].