Beispiel #1
0
    def mqtt_message(self, topic, msg):
        # try to find a device by matching known FullTopics against the MQTT topic of the message
        device = self.env.find_device(topic)
        if device:
            if topic.endswith("LWT"):
                if not msg:
                    msg = "Offline"
                device.update_property("LWT", msg)

                if msg == 'Online':
                    # known device came online, query initial state
                    self.initial_query(device, True)

            else:
                # forward the message for processing
                device.parse_message(topic, msg)
                if device.debug:
                    logging.debug("MQTT: %s %s", topic, msg)

        else:  # unknown device, start autodiscovery process
            if topic.endswith("LWT"):
                self.env.lwts.append(topic)
                logging.info("DISCOVERY: LWT from an unknown device %s", topic)

                # STAGE 1
                # load default and user-provided FullTopic patterns and for all the patterns,
                # try matching the LWT topic (it follows the device's FullTopic syntax

                for p in default_patterns + custom_patterns:
                    match = re.fullmatch(
                        p.replace("%topic%", "(?P<topic>.*?)").replace(
                            "%prefix%", "(?P<prefix>.*?)") + ".*$", topic)
                    if match:
                        # assume that the matched topic is the one configured in device settings
                        possible_topic = match.groupdict().get('topic')
                        if possible_topic not in ('tele', 'stat'):
                            # if the assumed topic is different from tele or stat, there is a chance that it's a valid topic
                            # query the assumed device for its FullTopic. False positives won't reply.
                            possible_topic_cmnd = p.replace(
                                "%prefix%", "cmnd").replace(
                                    "%topic%", possible_topic) + "FullTopic"
                            logging.debug(
                                "DISCOVERY: Asking an unknown device for FullTopic at %s",
                                possible_topic_cmnd)
                            self.mqtt_queue.append([possible_topic_cmnd, ""])

            elif topic.endswith("RESULT") or topic.endswith(
                    "FULLTOPIC"):  # reply from an unknown device
                # STAGE 2
                full_topic = loads(msg).get('FullTopic')
                if full_topic:
                    # the device replies with its FullTopic
                    # here the Topic is extracted using the returned FullTopic, identifying the device
                    parsed = parse_topic(full_topic, topic)
                    if parsed:
                        # got a match, we query the device's MAC address in case it's a known device that had its topic changed
                        logging.debug(
                            "DISCOVERY: topic %s is matched by fulltopic %s",
                            topic, full_topic)

                        d = self.env.find_device(topic=parsed['topic'])
                        if d:
                            d.update_property("FullTopic", full_topic)
                        else:
                            logging.info(
                                "DISCOVERY: Discovered topic=%s with fulltopic=%s",
                                parsed['topic'], full_topic)
                            d = TasmotaDevice(parsed['topic'], full_topic)
                            self.env.devices.append(d)
                            self.device_model.addDevice(d)
                            logging.debug(
                                "DISCOVERY: Sending initial query to topic %s",
                                parsed['topic'])
                            self.initial_query(d, True)
                            self.env.lwts.remove(d.tele_topic("LWT"))
                        d.update_property("LWT", "Online")
Beispiel #2
0
    def mqtt_message(self, topic, msg):
        # try to find a device by matching known FullTopics against the MQTT topic of the message
        device = self.env.find_device(topic)
        if device:
            if topic.endswith("LWT"):
                if not msg:
                    msg = "Offline"
                device.update_property("LWT", msg)

                if msg == 'Online':
                    # known device came online, query initial state
                    self.initial_query(device, True)

            else:
                # forward the message for processing
                device.parse_message(topic, msg)

        else:  # unknown device, start autodiscovery process
            if topic.endswith("LWT"):
                # STAGE 1
                # load default and user-provided FullTopic patterns and for all the patterns,
                # try matching the LWT topic (it follows the device's FullTopic syntax

                for p in default_patterns + custom_patterns:
                    match = re.fullmatch(
                        p.replace("%topic%", "(?P<topic>.*?)").replace(
                            "%prefix%", "(?P<prefix>.*?)") + ".*$", topic)
                    if match:
                        # assume that the matched topic is the one configured in device settings
                        possible_topic = match.groupdict().get('topic')
                        if possible_topic not in ('tele', 'stat'):
                            # if the assumed topic is different from tele or stat, there is a chance that it's a valid topic
                            # query the assumed device for its FullTopic. False positives won't reply.
                            self.mqtt_queue.append([
                                p.replace("%prefix%", "cmnd").replace(
                                    "%topic%", possible_topic) + "FullTopic",
                                ""
                            ])

            elif topic.endswith("RESULT"):  # reply from an unknown device
                # STAGE 2
                try:
                    full_topic = loads(msg).get('FullTopic')
                    if full_topic:
                        # the device replies with its FullTopic
                        # here the Topic is extracted using the returned FullTopic, identifying the device
                        parsed = parse_topic(full_topic, topic)
                        if parsed:
                            # got a match, we query the device's MAC address in case it's a known device that had its topic changed

                            d = self.env.find_device(topic=parsed['topic'])
                            if d:
                                d.update_property("FullTopic", full_topic)
                            else:
                                print("DISCOVERED", parsed['topic'])
                                d = TasmotaDevice(parsed['topic'], full_topic)
                                self.env.devices.append(d)
                                self.device_model.addDevice(d)
                                self.initial_query(d, True)
                            d.update_property("LWT", "Online")

                except JSONDecodeError as e:
                    with open("{}/TDM/error.log".format(QDir.homePath()),
                              "a+") as l:
                        l.write("{}\t{}\t{}\t{}\n".format(
                            QDateTime.currentDateTime().toString(
                                "yyyy-MM-dd hh:mm:ss"), topic, msg, e.msg))