commit
4ee468671e
|
@ -1,7 +1,7 @@
|
|||
language: python
|
||||
|
||||
python:
|
||||
- 2.7
|
||||
- 3.7
|
||||
|
||||
install:
|
||||
# Workaround for pi-rc522 dependency issue.
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Mopidy Pummeluff Python module.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
import mopidy
|
||||
|
||||
from .frontend import PummeluffFrontend
|
||||
from .web import LatestHandler, RegistryHandler, RegisterHandler, TypesHandler
|
||||
from .web import LatestHandler, RegistryHandler, RegisterHandler, TagClassesHandler
|
||||
|
||||
|
||||
def app_factory(config, core): # pylint: disable=unused-argument
|
||||
|
@ -27,7 +24,7 @@ def app_factory(config, core): # pylint: disable=unused-argument
|
|||
('/latest/', LatestHandler, {'core': core}),
|
||||
('/registry/', RegistryHandler, {'core': core}),
|
||||
('/register/', RegisterHandler, {'core': core}),
|
||||
('/types/', TypesHandler, {'core': core}),
|
||||
('/tag-classes/', TagClassesHandler, {'core': core}),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module for Mopidy Pummeluff actions.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
__all__ = (
|
||||
'replace_tracklist',
|
||||
'set_volume',
|
||||
|
@ -28,7 +25,7 @@ def replace_tracklist(core, uri):
|
|||
'''
|
||||
LOGGER.info('Replacing tracklist with URI "%s"', uri)
|
||||
core.tracklist.clear()
|
||||
core.tracklist.add(uri=uri)
|
||||
core.tracklist.add(uris=[uri])
|
||||
core.playback.play()
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module for Mopidy Pummeluff frontend.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
__all__ = (
|
||||
'PummeluffFrontend',
|
||||
)
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module for Mopidy Pummeluff registry.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
__all__ = (
|
||||
'RegistryDict',
|
||||
'REGISTRY',
|
||||
|
@ -14,46 +11,62 @@ import os
|
|||
import json
|
||||
from logging import getLogger
|
||||
|
||||
from mopidy_pummeluff import tags
|
||||
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
|
||||
|
||||
class RegistryDict(dict):
|
||||
'''
|
||||
Simple tag registry based on Python's internal :py:class:`dict` class,
|
||||
which reads and writes the registry from/to disk.
|
||||
Class which can be used to retreive and write RFID tags to the registry.
|
||||
'''
|
||||
|
||||
registry_path = '/var/lib/mopidy/pummeluff/tags.json'
|
||||
|
||||
def __init__(self):
|
||||
super(RegistryDict, self).__init__(self)
|
||||
'''
|
||||
Constructor.
|
||||
|
||||
Automatically reads the registry if it exists.
|
||||
'''
|
||||
super().__init__()
|
||||
|
||||
if os.path.exists(self.registry_path):
|
||||
self.read()
|
||||
else:
|
||||
LOGGER.warning('Registry not existing yet on "%s"', self.registry_path)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return super(RegistryDict, self).__getitem__(str(key))
|
||||
|
||||
def __setitem__(self, key, item):
|
||||
super(RegistryDict, self).__setitem__(str(key), item)
|
||||
self.write()
|
||||
|
||||
def get(self, key, default=None):
|
||||
@classmethod
|
||||
def unserialize_item(cls, item):
|
||||
'''
|
||||
Return the value for ``key`` if ``key`` is in the dictionary, else
|
||||
``default``.
|
||||
Unserialize an item from the persistent storage on filesystem to a
|
||||
native tag.
|
||||
|
||||
:param str key: The key
|
||||
:param default: The default value
|
||||
:type default: mixed
|
||||
:param tuple item: The item
|
||||
|
||||
:return: The value
|
||||
:rtype: mixed
|
||||
:return: The tag
|
||||
:rtype: tags.tag
|
||||
'''
|
||||
return super(RegistryDict, self).get(str(key), default)
|
||||
return item['uid'], cls.init_tag(**item)
|
||||
|
||||
@classmethod
|
||||
def init_tag(cls, tag_class, uid, alias=None, parameter=None):
|
||||
'''
|
||||
Initialise a new tag instance.
|
||||
|
||||
:param str tag_class: The tag class
|
||||
:param str uid: The RFID UID
|
||||
:param str alias: The alias
|
||||
:param str parameter: The parameter
|
||||
|
||||
:return: The tag instance
|
||||
:rtype: tags.Tag
|
||||
'''
|
||||
uid = str(uid).strip()
|
||||
tag_class = getattr(tags, tag_class)
|
||||
|
||||
return tag_class(uid, alias, parameter)
|
||||
|
||||
def read(self):
|
||||
'''
|
||||
|
@ -66,7 +79,7 @@ class RegistryDict(dict):
|
|||
with open(self.registry_path) as f:
|
||||
data = json.load(f)
|
||||
self.clear()
|
||||
self.update(data)
|
||||
self.update((self.unserialize_item(item) for item in data))
|
||||
|
||||
def write(self):
|
||||
'''
|
||||
|
@ -81,7 +94,35 @@ class RegistryDict(dict):
|
|||
os.makedirs(directory)
|
||||
|
||||
with open(config, 'w') as f:
|
||||
json.dump(self, f, indent=4)
|
||||
json.dump([tag.as_dict() for tag in self.values()], f, indent=4)
|
||||
|
||||
def register(self, tag_class, uid, alias=None, parameter=None):
|
||||
'''
|
||||
Register a new tag in the registry.
|
||||
|
||||
:param str tag_class: The tag class
|
||||
:param str uid: The UID
|
||||
:param str alias: The alias
|
||||
:param str parameter: The parameter (optional)
|
||||
|
||||
:return: The tag
|
||||
:rtype: tags.Tag
|
||||
'''
|
||||
LOGGER.info('Registering %s tag %s with parameter "%s"', tag_class, uid, parameter)
|
||||
|
||||
tag = self.init_tag(
|
||||
tag_class=tag_class,
|
||||
uid=uid,
|
||||
alias=alias,
|
||||
parameter=parameter
|
||||
)
|
||||
|
||||
tag.validate()
|
||||
|
||||
self[uid] = tag
|
||||
self.write()
|
||||
|
||||
return tag
|
||||
|
||||
|
||||
REGISTRY = RegistryDict()
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module to play sounds.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
__all__ = (
|
||||
'play_sound',
|
||||
)
|
||||
|
|
|
@ -1,252 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module for Mopidy Pummeluff tags.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
__all__ = (
|
||||
'Tag',
|
||||
'TracklistTag',
|
||||
'VolumeTag',
|
||||
'PlayPauseTag',
|
||||
'StopTag',
|
||||
'ShutdownTag',
|
||||
)
|
||||
|
||||
from logging import getLogger
|
||||
|
||||
from .registry import REGISTRY
|
||||
from . import actions
|
||||
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
|
||||
|
||||
class InvalidTagType(Exception):
|
||||
'''
|
||||
Exception which is thrown when an invalid tag type is defined.
|
||||
'''
|
||||
pass
|
||||
|
||||
|
||||
class Tag(object):
|
||||
'''
|
||||
Base RFID tag class, which will implement the factory pattern in Python's
|
||||
own :py:meth:`__new__` method.
|
||||
'''
|
||||
parameter_allowed = True
|
||||
|
||||
def __new__(cls, uid):
|
||||
'''
|
||||
Implement factory pattern and return correct tag instance.
|
||||
'''
|
||||
tag = REGISTRY.get(uid, {})
|
||||
new_cls = cls.get_class(tag.get('type', ''))
|
||||
|
||||
if cls is Tag and cls is not new_cls:
|
||||
instance = new_cls(uid=uid)
|
||||
else:
|
||||
instance = super(Tag, cls).__new__(cls, uid=uid)
|
||||
|
||||
instance.registered = bool(tag)
|
||||
instance.alias = tag.get('alias')
|
||||
instance.parameter = tag.get('parameter')
|
||||
|
||||
return instance
|
||||
|
||||
def __init__(self, uid):
|
||||
self.uid = uid
|
||||
self.scanned = None
|
||||
|
||||
def __str__(self):
|
||||
cls_name = self.__class__.__name__
|
||||
identifier = self.alias or self.uid
|
||||
return '<{}: {}>'.format(cls_name, identifier)
|
||||
|
||||
def __call__(self, core):
|
||||
'''
|
||||
Action method which is called when the tag is detected on the RFID
|
||||
reader.
|
||||
|
||||
:param mopidy.core.Core core: The mopidy core instance
|
||||
'''
|
||||
args = [core]
|
||||
if self.parameter:
|
||||
args.append(self.parameter)
|
||||
getattr(actions, self.action)(*args)
|
||||
|
||||
@staticmethod
|
||||
def get_class(tag_type):
|
||||
'''
|
||||
Return class for specific tag type.
|
||||
|
||||
:param str tag_type: The tag type
|
||||
|
||||
:return: The tag class
|
||||
:rtype: type
|
||||
'''
|
||||
try:
|
||||
name = tag_type.title() + 'Tag'
|
||||
cls = globals()[name]
|
||||
assert issubclass(cls, Tag)
|
||||
except (KeyError, AssertionError):
|
||||
raise InvalidTagType('Tag class for type "{}" does\'t exist.'.format(tag_type))
|
||||
|
||||
return cls
|
||||
|
||||
@classmethod
|
||||
def get_type(cls, tag_class=None):
|
||||
'''
|
||||
Return the type for a specific tag class.
|
||||
|
||||
:param type tag_class: The tag class
|
||||
|
||||
:return: The tag type
|
||||
:rtype: str
|
||||
'''
|
||||
return (tag_class or cls).__name__[0:-3].lower()
|
||||
|
||||
@classmethod
|
||||
def all(cls):
|
||||
'''
|
||||
Return all registered tags in a list.
|
||||
|
||||
:return: Registered tags
|
||||
:rtype: list[Tag]
|
||||
'''
|
||||
return {uid: Tag(uid=uid) for uid in REGISTRY}
|
||||
|
||||
@classmethod
|
||||
def register(cls, uid, alias=None, parameter=None, tag_type=None):
|
||||
'''
|
||||
Register tag in the registry.
|
||||
|
||||
:param str uid: The tag's UID
|
||||
:param str alias: The tag's alias
|
||||
:param str parameter: The optional parameter
|
||||
:param str tag_type: The tag type
|
||||
|
||||
:return: The registered tag
|
||||
:rtype: Tag
|
||||
'''
|
||||
|
||||
if tag_type is None:
|
||||
tag_type = cls.get_type(cls)
|
||||
|
||||
uid = uid.strip()
|
||||
if not uid:
|
||||
error = 'Invalid UID defined'
|
||||
LOGGER.error(error)
|
||||
raise ValueError(error)
|
||||
|
||||
LOGGER.info('Registering %s tag %s with parameter "%s"', tag_type, uid, parameter)
|
||||
|
||||
real_cls = cls.get_class(tag_type)
|
||||
|
||||
if real_cls == Tag:
|
||||
error = 'Registering tags without explicit types are not allowed. ' \
|
||||
'Set tag_type argument on Tag.register() ' \
|
||||
'or use register() method of explicit tag classes.'
|
||||
raise InvalidTagType(error)
|
||||
|
||||
if not real_cls.parameter_allowed and parameter:
|
||||
raise ValueError('No parameter allowed for this tag')
|
||||
elif hasattr(real_cls, 'validate_parameter'):
|
||||
real_cls.validate_parameter(parameter)
|
||||
|
||||
REGISTRY[uid] = {
|
||||
'type': tag_type,
|
||||
'alias': alias.strip(),
|
||||
'parameter': parameter.strip()
|
||||
}
|
||||
|
||||
return Tag.all().get(uid)
|
||||
|
||||
@property
|
||||
def dict(self):
|
||||
'''
|
||||
Return the dict version of this tag.
|
||||
|
||||
:return: The dict version of this tag
|
||||
:rtype: dict
|
||||
'''
|
||||
tag_dict = {
|
||||
'uid': self.uid,
|
||||
'alias': self.alias,
|
||||
'type': self.get_type(),
|
||||
'parameter': self.parameter,
|
||||
}
|
||||
|
||||
tag_dict['scanned'] = self.scanned
|
||||
|
||||
return tag_dict
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
'''
|
||||
Return a name of an action (function) defined in the
|
||||
:py:mod:`mopidy_pummeluff.actions` Python module.
|
||||
|
||||
:return: An action name
|
||||
:rtype: str
|
||||
:raises NotImplementedError: When action property isn't defined
|
||||
'''
|
||||
cls = self.__class__.__name__
|
||||
error = 'Missing action property in the %s class'
|
||||
LOGGER.error(error, cls)
|
||||
raise NotImplementedError(error % cls)
|
||||
|
||||
|
||||
class TracklistTag(Tag):
|
||||
'''
|
||||
Replaces the current tracklist with the URI retreived from the tag's
|
||||
parameter.
|
||||
'''
|
||||
action = 'replace_tracklist'
|
||||
|
||||
|
||||
class VolumeTag(Tag):
|
||||
'''
|
||||
Sets the volume to the percentage value retreived from the tag's parameter.
|
||||
'''
|
||||
action = 'set_volume'
|
||||
|
||||
@staticmethod
|
||||
def validate_parameter(parameter):
|
||||
'''
|
||||
Validates if the parameter is an integer between 0 and 100.
|
||||
|
||||
:param mixed parameter: The parameter
|
||||
|
||||
:raises ValueError: When parameter is invalid
|
||||
'''
|
||||
try:
|
||||
number = int(parameter)
|
||||
assert number >= 0 and number <= 100
|
||||
except (ValueError, AssertionError):
|
||||
raise ValueError('Volume parameter has to be a number between 0 and 100')
|
||||
|
||||
|
||||
class PlayPauseTag(Tag):
|
||||
'''
|
||||
Pauses or resumes the playback, based on the current state.
|
||||
'''
|
||||
action = 'play_pause'
|
||||
parameter_allowed = False
|
||||
|
||||
|
||||
class StopTag(Tag):
|
||||
'''
|
||||
Stops the playback.
|
||||
'''
|
||||
action = 'stop'
|
||||
parameter_allowed = False
|
||||
|
||||
|
||||
class ShutdownTag(Tag):
|
||||
'''
|
||||
Shutting down the system.
|
||||
'''
|
||||
action = 'shutdown'
|
||||
parameter_allowed = False
|
21
mopidy_pummeluff/tags/__init__.py
Normal file
21
mopidy_pummeluff/tags/__init__.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
'''
|
||||
Python module for Mopidy Pummeluff tags.
|
||||
'''
|
||||
|
||||
__all__ = (
|
||||
'Tracklist',
|
||||
'Volume',
|
||||
'PlayPause',
|
||||
'Stop',
|
||||
'Shutdown',
|
||||
)
|
||||
|
||||
from .tracklist import Tracklist
|
||||
from .volume import Volume
|
||||
from .play_pause import PlayPause
|
||||
from .stop import Stop
|
||||
from .shutdown import Shutdown
|
||||
|
||||
TAGS = {}
|
||||
for tag in __all__:
|
||||
TAGS[tag] = globals()[tag].__doc__.strip()
|
106
mopidy_pummeluff/tags/base.py
Normal file
106
mopidy_pummeluff/tags/base.py
Normal file
|
@ -0,0 +1,106 @@
|
|||
'''
|
||||
Python module for Mopidy Pummeluff base tag.
|
||||
'''
|
||||
|
||||
__all__ = (
|
||||
'Tag',
|
||||
)
|
||||
|
||||
from logging import getLogger
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
|
||||
|
||||
class Tag:
|
||||
'''
|
||||
Base RFID tag class, which will implement the factory pattern in Python's
|
||||
own :py:meth:`__new__` method.
|
||||
'''
|
||||
parameterised = True
|
||||
|
||||
def __init__(self, uid, alias=None, parameter=None):
|
||||
'''
|
||||
Concstructor.
|
||||
'''
|
||||
self.uid = uid
|
||||
self.alias = alias
|
||||
self.parameter = parameter
|
||||
self.scanned = None
|
||||
|
||||
def __str__(self):
|
||||
'''
|
||||
String representation of tag.
|
||||
|
||||
:return: The alias
|
||||
:rtype: str
|
||||
'''
|
||||
return self.alias or self.uid
|
||||
|
||||
def __repr__(self):
|
||||
'''
|
||||
Instance representation of tag.
|
||||
|
||||
:return: The class name and UID
|
||||
:rtype: str
|
||||
'''
|
||||
identifier = self.alias or self.uid
|
||||
return f'<{self.__class__.__name__} {identifier}>'
|
||||
|
||||
def __call__(self, core):
|
||||
'''
|
||||
Action method which is called when the tag is detected on the RFID
|
||||
reader.
|
||||
|
||||
:param mopidy.core.Core core: The mopidy core instance
|
||||
'''
|
||||
args = [core]
|
||||
if self.parameter:
|
||||
args.append(self.parameter)
|
||||
self.action.__func__(*args)
|
||||
|
||||
@property
|
||||
def action(self):
|
||||
'''
|
||||
Return an action function defined in the
|
||||
:py:mod:`mopidy_pummeluff.actions` Python module.
|
||||
|
||||
:return: An action
|
||||
:raises NotImplementedError: When action property isn't defined
|
||||
'''
|
||||
cls = self.__class__.__name__
|
||||
error = 'Missing action property in the %s class'
|
||||
LOGGER.error(error, cls)
|
||||
raise NotImplementedError(error % cls)
|
||||
|
||||
def as_dict(self, include_scanned=False):
|
||||
'''
|
||||
Dict representation of the tag.
|
||||
|
||||
:param bool include_scanned: Include scanned timestamp
|
||||
|
||||
:return: The dict version of the tag
|
||||
:rtype: dict
|
||||
'''
|
||||
data = {
|
||||
'tag_class': self.__class__.__name__,
|
||||
'uid': self.uid,
|
||||
'alias': self.alias or '',
|
||||
'parameter': self.parameter or '',
|
||||
}
|
||||
|
||||
if include_scanned:
|
||||
data['scanned'] = self.scanned
|
||||
|
||||
return data
|
||||
|
||||
def validate(self):
|
||||
'''
|
||||
Validate parameter.
|
||||
|
||||
:raises ValueError: When parameter is not allowed but defined
|
||||
'''
|
||||
if self.parameterised and not self.parameter:
|
||||
raise ValueError('Parameter required for this tag')
|
||||
|
||||
if not self.parameterised and self.parameter:
|
||||
raise ValueError('No parameter allowed for this tag')
|
18
mopidy_pummeluff/tags/play_pause.py
Normal file
18
mopidy_pummeluff/tags/play_pause.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
'''
|
||||
Python module for Mopidy Pummeluff play pause tag.
|
||||
'''
|
||||
|
||||
__all__ = (
|
||||
'PlayPause',
|
||||
)
|
||||
|
||||
from mopidy_pummeluff.actions import play_pause
|
||||
from .base import Tag
|
||||
|
||||
|
||||
class PlayPause(Tag):
|
||||
'''
|
||||
Pauses or resumes the playback, based on the current state.
|
||||
'''
|
||||
action = play_pause
|
||||
parameterised = False
|
18
mopidy_pummeluff/tags/shutdown.py
Normal file
18
mopidy_pummeluff/tags/shutdown.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
'''
|
||||
Python module for Mopidy Pummeluff shutdown tag.
|
||||
'''
|
||||
|
||||
__all__ = (
|
||||
'Shutdown',
|
||||
)
|
||||
|
||||
from mopidy_pummeluff.actions import shutdown
|
||||
from .base import Tag
|
||||
|
||||
|
||||
class Shutdown(Tag):
|
||||
'''
|
||||
Shutting down the system.
|
||||
'''
|
||||
action = shutdown
|
||||
parameterised = False
|
18
mopidy_pummeluff/tags/stop.py
Normal file
18
mopidy_pummeluff/tags/stop.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
'''
|
||||
Python module for Mopidy Pummeluff stop tag.
|
||||
'''
|
||||
|
||||
__all__ = (
|
||||
'Stop',
|
||||
)
|
||||
|
||||
from mopidy_pummeluff.actions import stop
|
||||
from .base import Tag
|
||||
|
||||
|
||||
class Stop(Tag):
|
||||
'''
|
||||
Stops the playback.
|
||||
'''
|
||||
action = stop
|
||||
parameterised = False
|
19
mopidy_pummeluff/tags/tracklist.py
Normal file
19
mopidy_pummeluff/tags/tracklist.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
'''
|
||||
Python module for Mopidy Pummeluff tracklist tag.
|
||||
'''
|
||||
|
||||
__all__ = (
|
||||
'Tracklist',
|
||||
)
|
||||
|
||||
from mopidy_pummeluff.actions import replace_tracklist
|
||||
from .base import Tag
|
||||
|
||||
|
||||
class Tracklist(Tag):
|
||||
'''
|
||||
Replaces the current tracklist with the URI retreived from the tag's
|
||||
parameter.
|
||||
'''
|
||||
|
||||
action = replace_tracklist
|
34
mopidy_pummeluff/tags/volume.py
Normal file
34
mopidy_pummeluff/tags/volume.py
Normal file
|
@ -0,0 +1,34 @@
|
|||
'''
|
||||
Python module for Mopidy Pummeluff volume tag.
|
||||
'''
|
||||
|
||||
__all__ = (
|
||||
'Volume',
|
||||
)
|
||||
|
||||
from mopidy_pummeluff.actions import set_volume
|
||||
from .base import Tag
|
||||
|
||||
|
||||
class Volume(Tag):
|
||||
'''
|
||||
Sets the volume to the percentage value retreived from the tag's parameter.
|
||||
'''
|
||||
|
||||
action = set_volume
|
||||
|
||||
def validate(self):
|
||||
'''
|
||||
Validates if the parameter is an integer between 0 and 100.
|
||||
|
||||
:param mixed parameter: The parameter
|
||||
|
||||
:raises ValueError: When parameter is invalid
|
||||
'''
|
||||
super().validate()
|
||||
|
||||
try:
|
||||
number = int(self.parameter)
|
||||
assert 0 <= number <= 100
|
||||
except (ValueError, AssertionError):
|
||||
raise ValueError('Volume parameter has to be a number between 0 and 100')
|
|
@ -1,9 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Threads of Mopidy Pummeluff.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
from .gpio_handler import *
|
||||
from .tag_reader import *
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module for the dedicated Mopidy Pummeluff threads.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
__all__ = (
|
||||
'GPIOHandler',
|
||||
)
|
||||
|
@ -40,7 +37,7 @@ class GPIOHandler(Thread):
|
|||
:param mopidy.core.Core core: The mopidy core instance
|
||||
:param threading.Event stop_event: The stop event
|
||||
'''
|
||||
super(GPIOHandler, self).__init__()
|
||||
super().__init__()
|
||||
|
||||
self.core = core
|
||||
self.stop_event = stop_event
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module for the dedicated Mopidy Pummeluff threads.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
__all__ = (
|
||||
'TagReader',
|
||||
)
|
||||
|
@ -16,7 +13,8 @@ from logging import getLogger
|
|||
import RPi.GPIO as GPIO
|
||||
from pirc522 import RFID
|
||||
|
||||
from mopidy_pummeluff.tags import Tag
|
||||
from mopidy_pummeluff.registry import REGISTRY
|
||||
from mopidy_pummeluff.tags.base import Tag
|
||||
from mopidy_pummeluff.sound import play_sound
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
|
@ -47,7 +45,7 @@ class TagReader(Thread):
|
|||
:param mopidy.core.Core core: The mopidy core instance
|
||||
:param threading.Event stop_event: The stop event
|
||||
'''
|
||||
super(TagReader, self).__init__()
|
||||
super().__init__()
|
||||
self.core = core
|
||||
self.stop_event = stop_event
|
||||
self.rfid = RFID()
|
||||
|
@ -105,16 +103,16 @@ class TagReader(Thread):
|
|||
|
||||
:param str uid: The UID
|
||||
'''
|
||||
tag = Tag(uid)
|
||||
|
||||
if tag.registered:
|
||||
try:
|
||||
tag = REGISTRY[str(uid)]
|
||||
LOGGER.info('Triggering action of registered tag')
|
||||
play_sound('success.wav')
|
||||
tag(self.core)
|
||||
|
||||
else:
|
||||
except KeyError:
|
||||
LOGGER.info('Tag is not registered, thus doing nothing')
|
||||
play_sound('fail.wav')
|
||||
tag = Tag(uid=uid)
|
||||
|
||||
tag.scanned = time()
|
||||
TagReader.latest = tag
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Python module for Mopidy Pummeluff web classes.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
__all__ = (
|
||||
'LatestHandler',
|
||||
'RegistryHandler',
|
||||
'RegisterHandler',
|
||||
'TagClassesHandler',
|
||||
)
|
||||
|
||||
from json import dumps
|
||||
|
@ -16,8 +14,9 @@ from logging import getLogger
|
|||
|
||||
from tornado.web import RequestHandler
|
||||
|
||||
from . import tags
|
||||
from .threads import TagReader
|
||||
from mopidy_pummeluff.registry import REGISTRY
|
||||
from mopidy_pummeluff.tags import TAGS
|
||||
from mopidy_pummeluff.threads import TagReader
|
||||
|
||||
LOGGER = getLogger(__name__)
|
||||
|
||||
|
@ -33,9 +32,9 @@ class LatestHandler(RequestHandler): # pylint: disable=abstract-method
|
|||
|
||||
:param mopidy.core.Core mopidy_core: The mopidy core instance
|
||||
'''
|
||||
self.core = core
|
||||
self.core = core # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
def get(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Handle GET request.
|
||||
'''
|
||||
|
@ -55,7 +54,7 @@ class LatestHandler(RequestHandler): # pylint: disable=abstract-method
|
|||
'message': 'Scanned tag found',
|
||||
}
|
||||
|
||||
data.update(tag.dict)
|
||||
data.update(tag.as_dict(include_scanned=True))
|
||||
|
||||
self.set_header('Content-type', 'application/json')
|
||||
self.write(dumps(data))
|
||||
|
@ -72,16 +71,16 @@ class RegistryHandler(RequestHandler): # pylint: disable=abstract-method
|
|||
|
||||
:param mopidy.core.Core mopidy_core: The mopidy core instance
|
||||
'''
|
||||
self.core = core
|
||||
self.core = core # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
def get(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Handle GET request.
|
||||
'''
|
||||
tags_list = []
|
||||
|
||||
for tag in tags.Tag.all().values():
|
||||
tags_list.append(tag.dict)
|
||||
for tag in REGISTRY.values():
|
||||
tags_list.append(tag.as_dict())
|
||||
|
||||
data = {
|
||||
'success': True,
|
||||
|
@ -104,18 +103,18 @@ class RegisterHandler(RequestHandler): # pylint: disable=abstract-method
|
|||
|
||||
:param mopidy.core.Core mopidy_core: The mopidy core instance
|
||||
'''
|
||||
self.core = core
|
||||
self.core = core # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
def post(self, *args, **kwargs):
|
||||
def post(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Handle POST request.
|
||||
'''
|
||||
try:
|
||||
tag = tags.Tag.register(
|
||||
tag = REGISTRY.register(
|
||||
tag_class=self.get_argument('tag-class'),
|
||||
uid=self.get_argument('uid'),
|
||||
alias=self.get_argument('alias', None),
|
||||
parameter=self.get_argument('parameter'),
|
||||
tag_type=self.get_argument('type')
|
||||
parameter=self.get_argument('parameter', None),
|
||||
)
|
||||
|
||||
data = {
|
||||
|
@ -123,7 +122,7 @@ class RegisterHandler(RequestHandler): # pylint: disable=abstract-method
|
|||
'message': 'Tag successfully registered',
|
||||
}
|
||||
|
||||
data.update(tag.dict)
|
||||
data.update(tag.as_dict())
|
||||
|
||||
except ValueError as ex:
|
||||
self.set_status(400)
|
||||
|
@ -135,16 +134,16 @@ class RegisterHandler(RequestHandler): # pylint: disable=abstract-method
|
|||
self.set_header('Content-type', 'application/json')
|
||||
self.write(dumps(data))
|
||||
|
||||
def put(self, *args, **kwargs):
|
||||
def put(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Handle PUT request.
|
||||
'''
|
||||
self.post()
|
||||
|
||||
|
||||
class TypesHandler(RequestHandler): # pylint: disable=abstract-method
|
||||
class TagClassesHandler(RequestHandler): # pylint: disable=abstract-method
|
||||
'''
|
||||
Request handler which returns all tag types.
|
||||
Request handler which returns all tag classes.
|
||||
'''
|
||||
|
||||
def initialize(self, core): # pylint: disable=arguments-differ
|
||||
|
@ -153,25 +152,16 @@ class TypesHandler(RequestHandler): # pylint: disable=abstract-method
|
|||
|
||||
:param mopidy.core.Core mopidy_core: The mopidy core instance
|
||||
'''
|
||||
self.core = core
|
||||
self.core = core # pylint: disable=attribute-defined-outside-init
|
||||
|
||||
def get(self, *args, **kwargs):
|
||||
def get(self, *args, **kwargs): # pylint: disable=unused-argument
|
||||
'''
|
||||
Handle GET request.
|
||||
'''
|
||||
types = {}
|
||||
|
||||
for cls_name in tags.__all__:
|
||||
tag_cls = getattr(tags, cls_name)
|
||||
if tag_cls is not tags.Tag:
|
||||
tag_type = tags.Tag.get_type(tag_cls)
|
||||
tag_doc = tag_cls.__doc__.strip().split('.')[0]
|
||||
types[tag_type] = tag_doc
|
||||
|
||||
data = {
|
||||
'success': True,
|
||||
'message': 'Types successfully retreived',
|
||||
'types': types
|
||||
'message': 'Tag classes successfully retreived',
|
||||
'tag_classes': TAGS
|
||||
}
|
||||
|
||||
self.set_header('Content-type', 'application/json')
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
<a id="read-rfid-tag" href="#">Read UID from RFID tag…</a>
|
||||
<label for="alias">Alias</label>
|
||||
<input id="alias" name="alias" type="text" placeholder="Your personal alias / identifier">
|
||||
<label for="type">Type</label>
|
||||
<select id="type" name="type">
|
||||
<label for="tag-class">Class</label>
|
||||
<select id="tag-class" name="tag-class">
|
||||
</select>
|
||||
<label for="parameter">Parameter</label>
|
||||
<input id="parameter" name="parameter" type="text" placeholder="A type-specific parameter">
|
||||
|
|
|
@ -40,12 +40,12 @@ class API {
|
|||
let tagElement = document.createElement('div')
|
||||
tagElement.setAttribute('class', 'tag')
|
||||
|
||||
let args = new Array('alias', 'uid', 'type', 'parameter')
|
||||
let args = new Array('alias', 'uid', 'tag_class', 'parameter')
|
||||
for(let arg of args)
|
||||
{
|
||||
let spanElement = document.createElement('span')
|
||||
let value = tag[arg] ? tag[arg] : '-'
|
||||
spanElement.setAttribute('class', arg)
|
||||
spanElement.setAttribute('class', arg.replace('_', '-'))
|
||||
spanElement.innerHTML = value
|
||||
tagElement.appendChild(spanElement)
|
||||
}
|
||||
|
@ -58,27 +58,27 @@ class API {
|
|||
}
|
||||
|
||||
/*
|
||||
* Refresh the tag types.
|
||||
* Refresh the tags.
|
||||
*/
|
||||
|
||||
refreshTypes()
|
||||
refreshTagClasses()
|
||||
{
|
||||
let callback = function(response)
|
||||
{
|
||||
let select = document.getElementById('type');
|
||||
let select = document.getElementById('tag-class');
|
||||
while(select.firstChild)
|
||||
select.removeChild(select.firstChild)
|
||||
|
||||
for(let type in response.types)
|
||||
for(let tag_class in response.tag_classes)
|
||||
{
|
||||
let option = document.createElement('option')
|
||||
option.setAttribute('value', type)
|
||||
option.innerHTML = type + ' (' + response.types[type] + ')'
|
||||
option.setAttribute('value', tag_class)
|
||||
option.innerHTML = tag_class + ' (' + response.tag_classes[tag_class] + ')'
|
||||
select.appendChild(option)
|
||||
}
|
||||
}
|
||||
|
||||
this.request('/pummeluff/types/', false, callback)
|
||||
this.request('/pummeluff/tag-classes/', false, callback)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -95,10 +95,10 @@ class API {
|
|||
if(response.success)
|
||||
{
|
||||
api.refreshRegistry()
|
||||
document.getElementById('uid').value = ''
|
||||
document.getElementById('alias').value = ''
|
||||
document.getElementById('parameter').value = ''
|
||||
document.getElementById('type').selectIndex = 0
|
||||
document.getElementById('uid').value = ''
|
||||
document.getElementById('alias').value = ''
|
||||
document.getElementById('parameter').value = ''
|
||||
document.getElementById('tag-class').selectIndex = 0
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -117,15 +117,15 @@ class API {
|
|||
{
|
||||
let latest_tag = undefined
|
||||
|
||||
let uid_field = document.getElementById('uid')
|
||||
let alias_field = document.getElementById('alias')
|
||||
let parameter_field = document.getElementById('parameter')
|
||||
let type_select = document.getElementById('type')
|
||||
let uid_field = document.getElementById('uid')
|
||||
let alias_field = document.getElementById('alias')
|
||||
let parameter_field = document.getElementById('parameter')
|
||||
let tag_class_select = document.getElementById('tag-class')
|
||||
|
||||
uid_field.value = ''
|
||||
alias_field.value = ''
|
||||
parameter_field.value = ''
|
||||
type_select.selectIndex = 0
|
||||
uid_field.value = ''
|
||||
alias_field.value = ''
|
||||
parameter_field.value = ''
|
||||
tag_class_select.selectIndex = 0
|
||||
|
||||
let link = document.getElementById('read-rfid-tag')
|
||||
link.classList.add('reading')
|
||||
|
@ -144,8 +144,8 @@ class API {
|
|||
if(response.parameter)
|
||||
parameter_field.value = response.parameter
|
||||
|
||||
if(response.type)
|
||||
type_select.value = response.type
|
||||
if(response.tag_class)
|
||||
tag_class_select.value = response.tag_class
|
||||
|
||||
link.classList.remove('reading')
|
||||
}
|
||||
|
@ -168,7 +168,7 @@ class API {
|
|||
api = new API()
|
||||
|
||||
api.refreshRegistry();
|
||||
api.refreshTypes();
|
||||
api.refreshTagClasses();
|
||||
|
||||
document.getElementById('register-form').onsubmit = function()
|
||||
{
|
||||
|
|
|
@ -117,8 +117,8 @@ button
|
|||
#read-rfid-tag
|
||||
{
|
||||
text-decoration: none;
|
||||
color: #fa0;
|
||||
font-size: 11px;
|
||||
color : #fa0;
|
||||
font-size : 11px;
|
||||
}
|
||||
|
||||
#read-rfid-tag.reading {
|
||||
|
@ -144,13 +144,13 @@ div.tag
|
|||
}
|
||||
|
||||
div.tag span.uid,
|
||||
div.tag span.type,
|
||||
div.tag span.tag-class,
|
||||
div.tag span.parameter
|
||||
{
|
||||
font-family: Courier New, monospace;
|
||||
}
|
||||
|
||||
div.tag span.type
|
||||
div.tag span.tag-class
|
||||
{
|
||||
display : inline-block;
|
||||
background-color: #888;
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
pycodestyle==2.5.0
|
||||
pylint==1.9.4
|
||||
pylint==2.4.4
|
5
setup.py
5
setup.py
|
@ -3,8 +3,6 @@
|
|||
Setup script for Mopidy-Pummeluff module.
|
||||
'''
|
||||
|
||||
from __future__ import absolute_import, unicode_literals, print_function
|
||||
|
||||
from setuptools import setup, find_packages
|
||||
|
||||
with open('requirements.txt') as f:
|
||||
|
@ -19,6 +17,7 @@ setup(
|
|||
url='https://github.com/confirm/mopidy-pummeluff',
|
||||
license='MIT',
|
||||
author='confirm IT solutions',
|
||||
author_email='mopidy-pummeluff@confirm.ch',
|
||||
description='Pummeluff is a Mopidy extension which allows you to control Mopidy via RFID tags',
|
||||
long_description=open('README.rst').read(),
|
||||
packages=find_packages(exclude=[
|
||||
|
@ -35,7 +34,7 @@ setup(
|
|||
'develop': requirements_dev,
|
||||
},
|
||||
entry_points={
|
||||
b'mopidy.ext': [
|
||||
'mopidy.ext': [
|
||||
'pummeluff = mopidy_pummeluff:Extension',
|
||||
],
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue