#46: Added Wiimote support
This commit is contained in:
parent
abbd8409ca
commit
2b03276159
3 changed files with 207 additions and 0 deletions
116
platypush/backend/wiimote.py
Normal file
116
platypush/backend/wiimote.py
Normal file
|
@ -0,0 +1,116 @@
|
|||
"""
|
||||
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||
"""
|
||||
|
||||
import cwiid
|
||||
import re
|
||||
import time
|
||||
|
||||
from platypush.backend import Backend
|
||||
from platypush.message import Message
|
||||
from platypush.message.event.wiimote import WiimoteEvent
|
||||
from platypush.message.request import Request
|
||||
|
||||
|
||||
class WiimoteBackend(Backend):
|
||||
"""
|
||||
Backend to communicate with a Nintendo WiiMote controller
|
||||
|
||||
Triggers:
|
||||
|
||||
* :class:`platypush.message.event.Wiimote.WiimoteEvent` \
|
||||
when the state of the Wiimote (battery, buttons, acceleration etc.) changes
|
||||
|
||||
Requires:
|
||||
|
||||
* **python3-wiimote** (follow instructions at https://github.com/azzra/python3-wiimote)
|
||||
"""
|
||||
|
||||
_wiimote = None
|
||||
|
||||
|
||||
def msg_callback(self):
|
||||
def _callback(msg_list, timestamp):
|
||||
print(msg_list)
|
||||
|
||||
return _callback
|
||||
|
||||
def get_wiimote(self):
|
||||
if not self._wiimote:
|
||||
self._wiimote = cwiid.Wiimote()
|
||||
self._wiimote.mesg_callback = self.msg_callback()
|
||||
# self._wiimote.enable(cwiid.FLAG_MESG_IFC | cwiid.FLAG_MOTIONPLUS)
|
||||
self._wiimote.enable(cwiid.FLAG_MOTIONPLUS)
|
||||
self._wiimote.rpt_mode = cwiid.RPT_ACC | cwiid.RPT_BTN | cwiid.RPT_MOTIONPLUS
|
||||
|
||||
self.logger.info('WiiMote connected')
|
||||
self._wiimote.led = 1
|
||||
self._wiimote.rumble = True
|
||||
time.sleep(0.5)
|
||||
self._wiimote.rumble = False
|
||||
|
||||
return self._wiimote
|
||||
|
||||
def get_state(self):
|
||||
wm = self.get_wiimote()
|
||||
state = wm.state
|
||||
parsed_state = {}
|
||||
|
||||
# Get buttons
|
||||
all_btns = [attr for attr in dir(cwiid) if attr.startswith('BTN_')]
|
||||
parsed_state['buttons'] = { btn: True for btn in all_btns
|
||||
if state.get('buttons', 0) & getattr(cwiid, btn) != 0 }
|
||||
|
||||
# Get LEDs
|
||||
all_leds = [attr for attr in dir(cwiid) if re.match('LED\d_ON', attr)]
|
||||
parsed_state['led'] = { led[:4]: True for led in all_leds
|
||||
if state.get('leds', 0) & getattr(cwiid, led) != 0 }
|
||||
|
||||
# Get errors
|
||||
all_errs = [attr for attr in dir(cwiid) if attr.startswith('ERROR_')]
|
||||
parsed_state['error'] = { err: True for err in all_errs
|
||||
if state.get('errs', 0) & getattr(cwiid, err) != 0 }
|
||||
|
||||
parsed_state['battery'] = round(state.get('battery', 0)/cwiid.BATTERY_MAX, 3)
|
||||
parsed_state['rumble'] = bool(state.get('rumble', 0))
|
||||
|
||||
if 'acc' in state:
|
||||
parsed_state['acc'] = tuple(int(acc/5)*5 for acc in state['acc'])
|
||||
|
||||
if 'motionplus' in state:
|
||||
parsed_state['motionplus'] = {
|
||||
'angle_rate': tuple(int(angle/100) for angle
|
||||
in state['motionplus']['angle_rate']),
|
||||
'low_speed': state['motionplus']['low_speed'],
|
||||
}
|
||||
|
||||
return parsed_state
|
||||
|
||||
|
||||
def run(self):
|
||||
super().run()
|
||||
connection_attempts = 0
|
||||
last_state = {}
|
||||
|
||||
while not self.should_stop():
|
||||
try:
|
||||
state = self.get_state()
|
||||
changed_state = { k: state[k] for k in state.keys()
|
||||
if state[k] != last_state.get(k) }
|
||||
|
||||
if changed_state:
|
||||
self.bus.post(WiimoteEvent(**changed_state))
|
||||
connection_attempts = 0
|
||||
last_state = state
|
||||
time.sleep(0.1)
|
||||
except RuntimeError as e:
|
||||
if type(e) == RuntimeError and str(e) == 'Error opening wiimote connection':
|
||||
if connection_attempts == 0:
|
||||
self.logger.info('Press 1+2 to pair your WiiMote controller')
|
||||
else:
|
||||
self.logger.exception(e)
|
||||
self._wiimote = None
|
||||
connection_attempts += 1
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
14
platypush/message/event/wiimote.py
Normal file
14
platypush/message/event/wiimote.py
Normal file
|
@ -0,0 +1,14 @@
|
|||
from platypush.message.event import Event
|
||||
|
||||
|
||||
class WiimoteEvent(Event):
|
||||
"""
|
||||
Event triggered upon Wiimote event
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
77
platypush/plugins/wiimote.py
Normal file
77
platypush/plugins/wiimote.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
"""
|
||||
.. moduleauthor:: Fabio Manganiello <blacklight86@gmail.com>
|
||||
"""
|
||||
|
||||
import time
|
||||
|
||||
from platypush.context import get_backend
|
||||
from platypush.plugins import Plugin, action
|
||||
|
||||
class WiimotePlugin(Plugin):
|
||||
"""
|
||||
WiiMote plugin.
|
||||
A wrapper around the :mod:`platypush.backend.wiimote` backend to
|
||||
programmatically control a Nintendo WiiMote.
|
||||
|
||||
It requires the WiiMote backend to be enabled.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _get_wiimote(cls):
|
||||
return get_backend('wiimote').get_wiimote()
|
||||
|
||||
|
||||
@action
|
||||
def connect(self):
|
||||
"""
|
||||
Connects to the WiiMote
|
||||
"""
|
||||
self._get_wiimote()
|
||||
|
||||
|
||||
@action
|
||||
def close(self):
|
||||
"""
|
||||
Closes the connection with the WiiMote
|
||||
"""
|
||||
self._get_wiimote().close()
|
||||
|
||||
|
||||
@action
|
||||
def rumble(self, secs):
|
||||
"""
|
||||
Rumbles the controller for the specified number of seconds
|
||||
"""
|
||||
wm = self._get_wiimote()
|
||||
wm.rumble = True
|
||||
time.sleep(secs)
|
||||
wm.rumble = False
|
||||
|
||||
|
||||
@action
|
||||
def state(self):
|
||||
"""
|
||||
Return the state of the controller
|
||||
"""
|
||||
return get_backend('wiimote').get_state()
|
||||
|
||||
|
||||
@action
|
||||
def set_leds(self, leds):
|
||||
"""
|
||||
Set the LEDs state on the controller
|
||||
|
||||
:param leds: Iterable with the new states to be applied to the LEDs. Example: [1, 0, 0, 0] or (False, True, False, False)
|
||||
:type leds: list
|
||||
"""
|
||||
|
||||
new_led = 0
|
||||
for i, led in enumerate(leds):
|
||||
if led:
|
||||
new_led |= (1 << i)
|
||||
|
||||
self._get_wiimote().led = new_led
|
||||
|
||||
|
||||
# vim:sw=4:ts=4:et:
|
||||
|
Loading…
Reference in a new issue