def _configure_and_stream(
         self,
         config: dict[str, Any] | None) -> AsyncGenerator[DataEvent, None]:
     if config is None:
         return stream.empty()
     try:
         # Run all config steps in order (concat) and one at a time (task_limit=1). Drop the output. There is
         # nothing to compare them to (filter => false), then read all sensors of the bricklet and process them in
         # parallel (flatten).
         config_stream = stream.chain(
             stream.iterate(config["on_connect"])
             | pipe.starmap(lambda func, timeout: stream.just(func()) | pipe
                            .timeout(timeout))
             | pipe.concat(task_limit=1)
             | pipe.filter(lambda result: False),
             stream.iterate(config["config"].items())
             | pipe.starmap(self._parse_callback_configuration)
             | pipe.starmap(self._set_callback_configuration)
             | pipe.flatten()
             |
             pipe.map(lambda args: self._read_sensor(config["uuid"], *args))
             | pipe.flatten(),
         )
         return config_stream
     except NotConnectedError:
         # Do not log it
         raise
     except Exception:
         self._logger.exception("This should not happen.")
         raise
Exemple #2
0
async def test_starmap(assert_run, event_loop):
    with event_loop.assert_cleanup():
        xs = stream.range(5)
        ys = stream.range(5)
        zs = xs | pipe.zip(ys) | pipe.starmap(lambda x, y: x+y)
        expected = [x*2 for x in range(5)]
        await assert_run(zs, expected)

    with event_loop.assert_cleanup():
        xs = stream.range(1, 4)
        ys = stream.range(1, 4)
        zs = xs | pipe.zip(ys) | pipe.starmap(asyncio.sleep)
        await assert_run(zs, [1, 2, 3])
        assert event_loop.steps == [1, 2, 3]
Exemple #3
0
    def _stream_data(self, transport):
        config_stream = (stream.chain(
            stream.call(
                call_safely,
                f"{self.__database_topic}/get_config",
                f"{self.__database_topic}/status_update",
                transport.uuid,
            ),
            stream.iterate(
                event_bus.subscribe(f"nodes/by_uuid/{transport.uuid}/add")),
        )
                         | pipe.map(lambda config: self._create_device(
                             transport, config))
                         | pipe.starmap(lambda config, device: stream.empty(
                         ) if device is None else device.stream_data(config))
                         | pipe.switch()
                         | context.pipe(
                             transport,
                             on_enter=lambda: logging.getLogger(__name__).info(
                                 "Connected to %s at %s (%s).", transport.name,
                                 transport.uri, transport.label),
                             on_exit=lambda: logging.getLogger(__name__).info(
                                 "Disconnected from %s at %s (%s).", transport.
                                 name, transport.uri, transport.label),
                         ))

        return config_stream
Exemple #4
0
 def _read_device(config: dict[str, Any]) -> AsyncGenerator[Any, None]:
     on_read: partial
     timeout: float
     on_read, timeout = config["on_read"]
     if inspect.isasyncgenfunction(on_read.func):
         return stream.iterate(on_read()) | pipe.timeout(timeout)
     return (stream.repeat(config["on_read"], interval=config["interval"])
             | pipe.starmap(lambda func, timeout: stream.just(func()) | pipe
                            .timeout(timeout))
             | pipe.concat(task_limit=1))
Exemple #5
0
async def test_starmap(assert_run, event_loop):
    with event_loop.assert_cleanup():
        xs = stream.range(5)
        ys = stream.range(5)
        zs = xs | pipe.zip(ys) | pipe.starmap(lambda x, y: x+y)
        expected = [x*2 for x in range(5)]
        await assert_run(zs, expected)

    with event_loop.assert_cleanup():
        xs = stream.range(1, 4)
        ys = stream.range(1, 4)
        zs = xs | pipe.zip(ys) | pipe.starmap(asyncio.sleep)
        await assert_run(zs, [1, 2, 3])
        assert event_loop.steps == [1, 1, 1]

    with event_loop.assert_cleanup():
        xs = stream.range(1, 4)
        ys = stream.range(1, 4)
        zs = xs | pipe.zip(ys) | pipe.starmap(asyncio.sleep, task_limit=1)
        await assert_run(zs, [1, 2, 3])
        assert event_loop.steps == [1, 2, 3]
 def _stream_transport(transport: TinkerforgeTransport):
     sensor_stream = stream.chain(
         stream.call(transport.enumerate) | pipe.filter(lambda x: False),
         stream.iterate(transport.read_enumeration())
         | pipe.action(lambda enumeration: event_bus.publish(f"nodes/tinkerforge/{enumeration[1].uid}/remove", None))
         | pipe.filter(lambda enumeration: enumeration[0] is not EnumerationType.DISCONNECTED)
         | pipe.starmap(lambda enumeration_type, sensor: TinkerforgeSensor(sensor))
         | pipe.map(lambda sensor: sensor.stream_data())
         | pipe.flatten(),
     ) | context.pipe(
         transport,
         on_enter=lambda: logging.getLogger(__name__).info(
             "Connected to Tinkerforge host at %s (%s).", transport.uri, transport.label
         ),
         on_exit=lambda: logging.getLogger(__name__).info(
             "Disconnected from Tinkerforge host at %s (%s).", transport.uri, transport.label
         ),
     )
     return sensor_stream
Exemple #7
0
 def _configure_and_stream(
         self, config: dict[str, Any]) -> AsyncGenerator[DataEvent, None]:
     if config is None:
         return stream.empty()
     # Run all config steps in order (concat) and one at a time (task_limit=1). Drop the output. There is nothing to
     # compare them to (filter => false), then read the device.
     config_stream = stream.chain(
         stream.iterate(config["on_connect"])
         | pipe.starmap(lambda func, timeout: stream.just(func()) | pipe.
                        timeout(timeout))
         | pipe.concat(task_limit=1)
         | pipe.filter(lambda result: False),
         self._read_device(config)
         | pipe.map(lambda item: DataEvent(sender=config["uuid"],
                                           topic=config["topic"],
                                           value=item,
                                           sid=0,
                                           unit=config["unit"]))
         | finally_action.pipe(
             stream.call(self._clean_up, config["on_disconnect"])),
     ) | catch.pipe(TypeError, on_exc=self.on_error)
     return config_stream