Newer
Older
pyenergenie / src / setup_tool.py
# setup_tool.py  28/05/2016  D.J.Whale
#
# A simple menu-driven setup tool for the Energenie Python library.

# Just be a simple menu system.
#   This then means you don't have to have all this in the demo apps
#   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 *

try:
    readin = raw_input # Python 2
except NameError:
    readin = input # Python 3

quit = False


def do_legacy_learn():
    """Repeatedly broadcast a legacy switch message, so you can learn a socket to the pattern"""
    # 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)
    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
    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


def do_mihome_discovery():
    """Discover any mihome device when it sends reports"""
    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")


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"""
    show_registry()


def do_switch_device():
    global quit
    """Turn the switch on a socket on and off, to test it"""
    # select the device from a menu of numbered devices
    names = show_registry()

    # ask user for on/off/another/done
    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


@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


@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
    names = show_registry()
    # get a choice 1..num+1
    # ask for a new name
    # registry.rename(old_name, new_name)


@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
    # loop until Ctrl-C
    #   if a device update comes in
    #   display summary of its data on screen
    #   add summary of data to energenie.csv using Logging.log_message


@log_method
def do_quit():
    """Finished with the program, so exit"""
    global quit
    quit = True


def show_menu(menu):
    """Display a menu on the console"""
    i = 1
    for item in menu:
        print("%d. %s" % (i, item[0]))
        i += 1


def get_choice(choices):
    """Get and validate a numberic choice from the tuple choices(first, last)"""
    first = choices[0]
    last  = choices[1]
    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):
    """Route to the handler for the given menu choice"""
    menu[choice-1][1]()


MAIN_MENU = [
    ("legacy learn mode",     do_legacy_learn),
    ("mihome discovery mode", do_mihome_discovery),
    ("list registry",         do_list_registry),
    ("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)
]


def setup_tool():
    while not quit:
        print("MAIN MENU")
        show_menu(MAIN_MENU)
        choice = get_choice((1,len(MAIN_MENU)))
        if not quit:
            handle_choice(MAIN_MENU, choice)


#----- MAIN ENTRY POINT -------------------------------------------------------

if __name__ == "__main__":
    energenie.init()
    try:
        setup_tool()
    finally:
        energenie.finished()

# END