forked from platypush/platypush
Major refactoring #2
This commit is contained in:
parent
546ea1b9b9
commit
4a04e51da7
12 changed files with 308 additions and 188 deletions
platypush
|
@ -1,16 +1,13 @@
|
||||||
import functools
|
|
||||||
import importlib
|
|
||||||
import os
|
|
||||||
import logging
|
import logging
|
||||||
import socket
|
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
import yaml
|
|
||||||
|
|
||||||
from queue import Queue
|
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
from getopt import getopt
|
from getopt import getopt
|
||||||
|
|
||||||
|
from .bus import Bus
|
||||||
|
from .config import Config
|
||||||
|
from .utils import get_or_load_plugin, init_backends
|
||||||
from .message.request import Request
|
from .message.request import Request
|
||||||
from .message.response import Response
|
from .message.response import Response
|
||||||
|
|
||||||
|
@ -19,50 +16,13 @@ __version__ = '0.3.3'
|
||||||
|
|
||||||
#-----------#
|
#-----------#
|
||||||
|
|
||||||
config = {}
|
|
||||||
modules = {}
|
|
||||||
wrkdir = os.path.dirname(os.path.realpath(__file__))
|
|
||||||
|
|
||||||
|
|
||||||
def _init_plugin(plugin_name, reload=False):
|
|
||||||
global modules
|
|
||||||
global config
|
|
||||||
|
|
||||||
if plugin_name in modules and not reload:
|
|
||||||
return modules[plugin_name]
|
|
||||||
|
|
||||||
try:
|
|
||||||
module = importlib.import_module(__package__ + '.plugins.' + plugin_name)
|
|
||||||
except ModuleNotFoundError as e:
|
|
||||||
logging.warn('No such plugin: {}'.format(plugin_name))
|
|
||||||
raise RuntimeError(e)
|
|
||||||
|
|
||||||
# e.g. plugins.music.mpd main class: MusicMpdPlugin
|
|
||||||
cls_name = functools.reduce(
|
|
||||||
lambda a,b: a.title() + b.title(),
|
|
||||||
(plugin_name.title().split('.'))
|
|
||||||
) + 'Plugin'
|
|
||||||
|
|
||||||
plugin_conf = config[plugin_name] if plugin_name in config else {}
|
|
||||||
|
|
||||||
try:
|
|
||||||
plugin = getattr(module, cls_name)(plugin_conf)
|
|
||||||
modules[plugin_name] = plugin
|
|
||||||
except AttributeError as e:
|
|
||||||
logging.warn('No such class in {}: {}'.format(
|
|
||||||
plugin_name, cls_name))
|
|
||||||
raise RuntimeError(e)
|
|
||||||
|
|
||||||
return plugin
|
|
||||||
|
|
||||||
|
|
||||||
def _execute_request(request, retry=True):
|
def _execute_request(request, retry=True):
|
||||||
tokens = request.action.split('.')
|
tokens = request.action.split('.')
|
||||||
module_name = str.join('.', tokens[:-1])
|
module_name = str.join('.', tokens[:-1])
|
||||||
method_name = tokens[-1:][0]
|
method_name = tokens[-1:][0]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
plugin = _init_plugin(module_name)
|
plugin = get_or_load_plugin(module_name)
|
||||||
except RuntimeError as e: # Module/class not found
|
except RuntimeError as e: # Module/class not found
|
||||||
logging.exception(e)
|
logging.exception(e)
|
||||||
return
|
return
|
||||||
|
@ -78,7 +38,7 @@ def _execute_request(request, retry=True):
|
||||||
logging.exception(e)
|
logging.exception(e)
|
||||||
if retry:
|
if retry:
|
||||||
logging.info('Reloading plugin {} and retrying'.format(module_name))
|
logging.info('Reloading plugin {} and retrying'.format(module_name))
|
||||||
_init_plugin(module_name, reload=True)
|
get_or_load_plugin(module_name, reload=True)
|
||||||
_execute_request(request, retry=False)
|
_execute_request(request, retry=False)
|
||||||
finally:
|
finally:
|
||||||
# Send the response on the backend that received the request
|
# Send the response on the backend that received the request
|
||||||
|
@ -95,131 +55,32 @@ def on_msg(msg):
|
||||||
logging.info('Received response: {}'.format(msg))
|
logging.info('Received response: {}'.format(msg))
|
||||||
|
|
||||||
|
|
||||||
def parse_config_file(config_file=None):
|
|
||||||
global config
|
|
||||||
|
|
||||||
if config_file:
|
|
||||||
locations = [config_file]
|
|
||||||
else:
|
|
||||||
locations = [
|
|
||||||
# ./config.yaml
|
|
||||||
os.path.join(wrkdir, 'config.yaml'),
|
|
||||||
# ~/.config/platypush/config.yaml
|
|
||||||
os.path.join(os.environ['HOME'], '.config', 'platypush', 'config.yaml'),
|
|
||||||
# /etc/platypush/config.yaml
|
|
||||||
os.path.join(os.sep, 'etc', 'platypush', 'config.yaml'),
|
|
||||||
]
|
|
||||||
|
|
||||||
for loc in locations:
|
|
||||||
try:
|
|
||||||
with open(loc,'r') as f:
|
|
||||||
config = yaml.load(f)
|
|
||||||
except FileNotFoundError as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
for section in config:
|
|
||||||
if 'disabled' in config[section] and config[section]['disabled']:
|
|
||||||
del config[section]
|
|
||||||
|
|
||||||
if 'logging' not in config:
|
|
||||||
config['logging'] = logging.INFO
|
|
||||||
else:
|
|
||||||
config['logging'] = getattr(logging, config['logging'].upper())
|
|
||||||
|
|
||||||
if 'device_id' not in config:
|
|
||||||
config['device_id'] = socket.gethostname()
|
|
||||||
|
|
||||||
return config
|
|
||||||
|
|
||||||
|
|
||||||
def init_backends(config, bus=None):
|
|
||||||
backends = {}
|
|
||||||
|
|
||||||
for k in config.keys():
|
|
||||||
if not k.startswith('backend.'): continue
|
|
||||||
|
|
||||||
module = importlib.import_module(__package__ + '.' + k)
|
|
||||||
|
|
||||||
# e.g. backend.pushbullet main class: PushbulletBackend
|
|
||||||
cls_name = functools.reduce(
|
|
||||||
lambda a,b: a.title() + b.title(),
|
|
||||||
(module.__name__.title().split('.')[2:])
|
|
||||||
) + 'Backend'
|
|
||||||
|
|
||||||
# Ignore the pusher attribute here
|
|
||||||
if 'pusher' in config[k]: del config[k]['pusher']
|
|
||||||
|
|
||||||
try:
|
|
||||||
b = getattr(module, cls_name)(bus=bus, **config[k])
|
|
||||||
name = '.'.join((k.split('.'))[1:])
|
|
||||||
backends[name] = b
|
|
||||||
except AttributeError as e:
|
|
||||||
logging.warn('No such class in {}: {}'.format(
|
|
||||||
module.__name__, cls_name))
|
|
||||||
raise RuntimeError(e)
|
|
||||||
|
|
||||||
return backends
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_pusher_backend(config):
|
|
||||||
backends = ['.'.join((k.split('.'))[1:])
|
|
||||||
for k in config.keys() if k.startswith('backend.')
|
|
||||||
and 'pusher' in config[k] and config[k]['pusher'] is True]
|
|
||||||
|
|
||||||
return backends[0] if backends else None
|
|
||||||
|
|
||||||
|
|
||||||
def get_logging_level():
|
|
||||||
global config
|
|
||||||
return config['logging']
|
|
||||||
|
|
||||||
|
|
||||||
def get_device_id():
|
|
||||||
global config
|
|
||||||
return config['device_id'] if 'device_id' in config else None
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
print('Starting platypush v.{}'.format(__version__))
|
print('Starting platypush v.{}'.format(__version__))
|
||||||
|
|
||||||
debug = False
|
|
||||||
config_file = None
|
config_file = None
|
||||||
|
|
||||||
plugins_dir = os.path.join(wrkdir, 'plugins')
|
|
||||||
sys.path.insert(0, plugins_dir)
|
|
||||||
|
|
||||||
optlist, args = getopt(sys.argv[1:], 'vh')
|
optlist, args = getopt(sys.argv[1:], 'vh')
|
||||||
for opt, arg in optlist:
|
for opt, arg in optlist:
|
||||||
if opt == '-c':
|
if opt == '-c':
|
||||||
config_file = arg
|
config_file = arg
|
||||||
if opt == '-v':
|
|
||||||
debug = True
|
|
||||||
elif opt == '-h':
|
elif opt == '-h':
|
||||||
print('''
|
print('''
|
||||||
Usage: {} [-v] [-h] [-c <config_file>]
|
Usage: {} [-h] [-c <config_file>]
|
||||||
-v Enable debug mode
|
|
||||||
-h Show this help
|
-h Show this help
|
||||||
-c Path to the configuration file (default: ./config.yaml)
|
-c Path to the configuration file (default: ./config.yaml)
|
||||||
'''.format(sys.argv[0]))
|
'''.format(sys.argv[0]))
|
||||||
return
|
return
|
||||||
|
|
||||||
config = parse_config_file(config_file)
|
Config.init(config_file)
|
||||||
if debug: config['logging'] = logging.DEBUG
|
logging.basicConfig(level=Config.get('logging'), stream=sys.stdout)
|
||||||
|
|
||||||
logging.basicConfig(level=get_logging_level(), stream=sys.stdout)
|
bus = Bus(on_msg=on_msg)
|
||||||
logging.debug('Configuration dump: {}'.format(config))
|
backends = init_backends(bus)
|
||||||
|
|
||||||
bus = Queue()
|
|
||||||
backends = init_backends(config, bus)
|
|
||||||
|
|
||||||
for backend in backends.values():
|
for backend in backends.values():
|
||||||
backend.start()
|
backend.start()
|
||||||
|
|
||||||
while True:
|
bus.loop_forever()
|
||||||
try:
|
|
||||||
on_msg(bus.get())
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
return
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import importlib
|
import importlib
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import platypush
|
|
||||||
|
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
|
|
||||||
|
from platypush.config import Config
|
||||||
from platypush.message import Message
|
from platypush.message import Message
|
||||||
from platypush.message.request import Request
|
from platypush.message.request import Request
|
||||||
from platypush.message.response import Response
|
from platypush.message.response import Response
|
||||||
|
@ -24,11 +24,11 @@ class Backend(Thread):
|
||||||
# If no bus is specified, create an internal queue where
|
# If no bus is specified, create an internal queue where
|
||||||
# the received messages will be pushed
|
# the received messages will be pushed
|
||||||
self.bus = bus if bus else Queue()
|
self.bus = bus if bus else Queue()
|
||||||
self.device_id = platypush.get_device_id()
|
self.device_id = Config.get('device_id')
|
||||||
self.msgtypes = {}
|
self.msgtypes = {}
|
||||||
|
|
||||||
Thread.__init__(self)
|
Thread.__init__(self)
|
||||||
logging.basicConfig(stream=sys.stdout, level=platypush.get_logging_level()
|
logging.basicConfig(stream=sys.stdout, level=Config.get('logging')
|
||||||
if 'logging' not in kwargs
|
if 'logging' not in kwargs
|
||||||
else getattr(logging, kwargs['logging']))
|
else getattr(logging, kwargs['logging']))
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class Backend(Thread):
|
||||||
|
|
||||||
logging.debug('Message received on the backend: {}'.format(msg))
|
logging.debug('Message received on the backend: {}'.format(msg))
|
||||||
msg.backend = self # Augment message
|
msg.backend = self # Augment message
|
||||||
self.bus.put(msg)
|
self.bus.post(msg)
|
||||||
|
|
||||||
def send_request(self, request):
|
def send_request(self, request):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -4,6 +4,7 @@ import requests
|
||||||
import time
|
import time
|
||||||
import websocket
|
import websocket
|
||||||
|
|
||||||
|
from platypush.config import Config
|
||||||
from platypush.message import Message
|
from platypush.message import Message
|
||||||
|
|
||||||
from .. import Backend
|
from .. import Backend
|
||||||
|
|
23
platypush/bus/__init__.py
Normal file
23
platypush/bus/__init__.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from queue import Queue
|
||||||
|
|
||||||
|
class Bus(object):
|
||||||
|
""" Main local bus where the daemon will listen for new messages """
|
||||||
|
|
||||||
|
def __init__(self, on_msg):
|
||||||
|
self.bus = Queue()
|
||||||
|
self.on_msg = on_msg
|
||||||
|
|
||||||
|
def post(self, msg):
|
||||||
|
""" Sends a message to the bus """
|
||||||
|
self.bus.put(msg)
|
||||||
|
|
||||||
|
def loop_forever(self):
|
||||||
|
""" Reads messages from the bus """
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
self.on_msg(self.bus.get())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
return
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
145
platypush/config/__init__.py
Normal file
145
platypush/config/__init__.py
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import socket
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
""" Config singleton instance """
|
||||||
|
_default_config_instance = None
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
"""
|
||||||
|
Configuration base class
|
||||||
|
Usage:
|
||||||
|
- Initialize config from one of the default paths:
|
||||||
|
Config.init()
|
||||||
|
- Initialize config from a custom path
|
||||||
|
Config.init(config_file_path)
|
||||||
|
- Set a value
|
||||||
|
Config.set('foo', 'bar')
|
||||||
|
- Get a value
|
||||||
|
Config.get('foo')
|
||||||
|
"""
|
||||||
|
|
||||||
|
"""
|
||||||
|
Default config file locations:
|
||||||
|
- $HOME/.config/platypush/config.yaml
|
||||||
|
- /etc/platypush/config.yaml
|
||||||
|
"""
|
||||||
|
_cfgfile_locations = [
|
||||||
|
os.path.join(os.environ['HOME'], '.config', 'platypush', 'config.yaml'),
|
||||||
|
os.path.join(os.sep, 'etc', 'platypush', 'config.yaml'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, cfgfile=None):
|
||||||
|
"""
|
||||||
|
Constructor. Always use the class as a singleton (i.e. through
|
||||||
|
Config.init), you won't probably need to call the constructor directly
|
||||||
|
Params:
|
||||||
|
cfgfile -- Config file path (default: retrieve the first
|
||||||
|
available location in _cfgfile_locations)
|
||||||
|
"""
|
||||||
|
|
||||||
|
if cfgfile is None:
|
||||||
|
cfgfile = self._get_default_cfgfile()
|
||||||
|
|
||||||
|
if cfgfile is None:
|
||||||
|
raise RuntimeError('No config file specified and nothing found in {}'
|
||||||
|
.format(self._cfgfile_locations))
|
||||||
|
|
||||||
|
with open(cfgfile, 'r') as fp:
|
||||||
|
self._config = yaml.load(fp)
|
||||||
|
|
||||||
|
for section in self._config:
|
||||||
|
if 'disabled' in self._config[section] \
|
||||||
|
and self._config[section]['disabled']:
|
||||||
|
del self._config[section]
|
||||||
|
|
||||||
|
if 'logging' not in self._config:
|
||||||
|
self._config['logging'] = logging.INFO
|
||||||
|
else:
|
||||||
|
self._config['logging'] = getattr(logging, self._config['logging'].upper())
|
||||||
|
|
||||||
|
if 'device_id' not in self._config:
|
||||||
|
self._config['device_id'] = socket.gethostname()
|
||||||
|
|
||||||
|
self._init_backends()
|
||||||
|
self._init_plugins()
|
||||||
|
|
||||||
|
def _init_backends(self):
|
||||||
|
self.backends = {}
|
||||||
|
for key in self._config.keys():
|
||||||
|
if not key.startswith('backend.'): continue
|
||||||
|
backend_name = '.'.join(key.split('.')[1:])
|
||||||
|
self.backends[backend_name] = self._config[key]
|
||||||
|
|
||||||
|
def _init_plugins(self):
|
||||||
|
self.plugins = {}
|
||||||
|
for key in self._config.keys():
|
||||||
|
if key.startswith('backend.'): continue
|
||||||
|
plugin_name = '.'.join(key.split('.')[1:])
|
||||||
|
self.plugins[plugin_name] = self._config[key]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_backends():
|
||||||
|
global _default_config_instance
|
||||||
|
if _default_config_instance is None: _default_config_instance = Config()
|
||||||
|
return _default_config_instance.backends
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_plugins():
|
||||||
|
global _default_config_instance
|
||||||
|
if _default_config_instance is None: _default_config_instance = Config()
|
||||||
|
return _default_config_instance.plugins
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_default_pusher_backend():
|
||||||
|
"""
|
||||||
|
Gets the default pusher backend from the config
|
||||||
|
"""
|
||||||
|
backends = [k for k in Config.get_backends().keys()
|
||||||
|
if 'pusher' in Config.get_backends()[k]
|
||||||
|
and Config.get_backends()[k]['pusher'] is True]
|
||||||
|
|
||||||
|
return backends[0] if backends else None
|
||||||
|
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _get_default_cfgfile(cls):
|
||||||
|
for location in cls._cfgfile_locations:
|
||||||
|
if os.path.isfile(location): return location
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def init(cfgfile=None):
|
||||||
|
"""
|
||||||
|
Initializes the config object singleton
|
||||||
|
Params:
|
||||||
|
cfgfile -- path to the config file - default: _cfgfile_locations
|
||||||
|
"""
|
||||||
|
global _default_config_instance
|
||||||
|
_default_config_instance = Config(cfgfile)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get(key):
|
||||||
|
"""
|
||||||
|
Gets a config value
|
||||||
|
Params:
|
||||||
|
key -- Config key to get
|
||||||
|
"""
|
||||||
|
global _default_config_instance
|
||||||
|
if _default_config_instance is None: _default_config_instance = Config()
|
||||||
|
return _default_config_instance._config[key]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set(key, value):
|
||||||
|
"""
|
||||||
|
Sets a config value
|
||||||
|
Params:
|
||||||
|
key -- Config key to set
|
||||||
|
value -- Value for key
|
||||||
|
"""
|
||||||
|
global _default_config_instance
|
||||||
|
if _default_config_instance is None: _default_config_instance = Config()
|
||||||
|
_default_config_instance._config[key] = key
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Request(Message):
|
||||||
args = {
|
args = {
|
||||||
'target' : msg['target'],
|
'target' : msg['target'],
|
||||||
'action' : msg['action'],
|
'action' : msg['action'],
|
||||||
'args' : msg['args'],
|
'args' : msg['args'] if 'args' in msg else {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if 'origin' in msg: args['origin'] = msg['origin']
|
if 'origin' in msg: args['origin'] = msg['origin']
|
||||||
|
|
|
@ -1,23 +1,16 @@
|
||||||
import os
|
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from platypush import get_logging_level
|
from platypush.config import Config
|
||||||
from platypush.message.response import Response
|
from platypush.message.response import Response
|
||||||
|
|
||||||
class Plugin(object):
|
class Plugin(object):
|
||||||
def __init__(self, config):
|
""" Base plugin class """
|
||||||
self.config = config
|
|
||||||
logging.basicConfig(stream=sys.stdout, level=get_logging_level()
|
|
||||||
if 'logging' not in config
|
|
||||||
else getattr(logging, config.pop('logging')))
|
|
||||||
|
|
||||||
for cls in reversed(self.__class__.mro()):
|
def __init__(self, **kwargs):
|
||||||
if cls is not object:
|
logging.basicConfig(stream=sys.stdout, level=Config.get('logging')
|
||||||
try:
|
if 'logging' not in kwargs
|
||||||
cls._init(self)
|
else getattr(logging, kwargs['logging']))
|
||||||
except AttributeError as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def run(self, method, *args, **kwargs):
|
def run(self, method, *args, **kwargs):
|
||||||
return getattr(self, method)(*args, **kwargs)
|
return getattr(self, method)(*args, **kwargs)
|
||||||
|
|
|
@ -7,12 +7,24 @@ from platypush.message.response import Response
|
||||||
from .. import LightPlugin
|
from .. import LightPlugin
|
||||||
|
|
||||||
class LightHuePlugin(LightPlugin):
|
class LightHuePlugin(LightPlugin):
|
||||||
|
""" Philips Hue lights plugin """
|
||||||
|
|
||||||
MAX_BRI = 255
|
MAX_BRI = 255
|
||||||
MAX_SAT = 255
|
MAX_SAT = 255
|
||||||
MAX_HUE = 65535
|
MAX_HUE = 65535
|
||||||
|
|
||||||
def _init(self):
|
def __init__(self, bridge, lights=None, groups=None):
|
||||||
self.bridge_address = self.config['bridge']
|
"""
|
||||||
|
Constructor
|
||||||
|
Params:
|
||||||
|
bridge -- Bridge address or hostname
|
||||||
|
lights -- Lights to be controlled (default: all)
|
||||||
|
groups -- Groups to be controlled (default: all)
|
||||||
|
"""
|
||||||
|
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.bridge_address = bridge
|
||||||
self.bridge = None
|
self.bridge = None
|
||||||
logging.info('Initializing Hue lights plugin - bridge: "{}"'.
|
logging.info('Initializing Hue lights plugin - bridge: "{}"'.
|
||||||
format(self.bridge_address))
|
format(self.bridge_address))
|
||||||
|
@ -20,20 +32,18 @@ class LightHuePlugin(LightPlugin):
|
||||||
self.connect()
|
self.connect()
|
||||||
self.lights = []; self.groups = []
|
self.lights = []; self.groups = []
|
||||||
|
|
||||||
if 'lights' in self.config:
|
if lights:
|
||||||
self.lights = self.config['lights']
|
self.lights = lights
|
||||||
elif 'groups' in self.config:
|
elif groups:
|
||||||
self.groups = self.config['groups']
|
self.groups = groups
|
||||||
self._expand_groups(self.groups)
|
self._expand_groups()
|
||||||
else:
|
else:
|
||||||
self.lights = [l.name for l in self.bridge.lights]
|
self.lights = [l.name for l in self.bridge.lights]
|
||||||
|
|
||||||
logging.info('Configured lights: "{}"'. format(self.lights))
|
logging.info('Configured lights: "{}"'. format(self.lights))
|
||||||
|
|
||||||
def _expand_groups(self, group_names):
|
def _expand_groups(self):
|
||||||
groups = [g for g in self.bridge.groups
|
groups = [g for g in self.bridge.groups if g.name in self.groups]
|
||||||
if g.name in group_names]
|
|
||||||
|
|
||||||
for g in groups:
|
for g in groups:
|
||||||
self.lights.extend([l.name for l in g.lights])
|
self.lights.extend([l.name for l in g.lights])
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,18 @@ from platypush.message.response import Response
|
||||||
from .. import MusicPlugin
|
from .. import MusicPlugin
|
||||||
|
|
||||||
class MusicMpdPlugin(MusicPlugin):
|
class MusicMpdPlugin(MusicPlugin):
|
||||||
def _init(self):
|
def __init__(self, host, port):
|
||||||
|
"""
|
||||||
|
Constructor
|
||||||
|
Params:
|
||||||
|
host -- MPD host
|
||||||
|
port -- MPD port
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.host = host
|
||||||
|
self.port = port
|
||||||
self.client = mpd.MPDClient(use_unicode=True)
|
self.client = mpd.MPDClient(use_unicode=True)
|
||||||
self.client.connect(self.config['host'], self.config['port'])
|
self.client.connect(self.host, self.port)
|
||||||
|
|
||||||
def _exec(self, method, *args, **kwargs):
|
def _exec(self, method, *args, **kwargs):
|
||||||
getattr(self.client, method)(*args, **kwargs)
|
getattr(self.client, method)(*args, **kwargs)
|
||||||
|
|
|
@ -7,7 +7,9 @@ from platypush.message.response import Response
|
||||||
from .. import SwitchPlugin
|
from .. import SwitchPlugin
|
||||||
|
|
||||||
class SwitchWemoPlugin(SwitchPlugin):
|
class SwitchWemoPlugin(SwitchPlugin):
|
||||||
def _init(self, discovery_seconds=3):
|
def __init__(self, discovery_seconds=3):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
self.discovery_seconds=discovery_seconds
|
self.discovery_seconds=discovery_seconds
|
||||||
self.env = Environment()
|
self.env = Environment()
|
||||||
self.env.start()
|
self.env.start()
|
||||||
|
|
|
@ -2,7 +2,8 @@ import argparse
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from platypush import init_backends, get_default_pusher_backend, parse_config_file
|
from platypush.config import Config
|
||||||
|
from platypush.utils import init_backends
|
||||||
from platypush.message.request import Request
|
from platypush.message.request import Request
|
||||||
|
|
||||||
def print_usage():
|
def print_usage():
|
||||||
|
@ -15,15 +16,16 @@ def print_usage():
|
||||||
'''.format(sys.argv[0]))
|
'''.format(sys.argv[0]))
|
||||||
|
|
||||||
|
|
||||||
def pusher(target, action, backend=None, **kwargs):
|
def pusher(target, action, backend=None, config=None, **kwargs):
|
||||||
config = parse_config_file()
|
Config.init(config)
|
||||||
|
|
||||||
if target == 'localhost':
|
if target == 'localhost':
|
||||||
backend = 'local'
|
backend = 'local'
|
||||||
elif not backend:
|
elif not backend:
|
||||||
backend = get_default_pusher_backend(config)
|
backend = Config.get_default_pusher_backend()
|
||||||
|
|
||||||
backends = init_backends(config)
|
# TODO Initialize a local bus and wait for the response
|
||||||
|
backends = init_backends()
|
||||||
if backend not in backends:
|
if backend not in backends:
|
||||||
raise RuntimeError('No such backend configured: {}'.format(backend))
|
raise RuntimeError('No such backend configured: {}'.format(backend))
|
||||||
|
|
||||||
|
@ -37,6 +39,11 @@ def pusher(target, action, backend=None, **kwargs):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument('--config', '-c', dest='config', required=False,
|
||||||
|
help="Configuration file path (default: " +
|
||||||
|
"~/.config/platypush/config.yaml or " +
|
||||||
|
"/etc/platypush/config.yaml")
|
||||||
|
|
||||||
parser.add_argument('--target', '-t', dest='target', required=True,
|
parser.add_argument('--target', '-t', dest='target', required=True,
|
||||||
help="Destination of the command")
|
help="Destination of the command")
|
||||||
|
|
||||||
|
@ -59,11 +66,14 @@ def main():
|
||||||
payload[re.sub('^-+', '', args[i])] = args[i+1]
|
payload[re.sub('^-+', '', args[i])] = args[i+1]
|
||||||
|
|
||||||
pusher(target=opts.target, action=opts.action,
|
pusher(target=opts.target, action=opts.action,
|
||||||
backend=opts.backend if 'backend' in opts else None, **payload)
|
backend=opts.backend if 'backend' in opts else None,
|
||||||
|
config=opts.config if 'config' in opts else None,
|
||||||
|
**payload)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
||||||
|
|
66
platypush/utils/__init__.py
Normal file
66
platypush/utils/__init__.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import functools
|
||||||
|
import importlib
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from platypush.config import Config
|
||||||
|
|
||||||
|
modules = {}
|
||||||
|
|
||||||
|
def get_or_load_plugin(plugin_name, reload=False):
|
||||||
|
global modules
|
||||||
|
|
||||||
|
if plugin_name in modules and not reload:
|
||||||
|
return modules[plugin_name]
|
||||||
|
|
||||||
|
try:
|
||||||
|
module = importlib.import_module('platypush.plugins.' + plugin_name)
|
||||||
|
except ModuleNotFoundError as e:
|
||||||
|
logging.warn('No such plugin: {}'.format(plugin_name))
|
||||||
|
raise RuntimeError(e)
|
||||||
|
|
||||||
|
# e.g. plugins.music.mpd main class: MusicMpdPlugin
|
||||||
|
cls_name = functools.reduce(
|
||||||
|
lambda a,b: a.title() + b.title(),
|
||||||
|
(plugin_name.title().split('.'))
|
||||||
|
) + 'Plugin'
|
||||||
|
|
||||||
|
plugin_conf = Config.get_plugins()[plugin_name] \
|
||||||
|
if plugin_name in Config.get_plugins() else {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
plugin = getattr(module, cls_name)(**plugin_conf)
|
||||||
|
modules[plugin_name] = plugin
|
||||||
|
except AttributeError as e:
|
||||||
|
logging.warn('No such class in {}: {}'.format(
|
||||||
|
plugin_name, cls_name))
|
||||||
|
raise RuntimeError(e)
|
||||||
|
|
||||||
|
return plugin
|
||||||
|
|
||||||
|
|
||||||
|
def init_backends(bus=None):
|
||||||
|
backends = {}
|
||||||
|
|
||||||
|
for k in Config.get_backends().keys():
|
||||||
|
module = importlib.import_module('platypush.backend.' + k)
|
||||||
|
cfg = Config.get_backends()[k]
|
||||||
|
|
||||||
|
# e.g. backend.pushbullet main class: PushbulletBackend
|
||||||
|
cls_name = functools.reduce(
|
||||||
|
lambda a,b: a.title() + b.title(),
|
||||||
|
(module.__name__.title().split('.')[2:])
|
||||||
|
) + 'Backend'
|
||||||
|
|
||||||
|
try:
|
||||||
|
b = getattr(module, cls_name)(bus=bus, **cfg)
|
||||||
|
backends[k] = b
|
||||||
|
except AttributeError as e:
|
||||||
|
logging.warn('No such class in {}: {}'.format(
|
||||||
|
module.__name__, cls_name))
|
||||||
|
raise RuntimeError(e)
|
||||||
|
|
||||||
|
return backends
|
||||||
|
|
||||||
|
|
||||||
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
Loading…
Reference in a new issue