Example #1
0
async def startSim():
    global client, stack
    # change entries to modify test
    beds = [
        ("W1", "1"),
        ("W1", "2"),
        ("W1", "3"),
        ("W1", "4"),
    ]
    async with AsyncExitStack() as stack:
        # Connect to the MQTT broker
        client = Client(BROKER_ADDRESS)
        await stack.enter_async_context(client)

        tasks = set()
        stack.push_async_callback(cancel_tasks, tasks)

        outbound_topics = [
            "+/+/patientDetails",
            "+/+/HR",
            "+/+/spO2",
            "+/+/diaBP",
            "+/+/sysBP",
            "+/+/ppg",
            "+/+/ecg",
        ]
        for ot in outbound_topics:
            manager = client.filtered_messages(ot)
            messages = await stack.enter_async_context(manager)
            template = f'Outbound -- [topic="{{}}"] {{}}'
            task = asyncio.create_task(log_messages(messages, template))
            tasks.add(task)

        inbound_topics = ["+/+/sendDetails"]

        for it in inbound_topics:
            manager = client.filtered_messages(it)
            messages = await stack.enter_async_context(manager)
            template = f'Inbound -- [topic="{{}}"] {{}}'
            task = asyncio.create_task(log_messages(messages, template))
            tasks.add(task)

        # Messages that doesn't match a filter will get logged here
        messages = await stack.enter_async_context(
            client.unfiltered_messages())
        task = asyncio.create_task(
            log_messages(messages, f'Other -- [topic="{{}}"] {{}}'))
        tasks.add(task)

        await client.subscribe('#')  # subscribe to all messages

        for bed in beds:
            tasks.add(asyncio.create_task(onboardPatient(bed, client)))
            tasks.add(asyncio.create_task(startHRProducer(bed, client)))
            tasks.add(asyncio.create_task(startBPProducer(bed, client)))
            tasks.add(asyncio.create_task(startSpO2Producer(bed, client)))
            tasks.add(asyncio.create_task(startECGProducer(bed, client)))
        await asyncio.gather(*tasks)
Example #2
0
async def connect_to_mqtt_server(config):
    async with AsyncExitStack() as stack:
        # Keep track of the asyncio tasks that we create, so that
        # we can cancel them on exit
        tasks = set()
        stack.push_async_callback(cancel_tasks, tasks)

        if config.has_section('MQTT'):
            # Connect to the MQTT broker
            # client = Client("10.0.1.20", username="******", password="******")
            client = Client(config.get('MQTT', 'broker_address'),
                            username=config.get('MQTT', 'usr'),
                            password=config.get('MQTT', 'pswd'))

            await stack.enter_async_context(client)

            # Create angle fsm
            fsm = AngleFSM(config)

            # Messages that doesn't match a filter will get logged here
            messages = await stack.enter_async_context(
                client.unfiltered_messages())
            task = asyncio.create_task(
                log_messages(messages, "[unfiltered] {}"))
            tasks.add(task)

            # Subscribe to chairState
            await client.subscribe("sensors/chairState")
            manager = client.filtered_messages('sensors/chairState')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_sensors_chair_state(client, messages, fsm))
            tasks.add(task)

            # Subscribe to config notification settings changes
            await client.subscribe("goal/update_data")
            manager = client.filtered_messages('goal/update_data')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_goal_update_data(client, messages, fsm))
            tasks.add(task)

            # Start periodic publish of chair state
            task = asyncio.create_task(publish_angle_fsm(client, fsm))
            tasks.add(task)

        # Wait for everything to complete (or fail due to, e.g., network errors)
        await asyncio.gather(*tasks)
Example #3
0
async def advanced_example():
    # We 💛 context managers. Let's create a stack to help
    # us manage them.
    async with AsyncExitStack() as stack:
        # Keep track of the asyncio tasks that we create, so that
        # we can cancel them on exit
        tasks = set()
        stack.push_async_callback(cancel_tasks, tasks)
        tls_ctx = ssl.create_default_context(
            cafile="/srv/security/iot-hub-ca.pem")
        tls_ctx.load_cert_chain(
            "/srv/security/device-home-office-crt.pem",
            keyfile="/srv/security/device-home-office-key.pem",
        )
        # Connect to the MQTT broker
        client = Client(
            "iot.fr-par.scw.cloud",
            port=8883,
            client_id="50ce1f12-ef04-4e25-806c-3c51aa3f044a",
            tls_context=tls_ctx,
        )
        await stack.enter_async_context(client)

        # You can create any number of topic filters
        topic_filters = (
            "floors/+/humidity", "floors/rooftop/#"
            # 👉 Try to add more filters!
        )
        for topic_filter in topic_filters:
            # Log all messages that matches the filter
            manager = client.filtered_messages(topic_filter)
            messages = await stack.enter_async_context(manager)
            template = f'[topic_filter="{topic_filter}"] {{}}'
            task = asyncio.create_task(log_messages(messages, template))
            tasks.add(task)

        # Messages that doesn't match a filter will get logged here
        messages = await stack.enter_async_context(
            client.unfiltered_messages())
        task = asyncio.create_task(log_messages(messages, "[unfiltered] {}"))
        tasks.add(task)

        # Subscribe to topic(s)
        # 🤔 Note that we subscribe *after* starting the message
        # loggers. Otherwise, we may miss retained messages.
        await client.subscribe("floors/#")

        # Publish a random value to each of these topics
        topics = (
            "floors/basement/humidity",
            "floors/rooftop/humidity",
            "floors/rooftop/illuminance",
            # 👉 Try to add more topics!
        )
        task = asyncio.create_task(post_to_topics(client, topics))
        tasks.add(task)

        # Wait for everything to complete (or fail due to, e.g., network
        # errors)
        await asyncio.gather(*tasks)
Example #4
0
    async def listen(self):
        async with AsyncExitStack() as stack:
            # Track tasks
            tasks = set()
            stack.push_async_callback(cancel_tasks, tasks)

            # Connect to the MQTT broker
            client = Client(self.host,
                            self.port,
                            username=self.username,
                            password=self.password)
            await stack.enter_async_context(client)

            logging.info(f'MQTT client connected')
            # Add tasks for each data source handler
            for ds in self.data_sources:
                # Get handlers from data source
                ds_listeners = ds.listeners()
                # Iterate through data source listeners and convert to
                # 'prime' listeners for each topic
                for listener in ds_listeners:
                    topic = listener.topic
                    funcs = listener.handlers
                    if topic in self.topics:
                        # Add these handlers to existing top level topic handler
                        logging.debug(
                            f'Adding handlers for existing prime Listener: {topic}'
                        )
                        ext_topic = self.topics[topic]
                        ext_topic.handlers.extend(funcs)
                    else:
                        # Add this instance as a new top level handler
                        logging.debug(
                            f'Creating new prime Listener for topic: {topic}')
                        self.topics[topic] = MQTTListener(topic, funcs)

            # Add handlers for each topic as a filtered topic
            for topic, listener in self.topics.items():
                manager = client.filtered_messages(topic)
                messages = await stack.enter_async_context(manager)
                task = asyncio.create_task(self.parse_messages(messages))
                tasks.add(task)

            # Subscribe to all topics
            # Assume QoS 0 for now
            all_topics = [(t, 0) for t in self.topics.keys()]
            logging.info(f'Subscribing to MQTT {len(all_topics)} topic(s)')
            logging.debug(f'Topics: {all_topics}')
            try:
                await client.subscribe(all_topics)
            except ValueError as err:
                logging.error(f'MQTT Subscribe error: {err}')

            # Gather all tasks
            await asyncio.gather(*tasks)
            logging.info(f'Listening for MQTT updates')
Example #5
0
async def handler(mqtt_hostname, mqtt_port, logger, context, topics, router):
    # defining an AsyncExitStack as stack to use with the asynccontextmanager
    async with AsyncExitStack() as stack:
        #set up a set of tasks the asyncio shall work through
        tasks = set()
        #defining what the asynccontextmanager shall do upon exit.
        stack.push_async_callback(cancel_tasks, tasks)
        #using the clientID as both clientID and base topic
        clientID = topics["clientID"]
        #TODO: Fix the asyncio_MQTT library with tuples to pass the certificates.
        #initializing a MQTT client
        LOG.info("Connect to MQTT-broker")
        client = Client(mqtt_hostname,
                        port=mqtt_port,
                        logger=logger,
                        tls_context=context,
                        client_id=clientID)
        router = teltonikaRUT9x(router["hostname"], router["username"],
                                router["password"])
        position = ColumbusV800()
        #putting the client into the asynccontextmanager
        await stack.enter_async_context(client)
        #Loop through all topics that we shall subscribe to
        topic_filters = topics["subscribe"]
        for topic_filter in topic_filters:
            #Use the filtered_messages to make an async generator
            manager = client.filtered_messages(topic_filter)
            #put the generator into the asynccontextmanager
            messages = await stack.enter_async_context(manager)
            template = f'[topic_filter="{topic_filter}"] {{}}'
            #set up a task
            task = asyncio.create_task(log_messages(messages, template))
            tasks.add(task)
        #Make a list of topics with Qos 1 to feed into the client.subscribe
        subscribe_topics = []
        for i in topic_filters:
            subscribe_topics.append((i, 1))
        await client.subscribe(subscribe_topics)

        #create a task that sends the position on the MQTT with the clientID as a basis for topic
        task = asyncio.create_task(
            sendPosition(client, position, 0.2, clientID))
        tasks.add(task)
        #add the signallogging to the async tasks
        task = asyncio.create_task(logSignal(router, 1))
        tasks.add(task)

        # Wait for everything to complete (or fail due to, e.g., network
        # errors)
        await asyncio.gather(*tasks)
async def advanced_example():
    # We 💛 context managers. Let's create a stack to help
    # us manage them.
    async with AsyncExitStack() as stack:
        # Keep track of the asyncio tasks that we create, so that
        # we can cancel them on exit
        tasks = set()
        stack.push_async_callback(cancel_tasks, tasks)

        # Connect to the MQTT broker
        client = Client(broker)
        await stack.enter_async_context(client)

        # You can create any number of topic filters
        topic_filters = (
            "Battle/#/Trainer1/", "Battle/#/Trainer2/"
            # 👉 Try to add more filters!
        )
        for topic_filter in topic_filters:
            # Log all messages that matches the filter
            manager = client.filtered_messages(topic_filter)
            messages = await stack.enter_async_context(manager)
            template = f'[topic_filter="{topic_filter}"] {{}}'
            task = asyncio.create_task(log_messages(messages, template))
            tasks.add(task)

        # Messages that doesn't match a filter will get logged here
        messages = await stack.enter_async_context(
            client.unfiltered_messages())
        task = asyncio.create_task(log_messages(messages, "[unfiltered] {}"))
        tasks.add(task)

        # Subscribe to topic(s)
        # 🤔 Note that we subscribe *after* starting the message
        # loggers. Otherwise, we may miss retained messages.
        await client.subscribe("Battle/#")

        # Publish a random value to each of these topics
        topics = (
            "Battle/BattleLog",
            "Battle/Trainer1/",
            "Battle/Trainer2/",
            # 👉 Try to add more topics!
        )
        task = asyncio.create_task(post_to_topics(client, topics))
        tasks.add(task)

        # Wait for everything to complete (or fail due to, e.g., network
        # errors)
        await asyncio.gather(*tasks)
Example #7
0
async def mqtt_listen(mq: MqttClient, q: asyncio.Queue, topic=MQTT_TOPIC_CMND):
    await mq.subscribe(topic)

    async with mq.filtered_messages(topic) as messages:
        async for message in messages:
            topic = message.topic
            data = message.payload.decode()
            _log.debug(f"MQTT incoming [{topic}]: {data}")

            msg = parse_mqtt_msg(topic, data)
            if not msg:
                continue

            try:
                cmnd = process_mqtt_msg(topic, msg)
            except Exception:
                cmnd = None
                _log.exception(f"while processing message [{topic}]: {msg}")
            if not cmnd:
                continue

            await q.put(cmnd)
Example #8
0
 async def handle_messages(self,client:Client):
     """Hier stop je logica in die inkomende berichten leest en 
     vervolgens jouw knx blind aanstuurt.
     """
     topic = f"{self._topic}/#"
     _LOGGER.debug(f"Start watching: {self._topic}")
     
     async with client.filtered_messages(topic) as messages:
         async for message in messages:
             data = json.loads(message.payload.decode("utf-8"))
             _LOGGER.debug("topic: %s data: %s",message.topic,data)
             
             if message.topic == f"{self._topic}/pos_ang":
                 _LOGGER.debug("Angle position topic found.")
                 position = data["pos"]
                 angle=data["ang"]
                 await self.handle_position_angle(position,angle)
             else:
                 _LOGGER.error("Incoming message with unknown topic: %s",message.topic)
                 await self.handle_unknown_message_type(**data)
                 
     _LOGGER.debug("Finished.")
Example #9
0
async def bed_loop(ble):
    async with AsyncExitStack() as stack:
        # Keep track of the asyncio tasks that we create, so that
        # we can cancel them on exit
        tasks = set()
        stack.push_async_callback(cancel_tasks, tasks)

        # Connect to the MQTT broker
        client = Client(
            MQTT_SERVER,
            port=MQTT_SERVER_PORT,
            username=MQTT_USERNAME,
            password=MQTT_PASSWORD,
        )
        await stack.enter_async_context(client)

        # Set up the topic filter
        manager = client.filtered_messages(MQTT_TOPIC)
        messages = await stack.enter_async_context(manager)
        task = asyncio.create_task(bed_command(ble, messages))
        tasks.add(task)

        # Subscribe to topic(s)
        await client.subscribe(MQTT_TOPIC)

        # let everyone know we are online
        if DEBUG:
            print("Going online")
        await client.publish(MQTT_CHECKIN_TOPIC, MQTT_ONLINE_PAYLOAD, qos=1)

        # let everyone know we are still alive
        task = asyncio.create_task(
            check_in(client, MQTT_CHECKIN_TOPIC, MQTT_CHECKIN_PAYLOAD)
        )
        tasks.add(task)

        # Wait for everything to complete (or fail due to, e.g., network
        # errors)
        await asyncio.gather(*tasks)
Example #10
0
class MQTTProxy(Base):
    def __init__(self,
                 hub,
                 server,
                 prefix="fakesilvia/",
                 debug_mappings=False):
        super().__init__(hub)
        self.prefix = prefix

        self.client = Client(server)
        self.client._client.will_set(self.write_topic('LWT'),
                                     'Offline',
                                     retain=True)
        self.last_send = {}

        self.mappings = {
            topics.TOPIC_AVERAGE_BOILER_TEMPERATURE:
            Mapping('avgtemp', formatter=Mapping.FloatFormatter, throttle=3),
            topics.TOPIC_CURRENT_GROUP_TEMPERATURE:
            Mapping('group_temp', formatter=Mapping.FloatFormatter,
                    throttle=3),
            topics.TOPIC_PID_AVERAGE_VALUE:
            Mapping('avgpid', formatter=Mapping.FloatFormatter, throttle=3),
            topics.TOPIC_SCALE_WEIGHT:
            Mapping('scale_weight',
                    formatter=Mapping.FloatFormatter,
                    throttle=1),
            topics.TOPIC_SCALE_CONNECTED:
            Mapping('scale_is_connected'),
            topics.TOPIC_CURRENT_BREW_TIME_UPDATE:
            Mapping('current_brew_time', formatter=Mapping.FloatFormatter),
            topics.TOPIC_LAST_BREW_DURATION:
            Mapping('shot_time', formatter=Mapping.FloatFormatter),
            topics.TOPIC_STEAM_MODE:
            Mapping('steam_mode', mode=Mapping.MODE_READWRITE),
            topics.TOPIC_CONNECT_TO_SCALE:
            Mapping('keep_scale_connected', mode=Mapping.MODE_READWRITE),
            topics.TOPIC_ENABLE_WEIGHTED_SHOT:
            Mapping('brew_to_weight', mode=Mapping.MODE_READWRITE),
            topics.TOPIC_TARGET_WEIGHT:
            Mapping('target_weight',
                    formatter=Mapping.FloatFormatter,
                    mode=Mapping.MODE_READWRITE),
            topics.TOPIC_TARGET_RATIO:
            Mapping('target_ratio',
                    formatter=Mapping.FloatFormatter,
                    mode=Mapping.MODE_READWRITE),
            topics.TOPIC_USE_PREINFUSION:
            Mapping('use_preinfusion', mode=Mapping.MODE_READWRITE),
            topics.TOPIC_PREINFUSION_TIME:
            Mapping('preinfusion_time',
                    formatter=Mapping.FloatFormatter,
                    mode=Mapping.MODE_READWRITE),
            topics.TOPIC_DWELL_TIME:
            Mapping('dwell_time',
                    formatter=Mapping.FloatFormatter,
                    mode=Mapping.MODE_READWRITE),
            topics.TOPIC_SET_POINT:
            Mapping('settemp',
                    mode=Mapping.MODE_READWRITE,
                    formatter=Mapping.FloatFormatter),
            topics.TOPIC_HE_ENABLED:
            Mapping('is_awake', mode=Mapping.MODE_READWRITE),
            topics.TOPIC_STEAM_TEMPERATURE_SET_POINT:
            Mapping('steam_set_point',
                    mode=Mapping.MODE_READWRITE,
                    formatter=Mapping.FloatFormatter),
            topics.TOPIC_STEAM_TEMPERATURE_DELTA:
            Mapping('steam_delta',
                    mode=Mapping.MODE_READWRITE,
                    formatter=Mapping.FloatFormatter),
            topics.TOPIC_PUMP_PIDVAL_FEED_FORWARD:
            Mapping('pump_feed_forward',
                    mode=Mapping.MODE_READWRITE,
                    formatter=Mapping.FloatFormatter),
            topics.TOPIC_OLED_SAVER:
            Mapping('oled_saver',
                    mode=Mapping.MODE_READWRITE,
                    formatter=Mapping.BoolFormatter),
            topics.TOPIC_CAPTURE_DOSE:
            Mapping('capture_dose',
                    mode=Mapping.MODE_WRITEONLY,
                    formatter=Mapping.BoolFormatter),
            topics.TOPIC_SOLENOID_OPEN:
            Mapping('solenoid', mode=Mapping.MODE_READWRITE),
            topics.TOPIC_CAPTURE_DOSE_AND_SET_TARGET_WEIGHT:
            Mapping('capture_dose_set_weight',
                    mode=Mapping.MODE_WRITEONLY,
                    formatter=Mapping.BoolFormatter),
        }

        if debug_mappings:
            self.mappings[topics.TOPIC_COFFEE_BUTTON] = Mapping(
                "coffee_button", mode=Mapping.MODE_READWRITE)
            self.mappings[topics.TOPIC_WATER_BUTTON] = Mapping(
                "water_button", mode=Mapping.MODE_READWRITE)
            self.mappings[topics.TOPIC_STEAM_BUTTON] = Mapping(
                "steam_button", mode=Mapping.MODE_READWRITE)

    async def run_async(self):
        async with AsyncExitStack() as stack:
            # Keep track of the asyncio tasks that we create, so that
            # we can cancel them on exit
            tasks = set()
            stack.push_async_callback(self.cancel_tasks, tasks)

            # Connect to the MQTT broker
            await stack.enter_async_context(self.client)

            await self.client.publish(self.write_topic('LWT'),
                                      "Online",
                                      retain=True)

            for key in self.mappings:
                mapping = self.mappings[key]
                if mapping.mode == Mapping.MODE_READONLY:
                    continue

                manager = self.client.filtered_messages(
                    self.read_topic(mapping.key))
                messages = await stack.enter_async_context(manager)
                task = asyncio.create_task(
                    self.read_values(messages, key, mapping))
                tasks.add(task)

                await self.client.subscribe(self.read_topic(mapping.key))

            pub_task = asyncio.create_task(self.publish_values())
            heartbeat_task = asyncio.create_task(self.publish_heartbeat())
            tasks.add(pub_task)
            tasks.add(heartbeat_task)

            await asyncio.gather(*tasks)

    async def cancel_tasks(self, tasks):
        for task in tasks:
            task.cancel()
            try:
                await task
            except asyncio.CancelledError:
                pass

    async def read_values(self, messages, key, mapping):
        async for message in messages:
            self.hub.publish(
                key, mapping.formatter.from_mqtt(message.payload.decode()))

    async def publish_heartbeat(self):
        while True:
            await self.client.publish(self.write_topic('heartbeat'),
                                      time.time())
            await asyncio.sleep(10)

    async def publish_values(self):
        with PubSub.Listener(self.hub) as queue:
            while True:
                key, value = await queue.get()

                try:
                    mapping = self.mappings[key]
                except KeyError:
                    continue

                if mapping.mode == Mapping.MODE_WRITEONLY:
                    continue

                if mapping.throttle:
                    try:
                        last_send = self.last_send[mapping.key]
                    except KeyError:
                        last_send = 0

                    if last_send + mapping.throttle > time.time():
                        continue

                await self.client.publish(self.write_topic(mapping.key),
                                          mapping.formatter.to_mqtt(value))
                self.last_send[mapping.key] = time.time()

    def write_topic(self, key):
        return "{}{}".format(self.prefix, key)

    def read_topic(self, key):
        return "{}{}/set".format(self.prefix, key)

    def futures(self, loop):
        return [self.run_async()]
Example #11
0
async def connect_to_mqtt_server(config):
    async with AsyncExitStack() as stack:
        # Keep track of the asyncio tasks that we create, so that
        # we can cancel them on exit
        tasks = set()
        stack.push_async_callback(cancel_tasks, tasks)

        if config.has_section('MQTT'):
            # Connect to the MQTT broker
            # client = Client("10.0.1.20", username="******", password="******")
            client = Client(config.get('MQTT', 'broker_address'),
                            username=config.get('MQTT', 'usr'),
                            password=config.get('MQTT', 'pswd'))

            await stack.enter_async_context(client)

            # Create PCA9536 driver
            pca = pca9536()

            # Create Alarm State
            state = AlarmState(config)

            # Messages that doesn't match a filter will get logged here
            messages = await stack.enter_async_context(
                client.unfiltered_messages())
            task = asyncio.create_task(
                log_messages(messages, "[unfiltered] {}"))
            tasks.add(task)

            # sensors/alarm/enabled
            await client.subscribe("sensors/alarm/enabled")
            manager = client.filtered_messages('sensors/alarm/enabled')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_alarm_enabled(client, messages, pca, state))
            tasks.add(task)

            # sensors/alarm/alternatingLedBlink
            await client.subscribe("sensors/alarm/alternatingLedBlink")
            manager = client.filtered_messages(
                'sensors/alarm/alternatingLedBlink')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_alarm_alternating_led_blink(client, messages, pca,
                                                   state))
            tasks.add(task)

            # sensors/alarm/motorOn
            await client.subscribe("sensors/alarm/motorOn")
            manager = client.filtered_messages('sensors/alarm/motorOn')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_alarm_motor_on(client, messages, pca, state))
            tasks.add(task)

            # sensors/alarm/redLedOn
            await client.subscribe("sensors/alarm/redLedOn")
            manager = client.filtered_messages('sensors/alarm/redLedOn')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_alarm_red_led_on(client, messages, pca, state))
            tasks.add(task)

            # sensors/alarm/redLedBlink
            await client.subscribe("sensors/alarm/redLedBlink")
            manager = client.filtered_messages('sensors/alarm/redLedBlink')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_alarm_red_led_blink(client, messages, pca, state))
            tasks.add(task)

            # sensors/alarm/greenLedOn
            await client.subscribe("sensors/alarm/greenLedOn")
            manager = client.filtered_messages('sensors/alarm/greenLedOn')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_alarm_green_led_on(client, messages, pca, state))
            tasks.add(task)

            # sensors/alarm/greenLedBlink
            await client.subscribe("sensors/alarm/greenLedBlink")
            manager = client.filtered_messages('sensors/alarm/greenLedBlink')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_alarm_green_led_blink(client, messages, pca, state))
            tasks.add(task)

            # Start periodic publish of alarm state
            task = asyncio.create_task(alarm_loop(client, pca, state))
            tasks.add(task)

        # Wait for everything to complete (or fail due to, e.g., network errors)
        await asyncio.gather(*tasks)
Example #12
0
class SatelliteController:
    def __init__(self, cbpi):
        self.cbpi = cbpi
        self.client = None

    async def init(self):
        asyncio.create_task(self.init_client(self.cbpi))

    async def publish(self, topic, message):
        print("MQTT ON")
        await self.client.publish(topic, message, qos=1)

    async def handle_message(self, messages):
        async for message in messages:
            print("FILTERED", message.payload.decode())

    async def handle_unfilterd_message(self, messages):
        async for message in messages:
            print("UNFILTERED", message.payload.decode())

    async def init_client(self, cbpi):
        async def log_messages(messages, template):

            async for message in messages:
                print(template.format(message.payload.decode()))

        async def cancel_tasks(tasks):
            for task in tasks:
                if task.done():
                    continue
                task.cancel()
                try:
                    await task
                except asyncio.CancelledError:
                    pass

        async with AsyncExitStack() as stack:

            tasks = set()
            stack.push_async_callback(cancel_tasks, tasks)

            self.client = Client("localhost",
                                 will=Will(topic="cbpi/diconnect",
                                           payload="CBPi Server Disconnected"))
            await stack.enter_async_context(self.client)

            topic_filters = ("cbpi/sensor/#", "cbpi/actor/#")
            for topic_filter in topic_filters:
                # Log all messages that matches the filter
                manager = self.client.filtered_messages(topic_filter)
                messages = await stack.enter_async_context(manager)
                task = asyncio.create_task(self.handle_message(messages))
                tasks.add(task)

            messages = await stack.enter_async_context(
                self.client.unfiltered_messages())
            task = asyncio.create_task(self.handle_unfilterd_message(messages))
            tasks.add(task)

            await self.client.subscribe("cbpi/#")
            await asyncio.gather(*tasks)
class SatelliteController:

    def __init__(self, cbpi):
        self.cbpi = cbpi
        self.logger = logging.getLogger(__name__)
        self.host = cbpi.static_config.get("mqtt_host", "localhost")
        self.port = cbpi.static_config.get("mqtt_port", 1883)
        self.username = cbpi.static_config.get("mqtt_username", None)
        self.password = cbpi.static_config.get("mqtt_password", None)
        self.client = None
        self.topic_filters = [
            ("cbpi/actor/+/on", self._actor_on),
            ("cbpi/actor/+/off", self._actor_off)
        ]
        self.tasks = set()

    async def init(self):
        asyncio.create_task(self.init_client(self.cbpi))

    async def publish(self, topic, message, retain=False):
        if self.client is not None and self.client._connected:
            try:
                await self.client.publish(topic, message, qos=1, retain=retain)
            except:
                self.logger.warning("Faild to push data via mqtt")

    async def _actor_on(self, messages):
        async for message in messages:
            try:
                topic_key = message.topic.split("/")
                await self.cbpi.actor.on(topic_key[2])
            except:
                self.logger.warning("Faild to process actor on via mqtt")

    async def _actor_off(self, messages):
        async for message in messages:
            try:
                topic_key = message.topic.split("/")
                await self.cbpi.actor.off(topic_key[2])
            except:
                self.logger.warning("Faild to process actor off via mqtt")

    def subcribe(self, topic, method):
        task = asyncio.create_task(self._subcribe(topic, method))
        return task

    async def _subcribe(self, topic, method):
        while True:
            try:
                if self.client._connected.done():
                    async with self.client.filtered_messages(topic) as messages:
                        await self.client.subscribe(topic)
                        async for message in messages:
                            await method(message.payload.decode())
            except asyncio.CancelledError as e:
                # Cancel
                self.logger.warning(
                    "Sub CancelledError Exception: {}".format(e))
                return
            except MqttError as e:
                self.logger.error("Sub MQTT Exception: {}".format(e))
            except Exception as e:
                self.logger.error("Sub Exception: {}".format(e))

            # wait before try to resubscribe
            await asyncio.sleep(5)

    async def init_client(self, cbpi):

        async def cancel_tasks(tasks):
            for task in tasks:
                if task.done():
                    continue
                task.cancel()
                try:
                    await task
                except asyncio.CancelledError:
                    pass

        while True:
            try:
                async with AsyncExitStack() as stack:
                    self.tasks = set()
                    stack.push_async_callback(cancel_tasks, self.tasks)
                    self.client = Client(self.host, port=self.port, username=self.username, password=self.password, will=Will(topic="cbpi/diconnect", payload="CBPi Server Disconnected"))

                    await stack.enter_async_context(self.client)

                    for topic_filter in self.topic_filters:
                        topic = topic_filter[0]
                        method = topic_filter[1]
                        manager = self.client.filtered_messages(topic)
                        messages = await stack.enter_async_context(manager)
                        task = asyncio.create_task(method(messages))
                        self.tasks.add(task)

                    for topic_filter in self.topic_filters:
                        topic = topic_filter[0]
                        await self.client.subscribe(topic)

                    self.logger.info("MQTT Connected to {}:{}".format(self.host, self.port))
                    await asyncio.gather(*self.tasks)

            except MqttError as e:
                self.logger.error("MQTT Exception: {}".format(e))
            except Exception as e:
                self.logger.error("MQTT General Exception: {}".format(e))
            await asyncio.sleep(5)
Example #14
0
class MQTT(BasePlugin):
    def __init__(self, daemon, cfg):
        super(MQTT, self).__init__(daemon, cfg)
        daemon.knx_read_cbs.append(self.process_knx)
        daemon.value_direct_cbs.append(self.process_direct)
        self.poll_interval = "poll_interval" in cfg and cfg["poll_interval"] or 10
        self._mqtt_tasks = None
        self._mqtt_client = None
        self.status_pending_for_groups = []

    async def mqtt_loop(self):
        while True:
          try:
              await self.mqtt_stack()
          except MqttError as error:
              log.warning("MqttError: {error}. Reconnecting in {self.poll_interval} seconds.")
          finally:
              await asyncio.sleep(self.poll_interval)

    async def mqtt_stack(self):
        async with AsyncExitStack() as stack:
            self._mqtt_tasks = set()
            stack.push_async_callback(self.cancel_tasks, self._mqtt_tasks)
            username = self.cfg["user"] or None
            password = self.cfg["pass"] or None
            self._mqtt_client = Client(self.cfg["host"],port=self.cfg["port"],username=username,password=password)
            await stack.enter_async_context(self._mqtt_client)

            topics = []
            for o in self.obj_list:
                topic = o["topic"]
                topics.append(topic)
                manager = self._mqtt_client.filtered_messages(topic)
                messages = await stack.enter_async_context(manager)
                task = asyncio.create_task(self.mqtt_handle(messages, o))
                self._mqtt_tasks.add(task)

            for topic in topics:
                await self._mqtt_client.subscribe(topic)

            await asyncio.gather(*self._mqtt_tasks)

    async def mqtt_handle(self, messages, obj):
        group_value_dict = {}
        async for message in messages:
            payload = message.payload.decode()
            try:
                jsonobj = loads(payload)
            except ValueError:
                jsonobj = None
                value = str(payload)
            objects = self._get_objects_by_topic(message.topic)
            for o in objects:
                knx_group = o["knx_group"]
                if jsonobj and "valmap" in o:
                    for key, valdict in o["valmap"].items():
                        if key in jsonobj:
                            prop = jsonobj[key]
                            if type(valdict) == dict and prop in valdict:
                                value = valdict[prop]
                            else:
                                value = str(prop)
                        else:
                            value = None
                            continue
                prev_val = o["value"]
                if value == None:
                    pass
                elif prev_val != value:
                    o["value"] = value
                    group_value_dict[knx_group] = value
                    log.debug(f"{self.device_name} mqtt topic={message.topic} payload={payload} knx_group={knx_group} updated value {prev_val}=>{value}")
                    if group_value_dict:
                        await self.d.set_group_value_dict(group_value_dict)
                else:
                    log.debug(f"{self.device_name} mqtt topic={message.topic} payload={payload} knx_group={knx_group} value={value} unchanged, ignored")
                if knx_group in self.status_pending_for_groups:
                    self.status_pending_for_groups.remove(knx_group)

    async def cancel_tasks(self):
        for task in self._mqtt_tasks:
            if task.done():
                continue
            task.cancel()
            try:
                await task
            except asyncio.CancelledError:
                pass

    async def process_direct(self, knx_group, knx_val):
        debug_msg = f"{self.device_name} process_direct({knx_group}={knx_val})"
        await self._write_mqtt(knx_group, knx_val, debug_msg)

    async def process_knx(self, cmd):
        try:
            knx_group, knx_val = cmd.strip().split("=")
            try:
                o = self.get_obj_by_knxgrp(knx_group)
                if o["enabled"]:
                    debug_msg = f"{self.device_name} process_knx({knx_group}={knx_val})"
                    await self._write_mqtt(knx_group, knx_val, debug_msg)
            except StopIteration:
                pass
            return True
        except Exception as e:
            log.warning("f{self.device_name} couldn't parse KNX command {cmd} ({e}!")
            return False

    async def _write_mqtt(self, knx_group, knx_val, debug_msg):
        if not self._mqtt_client:
            return
        objects = []
        request_status = False
        for item in self.obj_list:
            if item["knx_group"] == knx_group:
                objects.append(item)
                request_status = "request_status" in item
        for o in objects:
            if "publish_topic" in o:
                topic = o["publish_topic"]
                prev_val = o["value"]
                if "valmap" in o:
                    payload = o["valmap"][knx_val]
                else:
                    payload = knx_val
                log.info(f"{debug_msg} topic {topic} updating {prev_val}=>{knx_val} ({payload})")
                try:
                    await self._mqtt_client.publish(topic, payload, qos=1, retain=True)
                    o["value"] = knx_val
                except MqttCodeError as error:
                    log.error(f"{debug_msg} MqttCodeError {error} on topic {topic}")
        if objects and request_status and "status_object" in self.cfg and self._mqtt_client and not knx_group in self.status_pending_for_groups:
            so = self.cfg["status_object"]
            delay = so.get("delay", 10.0)
            topic = so["topic"]
            payload = so["payload"]
            await asyncio.sleep(delay)
            try:
                await self._mqtt_client.publish(topic, payload, qos=1, retain=True)
                log.debug(f"{debug_msg} requested status topic {topic} payload=>{payload}")
                self.status_pending_for_groups.append(knx_group)
            except MqttCodeError as error:
                log.error(f"{debug_msg} MqttCodeError {error} on topic {topic}")

    def _get_objects_by_topic(self, topic):
        objects = []
        for item in self.obj_list:
            if item["topic"] == topic:
                objects.append(item)
        return objects

    def _run(self):
        loop_task = self.d.loop.create_task(self.mqtt_loop())
        return [loop_task]
Example #15
0
async def connect_to_mqtt_server(config):
    async with AsyncExitStack() as stack:
        # Keep track of the asyncio tasks that we create, so that
        # we can cancel them on exit
        tasks = set()
        stack.push_async_callback(cancel_tasks, tasks)

        if config.has_section('MQTT'):
            # Connect to the MQTT broker
            # client = Client("10.0.1.20", username="******", password="******")
            client = Client(config.get('MQTT', 'broker_address'),
                            username=config.get('MQTT', 'usr'),
                            password=config.get('MQTT', 'pswd'))

            await stack.enter_async_context(client)

            # Create chair state
            chair_state = ChairState()

            # Select topic filters
            # You can create any number of topic filters
            topic_filters = (
                "sensors/#",
                # TODO add more filters
            )

            # Log all messages
            # for topic_filter in topic_filters:
            #     # Log all messages that matches the filter
            #     manager = client.filtered_messages(topic_filter)
            #     messages = await stack.enter_async_context(manager)
            #     template = f'[topic_filter="{topic_filter}"] {{}}'
            #     task = asyncio.create_task(log_messages(messages, template))
            #     tasks.add(task)

            # Messages that doesn't match a filter will get logged here
            messages = await stack.enter_async_context(
                client.unfiltered_messages())
            task = asyncio.create_task(
                log_messages(messages, "[unfiltered] {}"))
            tasks.add(task)

            # Subscribe to pressure sensors
            await client.subscribe("sensors/pressure")
            manager = client.filtered_messages('sensors/pressure')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_sensors_pressure(client, messages, chair_state))
            tasks.add(task)

            # Subscribe to angle sensors
            await client.subscribe("sensors/angle")
            manager = client.filtered_messages('sensors/angle')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_sensors_angle(client, messages, chair_state))
            tasks.add(task)

            # Subscribe to travel sensors
            await client.subscribe("sensors/travel")
            manager = client.filtered_messages('sensors/travel')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_sensors_travel(client, messages, chair_state))
            tasks.add(task)

            # Subscribe to alarm sensors
            await client.subscribe("sensors/alarm/state")
            manager = client.filtered_messages('sensors/alarm/state')
            messages = await stack.enter_async_context(manager)
            task = asyncio.create_task(
                handle_sensors_alarm(client, messages, chair_state))
            tasks.add(task)

            # Start periodic publish of chair state
            task = asyncio.create_task(publish_chair_state(
                client, chair_state))
            tasks.add(task)

        # Wait for everything to complete (or fail due to, e.g., network errors)
        await asyncio.gather(*tasks)