Ejemplo n.º 1
0
        def _worker(host, port):
            try:
                if exclude_local and (host == 'localhost'
                                      or host == Config.get('device_id')):
                    return

                server_status = self.status(host=host, port=port).output
                client_status = self.status(host=host, port=port,
                                            client=Config.get('device_id')).output

                if client_status.get('config', {}).get('volume', {}).get('muted'):
                    return

                group = [g for g in server_status.get('groups', {})
                         if g.get('id') == client_status.get('group_id')].pop(0)

                if group.get('muted'):
                    return

                stream = [s for s in server_status.get('streams')
                          if s.get('id') == group.get('stream_id')].pop(0)

                if stream.get('status') != 'playing':
                    return

                playing_hosts[host] = port
            except Exception as e:
                self.logger.warning(('Error while retrieving the status of ' +
                                     'Snapcast host at {}:{}: {}').format(
                    host, port, str(e)))
Ejemplo n.º 2
0
    def __init__(self,
                 target=None,
                 origin=None,
                 id=None,
                 timestamp=None,
                 disable_logging=False,
                 disable_web_clients_notification=False,
                 **kwargs):
        """
        Params:
            target  -- Target node [String]
            origin  -- Origin node (default: current node) [String]
            id      -- Event ID (default: auto-generated)
            kwargs  -- Additional arguments for the event [kwDict]
        """

        super().__init__(timestamp=timestamp)
        self.id = id if id else self._generate_id()
        self.target = target if target else Config.get('device_id')
        self.origin = origin if origin else Config.get('device_id')
        self.type = '{}.{}'.format(self.__class__.__module__,
                                   self.__class__.__name__)
        self.args = kwargs
        self.disable_logging = disable_logging
        self.disable_web_clients_notification = disable_web_clients_notification

        for arg, value in self.args.items():
            if arg != 'args':
                self.__setattr__(arg, value)
Ejemplo n.º 3
0
    def __init__(self, config_file=None, backend=None, on_response=None):
        """
        Constructor.
        Params:
            config_file -- Path to the configuration file - default:
                           ~/.config/platypush/config.yaml or
                           /etc/platypush/config.yaml)
            backend     -- Name of the backend where pusher will send the
                           request and wait for the response (kafka
                           or pushbullet). Default: whatever is specified
                           with pusher=true in your configuration file
            on_response -- Method that will be invoked upon response receipt.
                           Takes a platypush.message.response.Response as arg.
                           Default: print the response and exit.
        """

        # Initialize the configuration
        self.config_file = config_file
        log_conf = Config.get('logging')
        Config.init(config_file)
        logging.basicConfig(level=log_conf['level'] if log_conf
                            and 'level' in log_conf else logging.info,
                            stream=sys.stdout)

        self.on_response = on_response or self.default_on_response()
        self.backend = backend or Config.get_default_pusher_backend()
        self.bus = Bus()
Ejemplo n.º 4
0
    def __init__(self, bus=None, **kwargs):
        """
        Params:
            bus    -- Reference to the Platypush bus where the requests and the
                      responses will be posted [Bus]
            kwargs -- key-value configuration for this backend [Dict]
        """

        # If no bus is specified, create an internal queue where
        # the received messages will be pushed
        self.bus = bus or Bus()
        self.device_id = Config.get('device_id')
        self.thread_id = None
        self._stop = False
        self._kwargs = kwargs

        # Internal-only, we set the request context on a backend if that
        # backend is intended to react for a response to a specific request
        self._request_context = kwargs['_req_ctx'] if '_req_ctx' in kwargs \
            else None

        Thread.__init__(self)
        logging.basicConfig(
            stream=sys.stdout,
            level=Config.get('logging') if 'logging' not in kwargs else
            getattr(logging, kwargs['logging']))
Ejemplo n.º 5
0
    def stop(self):
        """ Stops the bus by sending a STOP event """
        evt = StopEvent(target=Config.get('device_id'),
                        origin=Config.get('device_id'),
                        thread_id=self.thread_id)

        self.post(evt)
Ejemplo n.º 6
0
def plugin_route(plugin):
    """ Route to the plugin pane template """
    js_folder = os.path.abspath(os.path.join(template_folder, '..', 'static', 'js'))
    style_folder = os.path.abspath(os.path.join(template_folder, '..', 'static', 'css', 'dist'))
    template_file = os.path.join(template_folder, 'plugins', plugin, 'index.html')
    script_file = os.path.join(js_folder, 'plugins', plugin, 'index.js')
    style_file = os.path.join(style_folder, 'webpanel', 'plugins', plugin+'.css')

    conf = Config.get(plugin) or {}
    if os.path.isfile(template_file):
        conf['_template_file'] = '/' + '/'.join(template_file.split(os.sep)[-3:])

    if os.path.isfile(script_file):
        conf['_script_file'] = '/'.join(script_file.split(os.sep)[-4:])

    if os.path.isfile(style_file):
        conf['_style_file'] = 'css/dist/' + style_file[len(style_folder)+1:]

    http_conf = Config.get('backend.http')
    return render_template('plugin.html',
                           plugin=plugin,
                           conf=conf,
                           template=conf.get('_template_file', {}),
                           script=conf.get('_script_file', {}),
                           style=conf.get('_style_file', {}),
                           utils=HttpUtils,
                           token=Config.get('token'),
                           websocket_port=get_websocket_port(),
                           template_folder=template_folder,
                           static_folder=static_folder,
                           has_ssl=http_conf.get('ssl_cert') is not None)
Ejemplo n.º 7
0
def get_manifests_from_conf(
        conf_file: Optional[str] = None) -> Mapping[str, Manifest]:
    import platypush
    from platypush.config import Config

    conf_args = []
    if conf_file:
        conf_args.append(conf_file)

    Config.init(*conf_args)
    app_dir = os.path.dirname(inspect.getfile(platypush))
    manifest_files = set()

    for name in Config.get_backends().keys():
        manifest_files.add(
            os.path.join(app_dir, 'backend', *name.split('.'),
                         'manifest.yaml'))

    for name in Config.get_plugins().keys():
        manifest_files.add(
            os.path.join(app_dir, 'plugins', *name.split('.'),
                         'manifest.yaml'))

    return {
        manifest_file: Manifest.from_file(manifest_file)
        for manifest_file in manifest_files
    }
Ejemplo n.º 8
0
def build(args):
    global workdir

    ports = set()
    parser = argparse.ArgumentParser(
        prog='platydock build',
        description='Build a Platypush image from a config.yaml')

    parser.add_argument('-c',
                        '--config',
                        type=str,
                        required=True,
                        help='Path to the platypush configuration file')
    parser.add_argument('-p',
                        '--python-version',
                        type=str,
                        default='3.9',
                        help='Python version to be used')

    opts, args = parser.parse_known_args(args)

    cfgfile = os.path.abspath(os.path.expanduser(opts.config))
    manifest._available_package_manager = 'apt'  # Force apt for Debian-based Docker images
    install_cmds = manifest.get_dependencies_from_conf(cfgfile)
    python_version = opts.python_version
    backend_config = Config.get_backends()

    # Container exposed ports
    if backend_config.get('http'):
        from platypush.backend.http import HttpBackend
        # noinspection PyProtectedMember
        ports.add(backend_config['http'].get('port',
                                             HttpBackend._DEFAULT_HTTP_PORT))
        # noinspection PyProtectedMember
        ports.add(backend_config['http'].get(
            'websocket_port', HttpBackend._DEFAULT_WEBSOCKET_PORT))

    if backend_config.get('tcp'):
        ports.add(backend_config['tcp']['port'])

    if backend_config.get('websocket'):
        from platypush.backend.websocket import WebsocketBackend
        # noinspection PyProtectedMember
        ports.add(backend_config['websocket'].get(
            'port', WebsocketBackend._default_websocket_port))

    dev_dir = os.path.join(workdir, Config.get('device_id'))
    generate_dockerfile(deps=dict(install_cmds),
                        ports=ports,
                        cfgfile=cfgfile,
                        device_dir=dev_dir,
                        python_version=python_version)

    subprocess.call([
        'docker', 'build', '-t',
        'platypush-{}'.format(Config.get('device_id')), dev_dir
    ])
Ejemplo n.º 9
0
    def get_config(self, entry: Optional[str] = None) -> dict:
        """
        Return the configuration of the application or of a section.

        :param entry: [Optional] configuration entry name to retrieve (e.g. ``workdir`` or ``backend.http``).
        :return: The requested configuration object.
        """
        if entry:
            return Config.get(entry)

        cfg = Config.get()
        return cfg
Ejemplo n.º 10
0
    def build(cls, action):
        action = super().parse(action)
        action['origin'] = Config.get('device_id')

        if 'target' not in action:
            action['target'] = action['origin']

        token = Config.get('token')
        if token:
            action['token'] = token

        return super().build(action)
Ejemplo n.º 11
0
def dashboard():
    """ Route for the fullscreen dashboard """
    http_conf = Config.get('backend.http')
    dashboard_conf = http_conf.get('dashboard', {})

    return render_template('dashboard.html',
                           config=dashboard_conf,
                           utils=HttpUtils,
                           token=Config.get('token'),
                           static_folder=static_folder,
                           template_folder=template_folder,
                           websocket_port=get_websocket_port(),
                           has_ssl=http_conf.get('ssl_cert') is not None)
Ejemplo n.º 12
0
    def __init__(self, target=None, origin=None, id=None, **kwargs):
        """
        Params:
            target  -- Target node [String]
            origin  -- Origin node (default: current node) [String]
            id      -- Event ID (default: auto-generated)
            kwargs  -- Additional arguments for the event [kwDict]
        """

        self.id = id if id else self._generate_id()
        self.target = target if target else Config.get('device_id')
        self.origin = origin if origin else Config.get('device_id')
        self.type = '{}.{}'.format(self.__class__.__module__,
                                   self.__class__.__name__)
        self.args = kwargs
Ejemplo n.º 13
0
    def build(cls, msg):
        """ Builds an event message from a JSON UTF-8 string/bytearray, a
        dictionary, or another Event """

        msg = super().parse(msg)
        event_type = msg['args'].pop('type')
        event_class = get_event_class_by_type(event_type)

        args = msg['args'] if 'args' in msg else {}
        args['id'] = msg['id'] if 'id' in msg else cls._generate_id()
        args['target'] = msg['target'] if 'target' in msg else Config.get(
            'device_id')
        args['origin'] = msg['origin'] if 'origin' in msg else Config.get(
            'device_id')
        return event_class(**args)
Ejemplo n.º 14
0
    def __init__(self, url, title=None, headers=None, params=None, max_entries=None,
                 extract_content=False, digest_format=None, *argv, **kwargs):
        self.workdir = os.path.join(os.path.expanduser(Config.get('workdir')), 'feeds')
        self.dbfile = os.path.join(self.workdir, 'rss.db')
        self.url = url
        self.title = title
        self.max_entries = max_entries

        # If true, then the http.webpage plugin will be used to parse the content
        self.extract_content = extract_content

        self.digest_format = digest_format.lower() if digest_format else None  # Supported formats: html, pdf

        os.makedirs(os.path.expanduser(os.path.dirname(self.dbfile)), exist_ok=True)

        if headers is None:
            headers = {}
        headers['User-Agent'] = self.user_agent

        request_args = {
            'method': 'get',
            'url': self.url,
            'headers': headers,
            'params': params or {},
        }

        super().__init__(skip_first_call=False, args=request_args, *argv, **kwargs)
Ejemplo n.º 15
0
    def __init__(self, url, title=None, headers=None, params=None, max_entries=None,
                 extract_content=False, digest_format=None, user_agent: str = user_agent,
                 body_style: str = 'font-size: 22px; ' +
                                   'font-family: "Merriweather", Georgia, "Times New Roman", Times, serif;',
                 title_style: str = 'margin-top: 30px',
                 subtitle_style: str = 'margin-top: 10px; page-break-after: always',
                 article_title_style: str = 'page-break-before: always',
                 article_link_style: str = 'color: #555; text-decoration: none; border-bottom: 1px dotted',
                 article_content_style: str = '', *argv, **kwargs):
        """
        :param url: URL to the RSS feed to be monitored.
        :param title: Optional title for the feed.
        :param headers: Extra headers to be passed to the request.
        :param params: Extra GET parameters to be appended to the URL.
        :param max_entries: Maximum number of entries that will be returned in a single
            :class:`platypush.message.event.http.rss.NewFeedEvent` event.
        :param extract_content: Whether the context should also be extracted (through the
            :class:`platypush.plugins.http.webpage.HttpWebpagePlugin` plugin) (default: ``False``).
        :param digest_format: Format of the digest output file (default: None, text. Other supported types: ``html``
            and ``pdf`` (requires the ``weasyprint`` module installed).
        :param user_agent: User agent string to be passed on the request.
        :param body_style: CSS style for the body.
        :param title_style: CSS style for the feed title.
        :param subtitle_style: CSS style for the feed subtitle.
        :param article_title_style: CSS style for the article titles.
        :param article_link_style: CSS style for the article link.
        :param article_content_style: CSS style for the article content.
        """
        self.workdir = os.path.join(os.path.expanduser(Config.get('workdir')), 'feeds')
        self.dbfile = os.path.join(self.workdir, 'rss.db')
        self.url = url
        self.title = title
        self.max_entries = max_entries
        self.user_agent = user_agent
        self.body_style = body_style
        self.title_style = title_style
        self.subtitle_style = subtitle_style
        self.article_title_style = article_title_style
        self.article_link_style = article_link_style
        self.article_content_style = article_content_style

        # If true, then the http.webpage plugin will be used to parse the content
        self.extract_content = extract_content

        self.digest_format = digest_format.lower() if digest_format else None  # Supported formats: html, pdf

        os.makedirs(os.path.expanduser(os.path.dirname(self.dbfile)), exist_ok=True)

        if headers is None:
            headers = {}
        headers['User-Agent'] = self.user_agent

        request_args = {
            'method': 'get',
            'url': self.url,
            'headers': headers,
            'params': params or {},
        }

        super().__init__(skip_first_call=False, args=request_args, *argv, **kwargs)
Ejemplo n.º 16
0
def resources_path(path):
    """ Custom static resources """
    path_tokens = path.split('/')
    filename = path_tokens.pop(-1)
    http_conf = Config.get('backend.http')
    resource_dirs = http_conf.get('resource_dirs', {})

    while path_tokens:
        if '/'.join(path_tokens) in resource_dirs:
            break
        path_tokens.pop()

    if not path_tokens:
        # Requested resource not found in the allowed resource_dirs
        abort(404)

    base_path = '/'.join(path_tokens)
    real_base_path = os.path.abspath(os.path.expanduser(resource_dirs[base_path]))
    real_path = real_base_path

    file_path = [s for s in re.sub(r'^{}(.*)$'.format(base_path), '\\1', path)
                 .split('/') if s]

    for p in file_path[:-1]:
        real_path += os.sep + p
        file_path.pop(0)

    file_path = file_path.pop(0)
    if not real_path.startswith(real_base_path):
        # Directory climbing attempt
        abort(404)

    return send_from_directory(real_path, file_path)
Ejemplo n.º 17
0
def get_or_create_ngrok_tunnel() -> str:
    """
    This method creates an ngrok tunnel for the local web application,
    useful to register public HTTPS callback URLs on the fly from plugins
    and backends.
    """
    global _app_tunnel_url
    with _app_tunnel_lock:
        if _app_tunnel_url:
            return _app_tunnel_url

        local_port = _get_http_port()

        ngrok = None
        if Config.get('ngrok'):
            ngrok = get_plugin('ngrok')

        assert ngrok, 'The ngrok plugin is required in order to subscribe to notifications'
        tunnel_response = ngrok.create_tunnel(
            resource=local_port,
            protocol='http',
            bind_tls=True,
        ).output

        _app_tunnel_url = tunnel_response.get('url')
        assert _app_tunnel_url, 'Unable to create an ngrok tunnel'
        return _app_tunnel_url
Ejemplo n.º 18
0
def _get_http_port() -> int:
    http = None
    if Config.get('backend.http'):
        http = get_backend('http')

    assert http, 'The http backend is required in order to subscribe to notifications'
    return http.port
Ejemplo n.º 19
0
    def _execute_procedure(self, *args, **kwargs):
        from platypush.config import Config
        from platypush.procedure import Procedure

        logger.info('Executing procedure request: {}'.format(self.action))
        procedures = Config.get_procedures()
        proc_name = '.'.join(self.action.split('.')[1:])
        if proc_name not in procedures:
            proc_name = self.action.split('.')[-1]

        proc_config = procedures[proc_name]
        if is_functional_procedure(proc_config):
            kwargs.update(**self.args)
            if 'n_tries' in kwargs:
                del kwargs['n_tries']

            return proc_config(*args, **kwargs)

        proc = Procedure.build(name=proc_name,
                               requests=proc_config['actions'],
                               _async=proc_config['_async'],
                               args=self.args,
                               backend=self.backend,
                               id=self.id)

        return proc.execute(*args, **kwargs)
Ejemplo n.º 20
0
    def __init__(self,
                 host: Optional[str] = None,
                 port: int = 8002,
                 timeout: Optional[int] = 5,
                 name='platypush',
                 token_file: Optional[str] = None,
                 **kwargs):
        """
        :param host: IP address or host name of the smart TV.
        :param port: Websocket port (default: 8002).
        :param timeout: Connection timeout in seconds (default: 5, specify 0 or None for no timeout).
        :param name: Name of the remote device (default: platypush).
        :param token_file: Path to the token file (default: ``~/.local/share/platypush/samsungtvws/token.txt``)
        """
        super().__init__(**kwargs)
        self.workdir = os.path.join(Config.get('workdir'), 'samsungtvws')
        if not token_file:
            token_file = os.path.join(self.workdir, 'token.txt')

        self.host = host
        self.port = port
        self.timeout = timeout
        self.name = name
        self.token_file = token_file
        self._connections: Dict[Tuple[host, port], SamsungTVWS] = {}
        os.makedirs(self.workdir, mode=0o700, exist_ok=True)
Ejemplo n.º 21
0
    def __init__(self, bus=None, **kwargs):
        """
        :param bus: Reference to the bus object to be used in the backend
        :type bus: platypush.bus.Bus

        :param kwargs: Key-value configuration for the backend
        :type kwargs: dict
        """

        self._thread_name = self.__class__.__name__
        EventGenerator.__init__(self)
        Thread.__init__(self, name=self._thread_name)

        # If no bus is specified, create an internal queue where
        # the received messages will be pushed
        self.bus = bus or Bus()
        self.device_id = Config.get('device_id')
        self.thread_id = None
        self._stop = False
        self._kwargs = kwargs
        self.logger = logging.getLogger(self.__class__.__name__)

        # Internal-only, we set the request context on a backend if that
        # backend is intended to react for a response to a specific request
        self._request_context = kwargs['_req_ctx'] if '_req_ctx' in kwargs \
            else None

        if 'logging' in kwargs:
            self.logger.setLevel(
                getattr(logging,
                        kwargs.get('logging').upper()))

        Thread.__init__(self)
Ejemplo n.º 22
0
 def __init__(self, dirs, *args, **kwargs):
     super().__init__()
     self.dirs = dirs
     db_dir = os.path.join(Config.get('workdir'), 'media')
     os.makedirs(db_dir, exist_ok=True)
     self.db_file = os.path.join(db_dir, 'media.db')
     self._db_engine = None
Ejemplo n.º 23
0
    def search_web_directory(cls, directory, *extensions):
        directory = os.path.abspath(os.path.expanduser(directory))
        resource_dirs = (Config.get('backend.http')
                         or {}).get('resource_dirs', {})
        resource_path = None
        uri = ''

        for name, resource_path in resource_dirs.items():
            resource_path = os.path.abspath(os.path.expanduser(resource_path))
            if directory.startswith(resource_path):
                subdir = re.sub('^{}(.*)$'.format(resource_path), '\\1',
                                directory)
                uri = '/resources/' + name
                break

        if not uri:
            raise RuntimeError(
                ('Directory {} not found among the available ' +
                 'static resources on the webserver').format(directory))

        results = [
            re.sub('^{}(.*)$'.format(resource_path), uri + '\\1', path)
            for path in cls.search_directory(directory, *extensions)
        ]

        return results
Ejemplo n.º 24
0
    def __init__(self,
                 device: str,
                 config_path: Optional[str] = None,
                 user_path: Optional[str] = None,
                 ready_timeout: float = 10.0,
                 *args,
                 **kwargs):
        """
        :param device: Path to the Z-Wave adapter (e.g. /dev/ttyUSB0 or /dev/ttyACM0).
        :param config_path: Z-Wave configuration path (default: ``<OPENZWAVE_PATH>/ozw_config``).
        :param user_path: Z-Wave user path where runtime and configuration files will be stored
            (default: ``<PLATYPUSH_WORKDIR>/zwave``).
        :param ready_timeout: Network ready timeout in seconds (default: 60).
        """
        import python_openzwave
        from openzwave.network import ZWaveNetwork

        super().__init__(*args, **kwargs)
        self.device = device

        if not config_path:
            config_path = os.path.join(
                os.path.dirname(inspect.getfile(python_openzwave)),
                'ozw_config')
        if not user_path:
            user_path = os.path.join(Config.get('workdir'), 'zwave')
            os.makedirs(user_path, mode=0o770, exist_ok=True)

        self.config_path = config_path
        self.user_path = user_path
        self.ready_timeout = ready_timeout
        self.network: Optional[ZWaveNetwork] = None
Ejemplo n.º 25
0
    def _expand_context(self, event_args=None, **context):
        from platypush.config import Config

        if event_args is None: event_args = copy.deepcopy(self.args)

        constants = Config.get_constants()
        context['constants'] = {}
        for (name,value) in constants.items():
            context['constants'][name] = value

        keys = []
        if isinstance(event_args, dict):
            keys = event_args.keys()
        elif isinstance(event_args, list):
            keys = range(0, len(event_args))

        for key in keys:
            value = event_args[key]

            if isinstance(value, str):
                value = self.expand_value_from_context(value, **context)
            elif isinstance(value, dict) or isinstance(value, list):
                self._expand_context(event_args=value, **context)

            event_args[key] = value

        return event_args
Ejemplo n.º 26
0
def index():
    """ Route to the main web panel """
    configured_plugins = Config.get_plugins()
    enabled_templates = {}
    enabled_scripts = {}
    enabled_styles = {}

    js_folder = os.path.abspath(
        os.path.join(template_folder, '..', 'static', 'js'))
    style_folder = os.path.abspath(
        os.path.join(template_folder, '..', 'static', 'css', 'dist'))

    for plugin, conf in configured_plugins.items():
        template_file = os.path.join(template_folder, 'plugins', plugin,
                                     'index.html')

        script_file = os.path.join(js_folder, 'plugins', plugin, 'index.js')
        style_file = os.path.join(style_folder, 'webpanel', 'plugins',
                                  plugin + '.css')

        if os.path.isfile(template_file):
            conf['_template_file'] = '/' + '/'.join(
                template_file.split(os.sep)[-3:])
            enabled_templates[plugin] = conf

        if os.path.isfile(script_file):
            conf['_script_file'] = '/'.join(script_file.split(os.sep)[-4:])
            enabled_scripts[plugin] = conf

        if os.path.isfile(style_file):
            conf['_style_file'] = 'css/dist/' + style_file[len(style_folder) +
                                                           1:]
            enabled_styles[plugin] = conf

    http_conf = Config.get('backend.http')
    return render_template('index.html',
                           templates=enabled_templates,
                           scripts=enabled_scripts,
                           styles=enabled_styles,
                           utils=HttpUtils,
                           token=Config.get('token'),
                           websocket_port=get_websocket_port(),
                           template_folder=template_folder,
                           static_folder=static_folder,
                           plugins=Config.get_plugins(),
                           backends=Config.get_backends(),
                           has_ssl=http_conf.get('ssl_cert') is not None)
Ejemplo n.º 27
0
def send_message(msg, wait_for_response=True):
    msg = Message.build(msg)

    if isinstance(msg, Request):
        msg.origin = 'http'

    if Config.get('token'):
        msg.token = Config.get('token')

    bus().post(msg)

    if isinstance(msg, Request) and wait_for_response:
        response = get_message_response(msg)
        logger().debug(
            'Processing response on the HTTP backend: {}'.format(response))

        return response
Ejemplo n.º 28
0
def get_credentials_filename(*scopes):
    from platypush.config import Config

    scope_name = '-'.join([scope.split('/')[-1] for scope in scopes])
    credentials_dir = os.path.join(Config.get('workdir'), 'credentials',
                                   'google')

    os.makedirs(credentials_dir, exist_ok=True)
    return os.path.join(credentials_dir, scope_name + '.json')
Ejemplo n.º 29
0
    def build(cls, msg):
        msg = super().parse(msg)
        args = {'target': msg.get('target', Config.get('device_id')), 'action': msg['action'],
                'args': msg.get('args', {}), 'id': msg['id'] if 'id' in msg else cls._generate_id(),
                'timestamp': msg['_timestamp'] if '_timestamp' in msg else time.time()}

        if 'origin' in msg: args['origin'] = msg['origin']
        if 'token' in msg: args['token'] = msg['token']
        return cls(**args)
Ejemplo n.º 30
0
 def get_switch_plugins(self) -> dict:
     """
     :return: The list of enabled switch plugins as a ``name -> configuration`` map.
     """
     from platypush.plugins.switch import SwitchPlugin
     return {
         name: Config.get(name)
         for name, plugin in get_enabled_plugins().items()
         if isinstance(plugin, SwitchPlugin)
     }