import socket, re import appuifw, e32, key_codes e32.ao_yield() # Some utility stuff that I came up with. # At some point I mean to experiment with creating some sort of # template-method-based object oriented application framework that # encapsulates all of the appuifw "view" and concurrency details. class AppuifwStateStack(object): """ Maintains a stack of AppuifwAppStates """ def __init__(self): self.stack = [] def push(self): """ Push the current appuifw.app state onto the stack. """ app = appuifw.app self.stack.append((app.title, app.body, app.menu, app.exit_key_handler)) def restore(self, state): app = appuifw.app (app.title, app.body, app.menu, app.exit_key_handler) = state def pop(self): """ Pop (restore) the appuifw.app state from the stack and delete the state object. """ self.restore(self.stack.pop()) def restore_original(self): """ Restore to the first item and clear stack. """ self.restore(self.stack[0]) del self.stack[:] def set_exit_if_standalone(): """Only set_exit() if this wasn't invoked from the interpreter ui.""" appname = appuifw.app.full_name() if appname[-10:] != u"Python.app": appuifw.app.set_exit() def bt_socket_connect(target=''): """ Stole this from Nokia's "bluetooth sockets" example (appendix F). Let the user select a device and serial service, then connect to that service and return the socket. """ if not target: (address, services) = socket.bt_discover() if len(services) > 1: choices = services.keys() choices.sort() choice = appuifw.popup_menu( [unicode(services[x])+": "+x for x in choices], u'Choose port:') target = (address, services[choices[choice]]) else: target = (address, services.values()[0]) sock = socket.socket(socket.AF_BT,socket.SOCK_STREAM) sock.connect(target) return sock class RemoteControlApp(object): """ Remote control application. """ STATE_OFF = 0 STATE_ON = 1 STATE_NONE = -1 state_str = { 1: "ON", 0: "OFF", -1: "" } # This defines the modules and commands. # Fields are: 0 = menu item name, 1 = associated command, 2 = initial state # For STATE_OFF and STATE_ON items, clicking the list item will toggle # the off/on state by appending "on" or "off" to the command [1]. # For STATE_NONE items, the command [1] will just be sent unchanged. # Strings get converted into unicode later. command_list = [ ["Light 1", "A1", STATE_OFF], ["Light 2", "A2", STATE_OFF], ["Lamp 1", "A3", STATE_OFF], ["Lamp 2", "A4", STATE_OFF], ["Fan 1", "A5", STATE_OFF], ["Fan 2", "A6", STATE_OFF], ["TV", "A7", STATE_OFF], ["Plug", "A8", STATE_OFF], ["All On", "A9", STATE_NONE], ["All Off", "A0", STATE_NONE], ] def __init__(self): app = appuifw.app self.app_lock = e32.Ao_lock() self.exit_flag = False # So far, in this app, this is only uses to restore the app state if # the app is run from within the interpreter ui. state = self.appstate = AppuifwStateStack() state.push() app.title = u"8051projects.info" app.exit_key_handler = self.handle_exit self.bt_connect() self.listbox_items = map(self.make_item_name, self.command_list) self.listbox = appuifw.Listbox(self.listbox_items, self.handle_list) app.body = self.listbox self.listbox.bind(key_codes.EKeyLeftArrow, self.handle_list_left) self.listbox.bind(key_codes.EKeyRightArrow, self.handle_list_right) def make_item_name(self, item): s = self.state_str[item[2]] if s: return unicode("%s [%s]" % (item[0], s)) else: return unicode(item[0]) def bt_connect(self): self.sock = bt_socket_connect() def send_command(self, command): sock = self.sock sock.send(command + "\r\n") def refresh_item_name(self, itemnum): item = self.command_list[itemnum] self.listbox_items[itemnum] = self.make_item_name(item) self.listbox.set_list(self.listbox_items, itemnum) def toggle_state(self, itemnum): item = self.command_list[itemnum] if item[2] == self.STATE_OFF: self.send_command("%s1" % (item[1])) item[2] = self.STATE_ON elif item[2] == self.STATE_ON: self.send_command("%s2" % (item[1])) item[2] = self.STATE_OFF else: raise RuntimeError("can't toggle this item") self.refresh_item_name(itemnum) def handle_list(self): lb = appuifw.app.body itemnum = lb.current() name, cmd, state = item = self.command_list[itemnum] if state > -1: self.toggle_state(itemnum) else: self.send_command(cmd) def lamp_brightness(self, direction): lb = appuifw.app.body itemnum = lb.current() item = self.command_list[itemnum] if item[2] < 0: return item[2] = self.STATE_ON cmd = item[1] houseletter = re.sub("[0-9]+","",cmd) self.send_command("%s1, %s %s" % (cmd, houseletter, direction)) item[2] = self.STATE_ON self.refresh_item_name(itemnum) def handle_list_left(self): self.lamp_brightness("dim") def handle_list_right(self): self.lamp_brightness("bright") def handle_exit(self): """Clean up and exit.""" self.sock.close() self.appstate.restore_original() self.exit_flag = True self.app_lock.signal() set_exit_if_standalone() def main(self): while not self.exit_flag: self.app_lock.wait() if __name__ == "__main__": RemoteControlApp().main()