diff --git a/src/energenie/Devices.py b/src/energenie/Devices.py index e2b99af..316483e 100644 --- a/src/energenie/Devices.py +++ b/src/energenie/Devices.py @@ -354,6 +354,18 @@ """An estimate of the next time we expect a message from this device""" pass + def get_readings_summary(self): + """Try to get a terse summary of all present readings""" + # if self.readings does not exist + # return "no readings" + # + # for each reading + # call get_x to get the reading + # think of a very short name, perhaps first letter of reading name? + # add it to a terse string + # return the string + return "no readings (yet - TODO)" + def get_receive_count(self): return self.rxseq @@ -405,6 +417,9 @@ device_id = (LegacyDevice.DEFAULT_HOUSE_ADDRESS, 1) elif type(device_id) == int: device_id = (LegacyDevice.DEFAULT_HOUSE_ADDRESS, device_id) + elif type(device_id) == tuple and device_id[0] == None: + device_id = (LegacyDevice.DEFAULT_HOUSE_ADDRESS, device_id[1]) + EnergenieDevice.__init__(self, device_id, ook_interface) #TODO: These might now just be implied by the ook_interface adaptor self.config.frequency = 433.92 diff --git a/src/energenie/Registry.py b/src/energenie/Registry.py index 80ba2c5..fe71dd7 100644 --- a/src/energenie/Registry.py +++ b/src/energenie/Registry.py @@ -77,9 +77,9 @@ DEFAULT_FILENAME = "registry.kvs" def __init__(self, filename=None): + print("***Opening DeviceRegistry") self.store = KVS(filename) - @untested def load_from(self, filename=None): """Start with a blank in memory registry, and load from the given filename""" if filename == None: filename = DeviceRegistry.DEFAULT_FILENAME @@ -148,9 +148,14 @@ dl.append(d) return dl + def names(self): + """Get a list of all the names in the registry""" + return self.store.keys() registry = DeviceRegistry() -#TODO: registry.reload?? +import os +if os.path.isfile(DeviceRegistry.DEFAULT_FILENAME): + registry.load_from(DeviceRegistry.DEFAULT_FILENAME) # This will create all class instance variables in the module that imports the registry. diff --git a/src/setup_tool.py b/src/setup_tool.py index 5b5ae09..9508aaf 100644 --- a/src/setup_tool.py +++ b/src/setup_tool.py @@ -7,11 +7,16 @@ # and the demo apps can just refer to object variables names # from an assumed auto_create registry, that is built using this setup tool. +#TODO: Choose a better way to interrupt other than Ctrl-C +#It's very platform independent +#also, the foreground thread gets the KeyboardInterrupt, +#so as soon as threads are added, its a bad way to terminate user entry +#or processing. +import time import energenie from energenie.lifecycle import * -#TODO: Catch Ctrl-C interrupt if possible try: readin = raw_input # Python 2 except NameError: @@ -20,86 +25,157 @@ quit = False -@log_method def do_legacy_learn(): """Repeatedly broadcast a legacy switch message, so you can learn a socket to the pattern""" - pass #TODO # get house code, default to energenie code + hc = readin("House code? (ENTER for default) ") + if hc == "": + house_code = None + else: + house_code = int(hc, 16) + #TODO: error check + # get switch index, default 1 (0,1,2,3,4) - # go into transmit OOK mode + si = readin("Switch index 1..4? (ENTER for all)") + if si == "": + switch_index = 0 #ALL + else: + switch_index = int(si) + #TODO: error check + + device = energenie.Devices.ENER002((house_code, switch_index)) + # in a loop until Ctrl-C - # transmit on message for house/device - # wait a short while + try: + while True: #TODO: detect Ctrl-C + print("ON") + device.turn_on() + time.sleep(0.5) + print("OFF") + device.turn_off() + time.sleep(0.5) + except KeyboardInterrupt: + pass # user exit -@log_method def do_mihome_discovery(): """Discover any mihome device when it sends reports""" - pass #TODO - # select join ask discovery mode - # in a loop until Ctrl-C - # just wait, the discovery agent will do everything for us - # in discover_askjoin mode, it will even ask the user for registry add/ignore + print("Discovery mode, press Ctrl-C to stop") + energenie.Registry.discovery_ask(energenie.Registry.ask) + try: + while True: + time.sleep(1) # tick + except KeyboardInterrupt: + print("Discovery stopped") -@log_method +def show_registry(): + """Show the registry as a numbered list""" + names = energenie.registry.names() + i=1 + for name in names: + print("%d. %s %s" % (i, name, energenie.registry.get(name))) + i += 1 + return names + + def do_list_registry(): """List the entries in the registry""" - energenie.registry.list() + show_registry() -@log_method -def do_rename_device(): - """Rename a device in the registry to a different name""" - #This is useful when turning auto discovered names into your own names - #TODO: The registry does not support a rename mode at the moment - #will need to add this by getting the record, deleting it, and appending it again - pass #TODO - - -@log_method -def do_delete_device(): - """Delete a device from the registry so it is no longer recognised""" - pass #TODO - #list the registry with numbers - # get the number of the device to delete, ctrl-C aborts - # ask the registry to delete it - - -@log_method def do_switch_device(): + global quit """Turn the switch on a socket on and off, to test it""" - pass #TODO # select the device from a menu of numbered devices + names = show_registry() + # ask user for on/off/another/done - # if on, turn it on - # if off, turn it off - # if another, show list again - # if done, exit + i = readin("Which device %s to %s" % (1,len(names))) + device_index = int(i) + #TODO: error check + #TODO: Ctrl-C check + + print("selected: %s" % names[device_index-1]) + + #TODO could list action methods by introspecting device class?? + def on(): + print("will turn on") + + def off(): + print("will turn off") + + MENU = [ + ("on", on), + ("off", off) + ] + + try: + while not quit: + show_menu(MENU) + choice = get_choice((1,len(MENU))) + if choice != None: + handle_choice(MENU, choice) + except KeyboardInterrupt: + pass # user exit + quit = False -@log_method +@untested def do_show_device_status(): """Show the readings associated with a device""" pass #TODO + #TODO: need a way of asking a device for a summary of it's readings + #In a way that Device() could implement it for all devices?? + #TODO, not sure might show all devices in a simple table #note different field names make table display hard, unless there are shorthand names # for each device in the registry # show a summary line for that device -@log_method -def do_watch_device(): - """Repeatedly show readings for a single device""" +@untested +def do_watch_devices(): + """Repeatedly show readings for all devices""" + try: + while True: + print('-' * 80) + names = energenie.registry.names() + for name in names: + device = energenie.registry.get(name) + readings = device.get_readings_summary() + print("%s %s" % (name, readings)) + print("") + time.sleep(1) + + except KeyboardInterrupt: + pass # user exit + +@unimplemented +def do_rename_device(): + """Rename a device in the registry to a different name""" + #This is useful when turning auto discovered names into your own names + #TODO: The registry does not support a rename mode at the moment + #will need to add this by getting the record, deleting it, and appending it again pass #TODO - #show a list of devices - # get a device number from the user - # loop until Ctrl-C - # show device status - # wait until device status updates + names = show_registry() + # get a choice 1..num+1 + # ask for a new name + # registry.rename(old_name, new_name) -@log_method +@unimplemented +def do_delete_device(): + """Delete a device from the registry so it is no longer recognised""" + pass #TODO + names = show_registry() + # get a choice 1..num+1 + # registry.delete(name) + + + + +@unimplemented def do_logging(): """Enter a mode where all communications are logged to screen and a file""" pass #TODO @@ -128,17 +204,19 @@ """Get and validate a numberic choice from the tuple choices(first, last)""" first = choices[0] last = choices[1] - while True: - choice = readin("Choose %d to %d?" % (first, last)) - try: - choice = int(choice) - if choice < first or choice > last: - print("Must enter a number between %d and %d" % (first, last)) - else: - return choice - except ValueError: - print("Must enter a number") - pass + try: + while True: + choice = readin("Choose %d to %d?" % (first, last)) + try: + choice = int(choice) + if choice < first or choice > last: + print("Must enter a number between %d and %d" % (first, last)) + else: + return choice + except ValueError: + print("Must enter a number") + except KeyboardInterrupt: + do_quit() def handle_choice(menu, choice): @@ -150,11 +228,11 @@ ("legacy learn mode", do_legacy_learn), ("mihome discovery mode", do_mihome_discovery), ("list registry", do_list_registry), - ("watch device", do_watch_device), - ("rename device", do_rename_device), - ("delete device", do_delete_device), ("switch device", do_switch_device), ("show device status", do_show_device_status), + ("watch devices", do_watch_devices), + ("rename device", do_rename_device), + ("delete device", do_delete_device), ("logging", do_logging), ("quit", do_quit) ] @@ -164,8 +242,9 @@ while not quit: print("MAIN MENU") show_menu(MAIN_MENU) - choice = get_choice((1,len(MAIN_MENU)+1)) - handle_choice(MAIN_MENU, choice) + choice = get_choice((1,len(MAIN_MENU))) + if not quit: + handle_choice(MAIN_MENU, choice) #----- MAIN ENTRY POINT -------------------------------------------------------