Exemplo n.º 1
0
 def pack_payload(kls, message_type, data, messages_register=None):
     """
     Given some payload data as a dictionary and it's ``pkt_type``, return a
     hexlified string of the payload.
     """
     for k in (messages_register or [kls]):
         if int(message_type) in k.by_type:
             return k.by_type[int(message_type)].Payload.normalise(
                 Meta.empty(), data).pack()
     raise BadConversion("Unknown message type!", pkt_type=message_type)
Exemplo n.º 2
0
    def from_options(kls, options):
        """Create a Filter based on the provided dictionary"""
        if isinstance(options, dict):
            for option in options:
                if option not in kls.fields:
                    log.warning(
                        hp.lc("Unknown option provided for filter",
                              wanted=option))

        return kls.FieldSpec().normalise(Meta.empty(), options)
Exemplo n.º 3
0
async def set_chain_state(collector, target, reference, artifact, **kwargs):
    """
    Set the state of colors on your tile

    ``lan:set_chain_state d073d5f09124 -- '{"colors": [[[0, 0, 0, 3500], [0, 0, 0, 3500], ...], [[0, 0, 1, 3500], ...], ...], "tile_index": 1, "length": 1, "x": 0, "y": 0, "width": 8}'``

    Where the colors is a grid of 8 rows of 8 ``[h, s, b, k]`` values.
    """
    options = collector.configuration["photons_app"].extra_as_json

    if "colors" in options:
        spec = sb.listof(
            sb.listof(
                list_spec(sb.integer_spec(), sb.float_spec(), sb.float_spec(),
                          sb.integer_spec())))
        colors = spec.normalise(Meta.empty().at("colors"), options["colors"])

        row_lengths = [len(row) for row in colors]
        if len(set(row_lengths)) != 1:
            raise PhotonsAppError(
                "Please specify colors as a grid with the same length rows",
                got=row_lengths)

        num_cells = sum(len(row) for row in colors)
        if num_cells != 64:
            raise PhotonsAppError("Please specify 64 colors", got=num_cells)

        cells = []
        for row in colors:
            for col in row:
                cells.append({
                    "hue": col[0],
                    "saturation": col[1],
                    "brightness": col[2],
                    "kelvin": col[3]
                })

        options["colors"] = cells
    else:
        raise PhotonsAppError(
            "Please specify colors in options after -- as a grid of [h, s, b, k]"
        )

    missing = []
    for field in TileMessages.SetState64.Payload.Meta.all_names:
        if field not in options and field not in ("duration", "reserved6"):
            missing.append(field)

    if missing:
        raise PhotonsAppError("Missing options for the SetTileState message",
                              missing=missing)

    options["res_required"] = False
    msg = TileMessages.SetState64.empty_normalise(**options)
    await target.script(msg).run_with_all(reference)
Exemplo n.º 4
0
    def pack(kls, data, protocol_register, unknown_ok=False):
        """
        Return a hexlified string of the data.

        This uses ``pkt_type`` and ``protocol`` in the data, along with the
        protocol_register to find the appropriate class to use to perform the
        packing.
        """
        if "pkt_type" in data:
            message_type = data["pkt_type"]
        elif "pkt_type" in data.get("protocol_header", {}):
            message_type = data["protocol_header"]["pkt_type"]
        else:
            raise BadConversion(
                "Don't know how to pack this dictionary, it doesn't specify a pkt_type!"
            )

        if "protocol" in data:
            protocol = data["protocol"]
        elif "frame_header" in data and "protocol" in data["frame_header"]:
            protocol = data["frame_header"]["protocol"]
        else:
            raise BadConversion(
                "Don't know how to pack this dictionary, it doesn't specify a protocol!"
            )

        prot = protocol_register.get(protocol)
        if prot is None:
            raise BadConversion("Unknown packet protocol",
                                wanted=protocol,
                                available=list(protocol_register))
        Packet, messages_register = prot

        for k in (messages_register or [kls]):
            if message_type in k.by_type:
                return k.by_type[message_type].normalise(Meta.empty(),
                                                         data).pack()
        if unknown_ok:
            return Packet.normalise(Meta.empty(), data).pack()
        raise BadConversion("Unknown message type!", pkt_type=message_type)
Exemplo n.º 5
0
async def set_attr(collector,
                   target,
                   reference,
                   artifact,
                   broadcast=False,
                   **kwargs):
    """
    Set attributes on your globes

    ``target:set_attr d073d5000000 color -- '{"hue": 360, "saturation": 1, "brightness": 1}'``

    This does the same thing as ``get_attr`` but will look for ``Set<Attr>``
    message and initiates it with the options found after the ``--``.

    So in this case it will create ``SetColor(hue=360, saturation=1, brightness=1)``
    and send that to the device.
    """
    protocol_register = collector.configuration["protocol_register"]

    if artifact in (None, "", NotSpecified):
        raise BadOption(
            "Please specify what you want to get\nUsage: {0} <target>:set_attr <reference> <attr_to_get> -- '{{<options>}}'"
            .format(sys.argv[0]))

    kls_name = "Set{0}".format("".join(part.capitalize()
                                       for part in artifact.split("_")))

    setter = None
    for messages in protocol_register.message_register(1024):
        for kls in messages.by_type.values():
            if kls.__name__ == kls_name:
                setter = kls
                break

    if setter is None:
        raise BadOption(
            "Sorry, couldn't find the message type {0}".format(kls_name))

    photons_app = collector.configuration["photons_app"]

    extra = photons_app.extra_as_json

    if "extra_payload_kwargs" in kwargs:
        extra.update(kwargs["extra_payload_kwargs"])

    script = target.script(setter.normalise(Meta.empty(), extra))
    async for pkt, _, _ in script.run_with(reference, broadcast=broadcast):
        print("{0}: {1}".format(pkt.serial, repr(pkt.payload)))
Exemplo n.º 6
0
async def get_attr(collector, target, reference, artifact, **kwargs):
    """
    Get attributes from your globes

    ``target:get_attr d073d5000000 color``

    Where ``d073d5000000`` is replaced with the serial of the device you are
    addressing and ``color`` is replaced with the attribute you want.

    This task works by looking at all the loaded LIFX binary protocol messages
    defined for the 1024 protocol and looks for ``Get<Attr>``.

    So if you want the ``color`` attribute, it will look for the ``GetColor``
    message and send that to the device and print out the reply packet we get
    back.
    """
    protocol_register = collector.configuration["protocol_register"]

    if artifact in (None, "", NotSpecified):
        raise BadOption(
            "Please specify what you want to get\nUsage: {0} <target>:get_attr <reference> <attr_to_get>"
            .format(sys.argv[0]))

    kls_name = "Get{0}".format("".join(part.capitalize()
                                       for part in artifact.split("_")))

    getter = None
    for messages in protocol_register.message_register(1024):
        for kls in messages.by_type.values():
            if kls.__name__ == kls_name:
                getter = kls
                break

    if getter is None:
        raise BadOption(
            "Sorry, couldn't find the message type {0}".format(kls_name))

    photons_app = collector.configuration["photons_app"]

    extra = photons_app.extra_as_json

    if "extra_payload_kwargs" in kwargs:
        extra.update(kwargs["extra_payload_kwargs"])

    script = target.script(getter.normalise(Meta.empty(), extra))
    async for pkt, _, _ in script.run_with(reference, **kwargs):
        print("{0}: {1}".format(pkt.serial, repr(pkt.payload)))
Exemplo n.º 7
0
async def apply_theme(collector, target, reference, artifact, **kwargs):
    """
    Apply a theme to specified device

    ``lan:apply_theme d073d5000001 -- `{"colors": <colors>, "theme": "SPLOTCH"}'``

    If you don't specify serials, then the theme will apply to all devices found on the network.

    colors must be an array of ``{"hue": <hue>, "saturation": <saturation>, "brightness": <brightness>, "kelvin": <kelvin>}``

    theme must be a valid theme type and defaults to SPLOTCH

    You may also specify ``duration`` which is how long to take to apply in seconds.

    And you may also supply ``hue``, ``saturation``, ``brightness`` and ``kelvin`` to override the specified colors.
    """
    options = Options.FieldSpec().normalise(
        Meta.empty(), collector.configuration["photons_app"].extra_as_json)

    async with target.session() as afr:
        await do_apply_theme(target, reference, afr, options)
Exemplo n.º 8
0
async def set_tile_positions(collector, target, reference, **kwargs):
    """
    Set the positions of the tiles in your chain.

    ``lan:set_tile_positions d073d5f09124 -- '[[0, 0], [-1, 0], [-1, 1]]'``
    """
    extra = collector.configuration["photons_app"].extra_as_json
    positions = sb.listof(sb.listof(sb.float_spec())).normalise(
        Meta.empty(), extra)
    if any(len(position) != 2 for position in positions):
        raise PhotonsAppError(
            "Please enter positions as a list of two item lists of user_x, user_y"
        )

    async with target.session() as afr:
        for i, (user_x, user_y) in enumerate(positions):
            msg = TileMessages.SetUserPosition(tile_index=i,
                                               user_x=user_x,
                                               user_y=user_y,
                                               res_required=False)
            await target.script(msg).run_with_all(reference, afr)
Exemplo n.º 9
0
 def empty_normalise(self, **kwargs):
     """Normalise val with the spec from self.make_spec"""
     return self.normalise(Meta.empty(), kwargs)
Exemplo n.º 10
0
            return pkt.getitem_spec(self.typ, self.key, actual, self.parent, self.serial
                , do_transform = do_transform
                , allow_bitarray = allow_bitarray
                , unpacking = self.unpacking
                )

        it "calls the value if it's allowed to be callable and is callable":
            self.typ._allow_callable = True
            cald = mock.Mock(name="actual return value")
            actual = mock.Mock(name='actual', return_value=cald)

            class P(PacketSpecMixin):
                pass

            p = P()
            meta = Meta.empty()
            self.assertIs(self.getitem_spec(p, actual, do_transform=True, allow_bitarray=True), self.untransformed)

            actual.assert_called_with(self.parent, self.serial)
            self.typ.spec.assert_called_once_with(p, self.unpacking, transform=False)
            self.initd_spec.normalise.assert_called_with(meta.at(self.key), cald)
            self.untransform.assert_called_with(self.normalised)

        it "does not call the value if it's not allowed to be callable and is callable":
            actual = mock.Mock(name='actual')

            class P(PacketSpecMixin):
                pass

            p = P()
            meta = Meta.empty()
Exemplo n.º 11
0
        describe "from_options":
            it "normalises the options":
                normalised = mock.Mock(name="normalised")

                spec = mock.Mock(name="spec")
                spec.normalise.return_value = normalised

                FieldSpec = mock.Mock(name='FieldSpec', return_value=spec)

                options = mock.Mock(name="options")

                with mock.patch.object(Filter, "FieldSpec", FieldSpec):
                    self.assertIs(Filter.from_options(options), normalised)

                FieldSpec.assert_called_once_with()
                spec.normalise.assert_called_once_with(Meta.empty(), options)

            it "works":
                want = {"label": ["bathroom", "hallway"], "location_id": ["identifier1"], "saturation": [(0.7, 0.7), (0.8, 1.0)]}
                filtr = Filter.from_options(want)
                self.assertFiltrMatches(filtr, want)

        describe "empty":
            it "uses from_options with just force_refresh":
                filtr = mock.Mock(name="filtr")
                from_options = mock.Mock(name="from_options", return_value=filtr)

                with mock.patch.object(Filter, "from_options", from_options):
                    self.assertIs(Filter.empty(), filtr)

                from_options.assert_called_once_with({"force_refresh": False})
Exemplo n.º 12
0
            assert not hasattr(changed, "three")
            assert not hasattr(changed, "four")
            self.assertEqual(changed.one, sb.NotSpecified)
            self.assertEqual(changed.two, sb.NotSpecified)

        it "allows setting all values to be required":
            class Original(dictobj.Spec):
                one = dictobj.Field(sb.string_spec)
                two = dictobj.Field(sb.integer_spec)
                three = dictobj.Field(sb.string_spec)
                four = dictobj.Field(sb.any_spec)

            Changed = Original.selection("Changed", ["one", "two"], all_required=True)

            m = Meta.empty()
            error1 = BadSpecValue("Expected a value but got none", meta=m.at("two"))
            error2 = BadSpecValue("Expected a value but got none", meta=m.at("one"))

            with self.fuzzyAssertRaisesError(BadSpecValue, _errors=[error1, error2]):
                changed = Changed.FieldSpec().normalise(m, {})

        it "can override all_required with optional":
            class Original(dictobj.Spec):
                one = dictobj.Field(sb.string_spec)
                two = dictobj.Field(sb.integer_spec)
                three = dictobj.Field(sb.string_spec)
                four = dictobj.Field(sb.any_spec)

            Changed = Original.selection("Changed", ["one", "two"], all_required=True, optional=["two"])
Exemplo n.º 13
0
from input_algorithms.meta import Meta
from bitarray import bitarray
from textwrap import dedent
import binascii
import mock

describe TestCase, "FrameHeader":
    before_each:
        self.frame_header = frame.FrameHeader()

    it "defaults size to size_bits on the pkt divided by 8":
        pkt = mock.Mock(name="pkt")
        pkt.size_bits.return_value = 16

        spec = self.frame_header.Meta.field_types_dict["size"].spec(pkt)
        val = spec.normalise(Meta.empty(), sb.NotSpecified)
        self.assertEqual(val, 2)

    it "defaults protocol to 1024":
        pkt = mock.Mock(name="pkt")
        spec = self.frame_header.Meta.field_types_dict["protocol"].spec(pkt)
        val = spec.normalise(Meta.empty(), sb.NotSpecified)
        self.assertEqual(val, 1024)

    it "defaults addressable to False if we have no target":
        pkt = mock.Mock(name="pkt", target=None)
        spec = self.frame_header.Meta.field_types_dict["addressable"].spec(pkt)
        val = spec.normalise(Meta.empty(), sb.NotSpecified)
        self.assertEqual(val, False)

    it "defaults addressable to True if we do have a target":
Exemplo n.º 14
0
 async def animate(self, target, afr, final_future, reference, options,
                   **kwargs):
     options = self.optionskls.FieldSpec().normalise(Meta.empty(), options)
     return await self.animationkls(target, afr, options).animate(
         reference, final_future, **kwargs)
Exemplo n.º 15
0
# coding: spec

from photons_device_finder import boolean, str_ranges

from photons_app.test_helpers import TestCase

from input_algorithms.errors import BadSpecValue
from input_algorithms.meta import Meta

describe TestCase, "boolean":
    it "transforms int into a boolean":
        self.assertEqual(boolean().normalise(Meta.empty(), 0), False)
        for i in (1, 20, 100):
            self.assertEqual(boolean().normalise(Meta.empty(), i), True)

    it "transforms a str into boolean":
        for s in ("no", "false", "No", "NO", "False", "FALSE"):
            self.assertEqual(boolean().normalise(Meta.empty(), s), False)

        for s in ("yes", "true", "True", "TRUE", "YES"):
            self.assertEqual(boolean().normalise(Meta.empty(), s), True)

    it "passes through booleans":
        self.assertEqual(boolean().normalise(Meta.empty(), False), False)
        self.assertEqual(boolean().normalise(Meta.empty(), True), True)

    it "complains about anything else":
        class Wat:
            pass

        for thing in ([], [1], {}, {1: 2}, lambda: 1, Wat, Wat()):