コード例 #1
0
 def run(self) -> None:
     self.log.trace("Message Bus Receive thread started successfully")
     try:
         while not poison_pill:
             try:
                 message = receive_queue.get(timeout=1)
             except QueueEmptyError:
                 pass
             else:
                 if isinstance(message, SubscribeMessage):
                     self.log.trace("Message received on receive queue: %s",
                                    message)
                     node, prop = get_property_from_path(message.path)
                     if node and prop and prop.callback:
                         message.callback = prop.callback
                         getattr(sys.modules[node.module],
                                 ATTR_QSUBSCRIBE).put_nowait(message)
                     elif not prop:
                         self.log.debug(
                             "Received message on unregistered path: %s",
                             message)
                 else:
                     try:
                         self.log.warn(
                             "Got unrecognized message on receive queue: %s",
                             message)
                     except:
                         self.log.warn(
                             "Got unrecognized message on receive queue")
     except Exception as err:  # pylint: disable=broad-except
         self.log.error("Error on Message Bus Receive thread")
         self.log.error("  %s", err)
         logger.log_traceback(self.log)
     else:
         self.log.debug("Message Bus Receive thread stopped cleanly")
コード例 #2
0
 def run(self) -> None:
     self.log.trace("Message Bus Transmit thread started successfully")
     try:
         while not poison_pill:
             try:
                 message = publish_queue.get(timeout=1)
             except QueueEmptyError:
                 pass
             else:
                 if isinstance(message, PublishMessage):
                     self.log.trace("Message received on publish queue: %s",
                                    message)
                     for q in transmit_queues:
                         transmit_queues[q].put_nowait(message)
                 else:
                     try:
                         self.log.warn(
                             "Got unrecognized message on publish queue: %s",
                             message)
                     except:
                         self.log.warn(
                             "Got unrecognized message on publish queue")
     except Exception as err:  # pylint: disable=broad-except
         self.log.error("Error on Message Bus Transmit thread")
         self.log.error("  %s", err)
         logger.log_traceback(self.log)
     else:
         self.log.debug("Message Bus Transmit thread stopped cleanly")
コード例 #3
0
def set_pin(pin, payload):
    """
    Set the state of a pin and publish
    ``payload`` expects ``payload on`` or ``payload off``
    """
    if payload == config[CONF_KEY_PAYLOAD_ON]:
        state = True
    elif payload == config[CONF_KEY_PAYLOAD_OFF]:
        state = False
    else:
        log.warn(
            "Received unrecognized SET payload '{payload}' for '{name}' on GPIO{pin:02d}"
            .format(name=pins[pin]["name"], payload=payload, pin=pin))
        return

    try:
        gpio.output(pin, state ^ pins[pin][CONF_KEY_INVERT])
    except:
        log.error(
            "An exception occurred while setting '{name}' on GPIO{pin:02d}".
            format(name=pins[pin]["name"], pin=pin))
        log_traceback(log)
    else:
        log.debug(
            "Set '{name}' on GPIO{pin:02d} to '{state}' logic {logic}".format(
                name=pins[pin]["name"],
                pin=pin,
                state=payload,
                logic=TEXT_LOGIC_STATE[int(state
                                           ^ pins[pin][CONF_KEY_INVERT])]))
        get_pin(pin)  # publish pin state
コード例 #4
0
 def _start_thread(thread: threading.Thread) -> None:
     try:
         log.debug("Starting Message Bus %s thread", thread.name)
         thread.start()
     except Exception as err:  # pylint: disable=broad-except
         log.error("Failed to start Message Bus %s thread", thread.name)
         log.error("  %s", err)
         logger.log_traceback(log)
コード例 #5
0
 def read(self) -> t.Union[bool, None]:
     """Read the pin state."""
     if self._setup:
         try:
             return self._interface.read()
         except GPIOError:
             log_traceback(log)
             return None
コード例 #6
0
def _load_modules(
    config_file: str, core_queue: "mproc.Queue[str]"
) -> t.List[types.ModuleType]:
    """
    Loads each module with a section in the config and spawns a process for them
    """
    config = load_config(config_file)

    if not config:
        return []

    for module_name in [key for key in config if isinstance(config[key], dict)]:
        module = None
        log.debug("Loading module '%s'", module_name)
        try:
            module = import_module(f"modules.{module_name}")

        except ImportError as err:
            log.error("Failed to import module '%s'", module_name)
            log.error("  %s", err)
            log_traceback(log)
            log.error("Module '%s' was not loaded", module_name)

        except ImportWarning as err:
            log.warn("Warnings occured when importing module '%s'", module_name)
            log.warn("  %s", err)
            log_traceback(log)
            log.error("Module '%s' was not loaded", module_name)

        else:
            if _validate_module(module):
                # call module load
                if not call(module, ATTR_LOAD, config_raw=config[module_name]):
                    log.warn("Module '%s' load failed", module_name)
                    continue
                else:
                    log.debug("Module '%s' loaded successfully", module_name)

                if getattr(module, ATTR_TYPE) == ModuleType.COMMUNICATION:
                    bus.setup_comm_module(module, core_queue)
                    communication_modules.append(module)

                elif getattr(module, ATTR_TYPE) == ModuleType.INTERFACE:
                    bus.setup_interface_module(module)
                    if not getattr(module, ATTR_NODES, {}):
                        log.error(
                            "Module '%s' contains no valid nodes and will not be loaded",
                            module_name,
                        )
                        continue
                    interface_modules.append(module)

        finally:
            del module

    del config
    return communication_modules + interface_modules
コード例 #7
0
 def cleanup(self) -> None:
     """Perform cleanup when shutting down."""
     if self._interrupt_handler:
         self._interrupt_handler.stop()
     if self._interface:
         try:
             self._interface.close()
         except GPIOError:
             log.error("An error occurred while closing %s", self.name)
             log_traceback(log)
コード例 #8
0
def dangerous_method():
    """
    When doing things that might cause a crash you can wrap them in a
    try/except and use ``log_traceback`` if something goes wrong. Each modules'
    subprocess will call the functions in the queue like this, but if you
    catch in the module you can potentially provide clearer logs about what
    went wrong.
    """
    try:
        assert False
    except:
        log.error("Something went terribly wrong!")
        log_traceback(log)
コード例 #9
0
    def _anim_loop(self, anim_args: t.Dict[str, t.Any]) -> None:
        """
        **DO NOT OVERRIDE THIS METHOD**
        Internal animation thread loop method
        """
        anim: str = anim_args[ANIM_KEY_NAME]
        repeat: int = anim_args[ANIM_KEY_REPEAT]
        remain: int = repeat or 1
        error_count: int = 0
        kwargs = {  # args to pass into anim function
            k: anim_args[k]
            for k in anim_args
            if k not in [ANIM_KEY_NAME, ANIM_KEY_PRIORITY, ANIM_KEY_REPEAT]
        }

        while remain > 0 and not self._anim_cancel.is_set():
            if self._anim_soft_cancel.is_set():
                break
            try:
                common.publish_queue.put_nowait(
                    PublishMessage(path=f"{self.id}/animation", content=anim))
                self.anims[anim].__globals__[
                    "FRAME_MS"] = self._frame_ms  # type: ignore
                self.anims[anim](self, self._anim_cancel, **kwargs)
            except:
                self._log.debug(
                    "An error occurred while running animation '%s' for array '%s'",
                    anim,
                    self._name,
                )
                error_count += 1
                if error_count > 2:
                    self._log.error(
                        "Animation '%s' for '%s' errored 3 times, aborting",
                        anim,
                        self._name,
                    )
                    log_traceback(self._log)
                    break
            else:
                remain -= 1 if repeat else 0

        if self._anim_cancel.is_set() or (anim_args.get(ANIM_KEY_REPEAT, 1) > 1
                                          and self._anim_soft_cancel.is_set()):
            self._log.debug("Cancelled animation '%s' for array '%s'", anim,
                            self._name)
        else:
            self._log.debug("Finished animation '%s' for array '%s'", anim,
                            self._name)
        common.publish_queue.put_nowait(
            PublishMessage(path=f"{self.id}/animation", content=""))
コード例 #10
0
def on_disconnect(client, userdata, rc):
    """
    Gets called when the client disconnects from the broker
    """
    for callback in on_disconnect_callbacks:
        try:
            callback["func"](*callback.get("args", []),
                             **callback.get("kwargs", {}))
        except:
            log.error(
                "An exception occurred while running on-disconnect callback '{func}'"
                .format(func=getattr(
                    callback["func"], "__name__", default=callback["func"])))
            log_traceback(log)
コード例 #11
0
ファイル: config.py プロジェクト: CrazyIvan359/mqttany
def load_config(config_file: str) -> t.Dict[str, t.Any]:
    """
    Reads configuration file and returns as dict
    """
    config: t.Dict[str, t.Any] = {}

    # attempt to determine full path if config_file is only a filename
    if not os.path.isfile(config_file):
        log.debug("Attempting to resolve config file location")
        config_file = os.path.expanduser(config_file)
        if os.path.isfile(os.path.abspath(config_file)):
            config_file = os.path.abspath(config_file)
        elif os.path.isfile(os.path.join(os.getcwd(), config_file)):
            config_file = os.path.join(os.getcwd(), config_file)
        else:
            log.debug("Unable to resolve config file location")
            config_file = ""

    if config_file:
        log.debug("Loading config file")
        try:
            with open(config_file) as fh:
                config = yaml.load(
                    fh,
                    Loader=yamlloader.ordereddict.CSafeLoader)  # type: ignore
        except:
            log.error("Config file contains errors")
            log_traceback(log, limit=0)

        if [
                int(s)
                for s in str(config.get(CONF_KEY_VERSION, "0.0")).split(".")
        ] < CONFIG_VERSION:
            if CONF_KEY_VERSION in config:
                log.error("Config file version is '%s'",
                          config[CONF_KEY_VERSION])
            else:
                log.error("Config file does not specify a version")
            log.error(
                "This version of MQTTany requires a minimum config file version of '%s'",
                ".".join([str(i) for i in CONFIG_VERSION]),
            )
            config = {}
        else:
            config.pop(CONF_KEY_VERSION, None)
    else:
        log.error("Config file does not exist: %s", config_file)

    return config
コード例 #12
0
def _call_func(module, name, **kwargs):
    """
    Calls ``name`` if define in ``module``
    """
    func = getattr(module, name, None)
    if func is not None:
        retval = False
        if callable(func):
            try:
                retval = func(**kwargs)
            except:
                log.error("An exception occurred while running function '{func}'".format(func=getattr(func, "__name__", func)))
                log_traceback(log)
            finally:
                return retval
コード例 #13
0
 def get(self) -> t.Union[bool, None]:
     """
     Reads the pin state, return ``None`` if read fails
     """
     if self._setup:
         handle = t.cast(CoreDigital, self._handle)
         try:
             return bool(handle.read() ^ self._invert)  # type:ignore
         except:
             self._log.error(
                 "An exception occurred while reading '%s' on %s",
                 self.name,
                 self.pin_name,
             )
             log_traceback(self._log)
     return None
コード例 #14
0
 def _setup_sysfs(self) -> bool:
     try:
         log.debug("Setting up pin %s using sysfs", self.name)
         self._interface = GPIO(self.soc, periphery_PinMode[self.mode])
     except GPIOError as err:
         if err.errno == 16:  # Device or resource busy
             log.error("Failed to setup %s using sysfs, pin is in use",
                       self.name)
         else:
             log.error("Failed to setup %s using sysfs", self.name)
             log_traceback(log)
     except TimeoutError:
         log.error("Unable to setup %s using sysfs, system calls timed out",
                   self.name)
     else:
         return True
     return False
コード例 #15
0
 def write(self, state: bool) -> None:
     """Write the state of the pin."""
     if self._setup:
         try:
             self._interface.write(state)
         except GPIOError as err:
             if err.errno == 1:  # Operation not permitted
                 log.error(
                     "Failed to write to to %s, operation not permitted",
                     self.name)
             elif err.errno == 22:  # Invalid arg (this is not a user error!)
                 log.error(
                     "Failed to setup %s using cdev, an invalid argument was given",
                     self.name,
                 )
             else:
                 log_traceback(log)
             raise
コード例 #16
0
def call(module: types.ModuleType, name: str, **kwargs: t.Any) -> t.Any:
    """
    Calls ``name`` if defined in ``module``
    """
    func = getattr(module, name, None)
    if func is not None:
        retval = False
        if callable(func):
            try:
                retval = func(**kwargs)
            except:
                module.log.error(  # type: ignore
                    "An exception occurred while running function '%s'",
                    getattr(func, "__name__", func),
                )
                log_traceback(module.log)  # type: ignore
            finally:
                # This function intentionally swallows exceptions. It is only used by
                # the core to call functions in modules. If there is an error in a
                # module the core must continue to run in order to exit gracefully.
                # If the core were to stop because of exceptions in modules, all child
                # processes would be orphaned and would have to be killed by manually
                # sending SIG.TERM or SIG.KILL to them.
                return retval  # pylint: disable=lost-exception
コード例 #17
0
def get_pin(pin):
    """
    Read the state from a pin and publish
    """
    try:
        state = bool(gpio.input(pin)) ^ pins[pin][
            CONF_KEY_INVERT]  # apply the invert flag
    except:
        log.error(
            "An exception occurred while reading '{name}' on GPIO{pin:02d}".
            format(name=pins[pin]["name"], pin=pin))
        log_traceback(log)
    else:
        log.debug(
            "Read state '{state}' logic {logic} from '{name}' on GPIO{pin:02d}"
            .format(name=pins[pin]["name"],
                    state=config[CONF_KEY_PAYLOAD_ON]
                    if state else config[CONF_KEY_PAYLOAD_OFF],
                    logic=TEXT_LOGIC_STATE[int(state
                                               ^ pins[pin][CONF_KEY_INVERT])],
                    pin=pin))
        publish(pins[pin][CONF_KEY_TOPIC],
                payload=config[CONF_KEY_PAYLOAD_ON]
                if state else config[CONF_KEY_PAYLOAD_OFF])
コード例 #18
0
ファイル: anim.py プロジェクト: Jockra/mqttany
def load_animations() -> t.Dict[str, t.Callable[[baseArray, threading.Event], None]]:
    """
    Loads custom animations and returns a dictionary of them and the built-ins.
    """
    anims: t.Dict[
        str, t.Callable[[baseArray, threading.Event], None]
    ] = {  # built-in animations
        "on": anim_on,
        "off": anim_off,
        "set.brightness": anim_set_brightness,
        "set.array": anim_set_array,
        "set.pixel": anim_set_pixel,
        "fade.on": anim_fade_on,
        "fade.off": anim_fade_off,
        "fade.brightness": anim_fade_brightness,
        "fade.array": anim_fade_array,
        "fade.pixel": anim_fade_pixel,
        "test.order": anim_testorder,
        "test.array": anim_testarray,
    }
    utils: t.List[t.Callable[[baseArray, *t.Any], t.Any]] = [  # utility functions
        parse_color,
        parse_pixel,
    ]

    log.debug("Loading animations")

    animpaths: t.List[str] = [DEFAULT_PATH] if os.path.isdir(DEFAULT_PATH) else []
    animpaths += (
        CONFIG[CONF_KEY_ANIM_DIR]
        if isinstance(CONFIG[CONF_KEY_ANIM_DIR], list)
        else [CONFIG[CONF_KEY_ANIM_DIR]]
    )
    for animpath in animpaths:
        if os.path.isdir(animpath):
            log.debug("Checking for animation files in '%s'", animpath)
            for filename in os.listdir(animpath):
                if (
                    os.path.splitext(filename)[-1] == ".py"
                    and filename != "__init__.py"
                ):
                    log.trace(
                        "Attempting to import animation file '%s'",
                        os.path.join(animpath, filename),
                    )
                    mod_anims = []

                    try:
                        spec = importlib.util.spec_from_file_location("*", filename)  # type: ignore
                        module = importlib.util.module_from_spec(spec)
                        spec.loader.exec_module(module)  # type: ignore
                    except:
                        log.error(
                            "An error occured while importing animation file '%s'",
                            filename,
                        )
                        log_traceback(log)
                        log.error("Animation file '%s' was not loaded", filename)
                    else:
                        log.trace(
                            "Animation file '%s' imported successfully", module.__name__
                        )

                        # get all functions in module that start with "anim_" and don't have a conflicting name
                        mod_anims = dict(inspect.getmembers(module, inspect.isfunction))
                        for func_name in [key for key in mod_anims]:
                            if not func_name.startswith("anim_"):
                                mod_anims.pop(func_name, None)
                                log.trace(
                                    "Ignoring function '%s' in '%s' as it does not start with 'anim_",
                                    func_name,
                                    os.path.join(animpath, filename),
                                )
                            elif not callable(mod_anims[func_name]):
                                # TODO check function signatures
                                mod_anims.pop(func_name, None)
                                log.warn(
                                    "Ignoring animation '%s.%s' in '%s' as it is not callable",
                                    module.__name__,
                                    func_name[5:],
                                    os.path.join(animpath, filename),
                                )
                            elif f"{module.__name__}.{func_name[5:]}" in mod_anims:
                                mod_anims.pop(func_name, None)
                                log.warn(
                                    "Duplicate animation '%s.%s' in '%s' is being ignored",
                                    module.__name__,
                                    func_name[5:],
                                    os.path.join(animpath, filename),
                                )

                        # add all functions to main anim list, names are "module.funcname" with "anim_" prefix removed
                        for func_name in mod_anims:
                            anims[f"{module.__name__}.{func_name[5:]}"] = mod_anims[
                                func_name
                            ]
                            log.trace(
                                "Animation '%s.%s' added",
                                module.__name__,
                                func_name[5:],
                            )

                        log.debug(
                            "Loaded %d animations from '%s'",
                            len(mod_anims),
                            os.path.join(animpath, filename),
                        )

                else:
                    log.trace("Skipping file '%s'", os.path.join(animpath, filename))
        else:
            log.warn("Animation path '%s' is not a directory", animpath)

    # add utils to anims
    for func_name in anims:
        func_globals = t.cast(t.Dict[str, t.Any], anims[func_name].__globals__)  # type: ignore
        func_globals["log"] = logger.get_logger(f"led.anim.{func_name}")
        func_globals["Color"] = Color
        for util in utils:
            func_globals[util.__name__] = util

    return anims
コード例 #19
0
    def begin(self) -> bool:
        """Setup the LED array"""
        self._log.info(
            "Setting up '%s' on GPIO%02d with %d %s LEDS %s",
            self._name,
            self._pin,
            self._count,
            self._chip,
            f"with {self._per_pixel} LEDs per pixel"
            if self._per_pixel > 1 else "",
        )

        try:
            import rpi_ws281x
        except ModuleNotFoundError:
            self._log.error(
                "MQTTany's LED module requires 'rpi-ws281x' to be installed, "
                "please see the wiki for instructions on how to install requirements"
            )
            return False

        if self._pin != 10:
            if not os.access("/dev/mem", os.R_OK | os.W_OK,
                             effective_ids=True):
                self._log.error(
                    "No read/write access to '/dev/mem', try running with root privileges"
                )
                return False

        if gpio.board.lock(self._pin, gpio.common.Mode.SOC):
            try:
                self._array = rpi_ws281x.PixelStrip(
                    num=self._count * self._per_pixel,
                    pin=self._pin,
                    freq_hz=self._frequency * 1000,
                    dma=DMA_CHANNEL[self._pin],
                    invert=self._invert,
                    brightness=self._init_brightness,
                    channel=PWM_CHANNEL[self._pin],
                    strip_type=LED_COLOR_ORDERS[self._order] +
                    LED_TYPES[self._chip],
                )
                self._array.begin()
            except:
                self._log.error("An error occured while setting up '%s'",
                                self._name)
                logger.log_traceback(self._log)
                return False
            else:
                super().begin()
                common.publish_queue.put_nowait(
                    PublishMessage(path=f"{self.id}/gpio",
                                   content=self._pin,
                                   mqtt_retained=True))
                common.publish_queue.put_nowait(
                    PublishMessage(path=f"{self.id}/chip",
                                   content=self._chip,
                                   mqtt_retained=True))
                common.publish_queue.put_nowait(
                    PublishMessage(
                        path=f"{self.id}/frequency",
                        content=self._frequency,
                        mqtt_retained=True,
                    ))
                common.publish_queue.put_nowait(
                    PublishMessage(
                        path=f"{self.id}/invert",
                        content=self._invert,
                        mqtt_retained=True,
                    ))
                del self._init_brightness
                del self._chip
                del self._frequency
                del self._invert
                self._setup = True

        return self._setup
コード例 #20
0
        log.warn("#######################################")
        log.warn("")

    try:
        core.start(queue_core, args.config_file)
        while not poison_pill and not signal.exit:
            try:  # to get an item from the queue
                message = queue_core.get_nowait()
            except QueueEmptyError:
                time.sleep(0.1)  # 100ms
            else:
                poison_pill = True
                log.debug("Received exit request from {}".format(message))

    except:
        logger.log_traceback(log)
        poison_pill = True

    else:
        if signal.signal == signal.SIGINT:
            print()  # newline after '^C'
        core.stop()

    finally:
        if poison_pill:
            log.warn("MQTTany exiting with errors")
        else:
            log.info("MQTTany stopped")

        logger.uninit()
        exit(int(poison_pill))
コード例 #21
0
def pre_loop():
    """
    Actions to be done in the subprocess before the loop starts
    """
    log.debug("Setting up hardware")
    for pin in pins:
        log.info("Setting up '{name}' on GPIO{pin:02d} as {direction}".format(
            name=pins[pin]["name"],
            pin=pin,
            direction=TEXT_DIRECTION[pins[pin][CONF_KEY_DIRECTION]]))
        log.debug("  with options [{options}]".format(options=pins[pin]))

        if not acquire_gpio_lock(pin, TEXT_NAME, timeout=2000):
            log.error(
                "Failed to acquire a lock on GPIO{pin:02d}".format(pin=pin))
            pins.pop(pin)
            continue

        try:
            gpio.setup(pin,
                       pins[pin][CONF_KEY_DIRECTION],
                       pull_up_down=pins[pin][CONF_KEY_RESISTOR])
        except:
            log.error(
                "An exception occurred while setting up '{name}' on GPIO{pin:02d}"
                .format(name=pins[pin]["name"], pin=pin))
            log_traceback(log)
            release_gpio_lock(pin, TEXT_NAME)
            pins.pop(pin)
            continue

        if pins[pin][CONF_KEY_DIRECTION] == GPIO.IN and pins[pin][
                CONF_KEY_INTERRUPT] is not None:
            log.debug(
                "Adding interrupt event for '{name}' on GPIO{pin:02d} with edge trigger '{edge}'"
                .format(name=pins[pin]["name"],
                        pin=pin,
                        edge=TEXT_INTERRUPT[pins[pin][CONF_KEY_INTERRUPT]]))
            gpio.add_event_detect(pin,
                                  pins[pin][CONF_KEY_INTERRUPT],
                                  callback=interrupt_handler,
                                  bouncetime=config[CONF_KEY_DEBOUNCE])
        elif pins[pin][CONF_KEY_DIRECTION] == GPIO.OUT:
            log.debug(
                "Adding MQTT subscriptions for '{name}' on GPIO{pin:02d}".
                format(name=pins[pin]["name"], pin=pin))
            subscribe(pins[pin][CONF_KEY_TOPIC] + "/{setter}",
                      callback=callback_setter,
                      subtopics=["{module_topic}"],
                      substitutions={
                          "module_topic": config[CONF_KEY_TOPIC],
                          "module_name": TEXT_NAME,
                          "setter": config[CONF_KEY_TOPIC_SETTER],
                          "pin": pin
                      })
            if pins[pin][CONF_KEY_INITIAL] in [
                    config[CONF_KEY_PAYLOAD_ON], config[CONF_KEY_PAYLOAD_OFF]
            ]:
                log.debug(
                    "Setting '{name}' on GPIO{pin:02d} to initial state '{state}'"
                    .format(name=pins[pin]["name"],
                            pin=pin,
                            state=pins[pin][CONF_KEY_INITIAL]))
                set_pin(pin, pins[pin][CONF_KEY_INITIAL])
            else:
                log.warn(
                    "Invalid initial state '{initial_state}' for '{name}' on GPIO{pin:02d}, setting pin to '{state}'"
                    .format(name=pins[pin]["name"],
                            initial_state=pins[pin][CONF_KEY_INITIAL],
                            pin=pin,
                            state=config[CONF_KEY_PAYLOAD_OFF]))
                set_pin(pin, config[CONF_KEY_PAYLOAD_OFF])

        subscribe(pins[pin][CONF_KEY_TOPIC] + "/{getter}",
                  callback=callback_getter,
                  subtopics=["{module_topic}"],
                  substitutions={
                      "module_topic": config[CONF_KEY_TOPIC],
                      "module_name": TEXT_NAME,
                      "getter": config[CONF_KEY_TOPIC_GETTER]
                  })

    log.debug("Adding MQTT subscription to poll topic")
    subscribe(config[CONF_KEY_TOPIC_GETTER],
              callback=callback_poll_all,
              subtopics=["{module_topic}"],
              substitutions={
                  "module_topic": config[CONF_KEY_TOPIC],
                  "module_name": TEXT_NAME,
              })

    if config[CONF_KEY_POLL_INT] > 0:
        log.debug("Starting polling timer with interval of {interval}s".format(
            interval=config[CONF_KEY_POLL_INT]))
        global polling_timer
        polling_timer = Timer(config[CONF_KEY_POLL_INT], poll_interval)
        polling_timer.start()

    log.debug("Publishing initial pin states")
    poll_all()
コード例 #22
0
def _on_connect(client, userdata, flags, rc):
    """
    Gets called when the client connect attempt finishes
    """
    global retries

    if rc == 0:  # connected successfully
        log.info("Connected to broker '{host}:{port}'".format(
            host=config[CONF_KEY_HOST], port=config[CONF_KEY_PORT]))
        retries = MQTT_MAX_RETRIES  # reset max retries counter
        log.debug("Resuming previous session"
                  if flags["session present"] else "Starting new session")
        client.publish(topic=resolve_topic(config[CONF_KEY_TOPIC_LWT]),
                       payload="Online",
                       retain=True)
        for sub in subscriptions:
            subscribe(**sub)
        for callback in on_connect_callbacks:
            try:
                callback["func"](*callback.get("args", []),
                                 **callback.get("kwargs", {}))
            except:
                log.error(
                    "An exception occurred while running on-connect callback '{func}'"
                    .format(func=getattr(callback["func"],
                                         "__name__",
                                         default=callback["func"])))
                log_traceback(log)

    elif rc == 1:  # refused: incorrect mqtt protocol version
        log.error(
            "Connection refused: broker uses a different MQTT protocol version"
        )
        client.disconnect()
        main_queue.put_nowait(POISON_PILL)

    elif rc == 2:  # refused: client_id invalid
        log.error(
            "Connection refused: client_id '{client_id}' is invalid".format(
                client_id=config[CONF_KEY_CLIENTID]))
        client.disconnect()
        main_queue.put_nowait(POISON_PILL)

    elif rc == 3:  # refused: server unavailable
        retries -= 1
        if retries > 0:
            log.warn(
                "Connection attempt failed, server did not respond. {retries} retries left"
                .format(retries=retries))
        else:  # too many retries, give up
            log.error("Connection to broker failed, server did not respond.")
            client.disconnect()
            main_queue.put_nowait(POISON_PILL)

    elif rc == 4:  # refused: bad username and/or password
        log.error("Connection refused: username or password incorrect")
        client.disconnect()
        main_queue.put_nowait(POISON_PILL)

    elif rc == 5:  # refused: not authorized
        log.error("Connection refused: you are not authorized on this broker")
        client.disconnect()
        main_queue.put_nowait(POISON_PILL)

    else:  # invalid rc
        log.error(
            "Connection failed: invalid return code '{code}' received".format(
                code=rc))
        client.disconnect()
        main_queue.put_nowait(POISON_PILL)