import sys
[docs]class GroupController(object):
""" Dispatches calls to its member Controllers (recursively!). Members can be Lights, Groups, Bridges or GroupControllers. """
def __init__(self, name=''):
self.name = name
self._members = set()
def __str__(self):
return '<{0}(name="{1}", members=[{2}])>'.format(self.__class__.__name__, self.name, ', '.join([str(m) for m in self._members]))
def __len__(self):
return len(self._members)
def __iter__(self):
""" Provide an interface for iteration over all members. """
for m in self._members:
yield m
def __getitem__(self, key):
""" Allow `groupcontroller[item_name]` style access """
try:
i = filter(lambda m: m.name == key, self._members)
return next(i)
except StopIteration:
raise KeyError
[docs] def add_member(self, obj):
""" Add a single Light/Group/Bridge or GroupController to the current GroupController. """
self._members.add(obj)
[docs] def add_members(self, iter):
""" Shortcut to `add_member` when you want to add many, will consume any iterable. """
for obj in iter:
self.add_member(obj)
@property
def members(self):
""" Return a ``list`` of Group members. """
return list(self._members)
## `Controller` interface
def __getattr__(self, key):
""" Dispatch calls to members, values are returned as a list of two-tuples: (name, value). """
# TODO - this can be dumber
def wrapper(new_val=None, commit=False):
#print('{0}.{1}({2})'.format(self, key, new_val))
vals = [(m.name, getattr(m, key)() if new_val is None else getattr(m, key)(new_val)) for m in self._members]
if new_val is None:
return vals
if commit:
self.commit()
return self
return wrapper
[docs] def find(self, *names):
""" Find members by name """
group = GroupController(name='{0}'.format(' ,'.join(str(n) if not hasattr(n, 'pattern') else '/{0}/'.format(n.pattern) for n in names)))
for member in self._members:
group.add_members(member.find(*names))
return group
group = light = find
[docs]class Hueman(GroupController):
""" Top level `GroupController` for managing all your Bridges and Configurations """
def __init__(self, cfg):
def import_classpath(cp):
mod, cls = cp.rsplit('.', 1)
__import__(mod)
mod = sys.modules[mod]
return getattr(mod, cls)
super(Hueman, self).__init__()
self.plugins = {}
if cfg.get('plugins'):
for plugin_name, plugin_cfg in cfg.get('plugins').items():
plugin_settings = {}
if isinstance(plugin_cfg, str):
plugin_classpath = plugin_cfg
else:
plugin_classpath = plugin_cfg['path']
plugin_settings = plugin_cfg.get('settings', {})
plugin_class = import_classpath(plugin_classpath)
self.plugins[plugin_name] = plugin_class(**plugin_settings)
self.groups = cfg.get('groups') or {}
self.presets = cfg.get('presets') or {}
self.scenes = cfg.get('scenes') or {}
from hueman.entities import Bridge
for bridge_cfg in cfg.get('bridges', []):
self.add_member(Bridge(bridge_cfg['hostname'], bridge_cfg['username'], self.groups, self.plugins, self.presets, self.scenes))
def __str__(self):
return '<{0}(members=[{1}])>'.format(self.__class__.__name__, ', '.join([str(m) for m in self._members]))
[docs] def scene(self, scene, commit=False):
if isinstance(scene, str):
scene = self.scenes[scene]
for target, settings in scene.items():
if isinstance(settings, str):
self.find(target)._apply_command(settings)
elif isinstance(settings, dict):
self.find(target)._apply(settings)
if commit:
target = self.find(*list(scene.keys()))
target.commit()
return self