#!/usr/bin/env python # # xbmc-wiimote - XBMC event client for Wii remotes # # Copyright © 2011 Paul van Tilburg # # XBMC Wiimote Gateway is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as published # by the Free Software Foundation, either version 3 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General # Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program. If not, see . import cwiid import sys from time import * from xbmc.xbmcclient import XBMCClient, PacketBUTTON from threading import Thread, Event, Timer ### Resettable timer code, from http://code.activestate.com/recipes/577407/, ### with comments and debug statements removed. class TimerReset(Thread): def __init__(self, interval, function, args=[], kwargs={}): Thread.__init__(self) self.interval = interval self.function = function self.args = args self.kwargs = kwargs self.finished = Event() self.resetted = True def cancel(self): self.finished.set() def run(self): while self.resetted: self.resetted = False self.finished.wait(self.interval) if not self.finished.isSet(): self.function(*self.args, **self.kwargs) self.finished.set() def reset(self, interval=None): if interval: self.interval = interval self.resetted = True self.finished.set() self.finished.clear() ### end of included code # Default settings PROGRAM = "XBMC Wiimote Gateway" ICON = "/usr/share/pixmaps/xbmc/bluetooth.png" WIIMOTE_BTADDR = sys.argv[1] WIIMOTE_LED = 0b1001 WIIMOTE_MAP = "JS0:WiiRemote" WIIMOTE_CONVERT = { 1: cwiid.BTN_UP, 2: cwiid.BTN_DOWN, 3: cwiid.BTN_LEFT, 4: cwiid.BTN_RIGHT, 5: cwiid.BTN_A, 6: cwiid.BTN_B, 7: cwiid.BTN_MINUS, 8: cwiid.BTN_HOME, 9: cwiid.BTN_PLUS, 10: cwiid.BTN_1, 11: cwiid.BTN_2} # Extend XBMCClient with a method to directly send WiiMote button codes. def send_wiimote_button(self, code=0, map_name=WIIMOTE_MAP, queue=0, repeat=1): packet = PacketBUTTON(code=int(code), map_name=str(map_name), queue=queue, repeat=repeat) packet.send(self.sock, self.addr, self.uid) XBMCClient.send_wiimote_button = send_wiimote_button def rumble_signal(wm): wm.rumble = 1 for i in range(0, 3): sleep(0.1) wm.rumble = (i % 2) def convert_msg_to_buttons(mesg): buttons = [] for button in WIIMOTE_CONVERT.keys(): if mesg & WIIMOTE_CONVERT[button]: buttons.append(button) return buttons def handle_msg(mesg_list, time): global xbmc, wm, tim for mesg in mesg_list: if mesg[0] == cwiid.MESG_BTN: print("Handling keycode %d" % mesg[1]) tim.reset() if (mesg[1] == 0): xbmc.send_wiimote_button(0, repeat=0) else: # FIXME: How to send combined key presses? for button in convert_msg_to_buttons(mesg[1]): xbmc.send_wiimote_button(button) elif mesg[0] == cwiid.MESG_ERROR: wm.close() tim.cancel() if (mesg[1] == cwiid.ERROR_DISCONNECT): print("Wiimote disconnect to to power-off") xbmc.send_notification(PROGRAM, "Wiimote disconnected") elif (mesg[1] == cwiid.ERROR_COMM): print("Wiimote communication error!") xbmc.send_notification(PROGRAM, "Wiimote communication error!") else: print("Unhandled and ignored message type: %d" % mesg[0]) def timeout(): print("Timeout due to inactivity!") def main(): # Create an XBMCClient object and connect. global xbmc, wm, tim xbmc = XBMCClient(PROGRAM, icon_file=ICON) xbmc.connect() while(True): # The main loop. try: print("Press 1+2 on the Wiimote with address %s..." % WIIMOTE_BTADDR) wm = cwiid.Wiimote(WIIMOTE_BTADDR, cwiid.FLAG_REPEAT_BTN | cwiid.FLAG_MESG_IFC) except RuntimeError as error: print(error) continue # If a Wiimote is found, set the leds, rumble, register the # callback and start the timer. tim = TimerReset(120, timeout) tim.start() wm.led = WIIMOTE_LED wm.rpt_mode = cwiid.RPT_BTN wm.mesg_callback = handle_msg rumble_signal(wm) battperc = 100.0 * wm.state['battery'] / cwiid.BATTERY_MAX print("Wiimote connected (battery: %d%%)" % battperc) xbmc.send_notification(PROGRAM, "Wiimote connected\n(battery: %d%%)" % battperc) tim.join() # A timeout has occured (due to inactivity), close the connection to # the Wiimote. try: wm.close() except ValueError: # Connection was already closed. pass print("Wiimote disconnected due to timeout") #xbmc.send_notification(PROGRAM, "Wiimote disconnected") sleep(3) # Ok we're done, close the connection. xbmc.close() if __name__=="__main__": main()