diff --git a/doc/devices_classes_branch.txt b/doc/devices_classes_branch.txt index f38a515..f8e5b05 100644 --- a/doc/devices_classes_branch.txt +++ b/doc/devices_classes_branch.txt @@ -223,6 +223,17 @@ -------------------------------------------------------------------------------- PLAN UP TO: MERGE BACK TO MASTER +---- PRE-RELEASE CLEAN-UP + +Move all global code from Registry.py (setup of router, registry) to __init__ + +Enable all tests and see if they work as a group + +Remove all commented out code + +Search TODO:s and remove any that are done + + ---- TEST ON REAL HARDWARE diff --git a/src/discover_mihome.py b/src/discover_mihome.py index f4916e9..107032b 100644 --- a/src/discover_mihome.py +++ b/src/discover_mihome.py @@ -6,7 +6,7 @@ import energenie -# You could also use the standard energenie.Registry.ask callback instead if you want +# You could also use the standard energenie.ask callback instead if you want # as that does exactly the same thing def ask_fn(address, message): @@ -27,10 +27,10 @@ def discover_mihome(): # Select your discovery behaviour from one of these: - ##energenie.Registry.discovery_auto() - energenie.Registry.discovery_ask(ask_fn) - ##energenie.Registry.discovery_autojoin() - ##energenie.Registry.discovery_askjoin(ask_fn) + ##energenie.discovery_auto() + energenie.discovery_ask(ask_fn) + ##energenie.discovery_autojoin() + ##energenie.discovery_askjoin(ask_fn) # Run the receive loop permanently, so that receive messages are processed try: diff --git a/src/energenie/Devices.py b/src/energenie/Devices.py index 569a78a..d795b99 100644 --- a/src/energenie/Devices.py +++ b/src/energenie/Devices.py @@ -66,49 +66,49 @@ # This makes simple discovery possible. BROADCAST_ID = 0xFFFFFF # Energenie broadcast -#TODO: This might be deprecated now, and replaced with the DeviceFactory? -#Still used in deprecated methods in Registry.py - -@unimplemented # no longer supported -def getDescription(mfrid, productid): - if mfrid == MFRID_ENERGENIE: - mfr = "Energenie" - if productid == PRODUCTID_MIHO004: - product = "MIHO004 MONITOR" - elif productid == PRODUCTID_MIHO005: - product = "MIHO005 ADAPTOR PLUS" - elif productid == PRODUCTID_MIHO006: - product = "MIHO006 HOUSE MONITOR" - elif productid == PRODUCTID_MIHO013: - product = "MIHO013 ETRV" - else: - product = "UNKNOWN_%s" % str(hex(productid)) - else: - mfr = "UNKNOWN_%s" % str(hex(mfrid)) - product = "UNKNOWN_%s" % str(hex(productid)) - - return "Manufacturer:%s Product:%s" % (mfr, product) -#TODO this might be deprecated now, and replaced with the Device classes. -#e.g. if there is a turn_on method or get_switch method, it has a switch. -#still used in switch.py demo (will be until device classes deployed into tests) - -@unimplemented # no longer supported -def hasSwitch(mfrid, productid): - if mfrid != MFRID: return False - if productid == PRODUCTID_MIHO005: return True - return False +#TODO: Remove these +##@unimplemented # no longer supported +##def getDescription(mfrid, productid): +## if mfrid == MFRID_ENERGENIE: +## mfr = "Energenie" +## if productid == PRODUCTID_MIHO004: +## product = "MIHO004 MONITOR" +## elif productid == PRODUCTID_MIHO005: +## product = "MIHO005 ADAPTOR PLUS" +## elif productid == PRODUCTID_MIHO006: +## product = "MIHO006 HOUSE MONITOR" +## elif productid == PRODUCTID_MIHO013: +## product = "MIHO013 ETRV" +## else: +## product = "UNKNOWN_%s" % str(hex(productid)) +## else: +## mfr = "UNKNOWN_%s" % str(hex(mfrid)) +## product = "UNKNOWN_%s" % str(hex(productid)) +#### +## return "Manufacturer:%s Product:%s" % (mfr, product) +#### +## +###TODO this might be deprecated now, and replaced with the Device classes. +###e.g. if there is a turn_on method or get_switch method, it has a switch. +###still used in switch.py demo (will be until device classes deployed into tests) +#### +##@unimplemented # no longer supported +##def hasSwitch(mfrid, productid): +## if mfrid != MFRID: return False +## if productid == PRODUCTID_MIHO005: return True +## return False #----- DEFINED MESSAGE TEMPLATES ---------------------------------------------- -##TODO: This should really be in OpenThings.Message +##TODO: remove +##import copy +## +##def create_message(message): +## return copy.deepcopy(message) -import copy - -def create_message(message): - return copy.deepcopy(message) SWITCH = { "header": { @@ -162,7 +162,6 @@ ] } - REGISTERED_SENSOR = { "header": { "mfrid": MFRID_ENERGENIE, @@ -172,7 +171,6 @@ } } - MIHO005_REPORT = { "header": { "mfrid": MFRID_ENERGENIE, @@ -234,16 +232,17 @@ ] } -def send_join_ack(radio, mfrid, productid, sensorid): - # send back a JOIN ACK, so that join light stops flashing - response = OpenThings.Message(JOIN_ACK) - response.set(header_mfrid=mfrid, - header_productid=productid, - header_sensorid=sensorid) - p = OpenThings.encode(response) - radio.transmitter() - radio.transmit(p, inner_times=2) - radio.receiver() +#TODO: remove +##def send_join_ack(radio, mfrid, productid, sensorid): +## # send back a JOIN ACK, so that join light stops flashing +## response = OpenThings.Message(JOIN_ACK) +## response.set(header_mfrid=mfrid, +## header_productid=productid, +## header_sensorid=sensorid) +## p = OpenThings.encode(response) +## radio.transmitter() +## radio.transmit(p, inner_times=2) +## radio.receiver() diff --git a/src/energenie/KVS.py b/src/energenie/KVS.py index 100e0bd..003cb85 100644 --- a/src/energenie/KVS.py +++ b/src/energenie/KVS.py @@ -129,7 +129,7 @@ if self.filename != None: with open(self.filename, 'a') as f: - f.write("ADD %s\n" % key) + f.write("\nADD %s\n" % key) for k in values: v = values[k] f.write("%s=%s\n" % (k, v)) diff --git a/src/energenie/OnAir.py b/src/energenie/OnAir.py index 560df00..c173a8a 100644 --- a/src/energenie/OnAir.py +++ b/src/energenie/OnAir.py @@ -13,12 +13,20 @@ # NOTE: This also might include intelligent power level selection based # on RSSI reports from different devices. -from lifecycle import * -import OpenThings -import TwoBit -import radio +##from lifecycle import * import time +try: + # Python 2 + import OpenThings + import TwoBit + import radio +except ImportError: + # Python 3 + from . import OpenThings + from . import TwoBit + from . import radio + class OpenThingsAirInterface(): def __init__(self): diff --git a/src/energenie/OpenThings.py b/src/energenie/OpenThings.py index 8311433..c12897f 100644 --- a/src/energenie/OpenThings.py +++ b/src/energenie/OpenThings.py @@ -4,10 +4,13 @@ from lifecycle import * import time + try: - import crypto # python 2 + # Python 2 + import crypto except ImportError: - from . import crypto # python 3 + # Python 3 + from . import crypto def warning(msg): @@ -25,6 +28,7 @@ def __str__(self): return repr(self.value) + #----- CRYPT PROCESSING ------------------------------------------------------- crypt_pid = None @@ -33,6 +37,7 @@ global crypt_pid crypt_pid = pid + #----- PARAMETERS ------------------------------------------------------------- # report has bit 7 clear @@ -132,6 +137,7 @@ PARAM_WATER_PRESSURE : {"n":"WATER_PRESSURE", "u":"Pa"}, } + def paramname_to_paramid(paramname): """Turn a parameter name to a parameter id number""" for paramid in param_info: diff --git a/src/energenie/Registry.py b/src/energenie/Registry.py index 5d3860e..f82b08d 100644 --- a/src/energenie/Registry.py +++ b/src/energenie/Registry.py @@ -19,50 +19,51 @@ from KVS import KVS -directory = {} +#TODO: REMOVE +##directory = {} -@unimplemented # no longer supported -def allkeys(d): - result = "" - for k in d: - if len(result) != 0: - result += ',' - result += str(k) - return result +##@unimplemented # no longer supported +##def allkeys(d): +## result = "" +## for k in d: +## if len(result) != 0: +## result += ',' +## result += str(k) +## return result -@unimplemented # no longer supported -def update(message): - """Update the local directory with information about this device""" - now = time.time() - header = message["header"] - sensorId = header["sensorid"] - - if not (sensorId in directory): - # new device discovered - desc = Devices.getDescription(header["mfrid"], header["productid"]) - print("ADD device:%s %s" % (hex(sensorId), desc)) - directory[sensorId] = {"header": message["header"]} - #trace(allkeys(directory)) - - directory[sensorId]["time"] = now - #TODO would be good to keep recs, but need to iterate through all and key by paramid, - #not as a list index, else merging will be hard. - - -@unimplemented # no longer supported -def size(): - return len(directory) - - -@unimplemented # no longer supported -def get_sensorids(): - return directory.keys() - - -@unimplemented # no longer supported -def get_info(sensor_id): - return directory[sensor_id] +## @unimplemented # no longer supported +## def update(message): +## """Update the local directory with information about this device""" +## now = time.time() +## header = message["header"] +## sensorId = header["sensorid"] +## ## +## if not (sensorId in directory): +## # new device discovered +## desc = Devices.getDescription(header["mfrid"], header["productid"]) +## print("ADD device:%s %s" % (hex(sensorId), desc)) +## directory[sensorId] = {"header": message["header"]} +## #trace(allkeys(directory)) +## ## +## directory[sensorId]["time"] = now +## #TODO would be good to keep recs, but need to iterate through all and key by paramid, +## #not as a list index, else merging will be hard. +## ## +## +## @unimplemented # no longer supported +## def size(): +## return len(directory) +## ## +## +## @unimplemented # no longer supported +## def get_sensorids(): +## return directory.keys() +## ## +## +## @unimplemented # no longer supported +## def get_info(sensor_id): +## return directory[sensor_id] @@ -79,6 +80,10 @@ def __init__(self, filename=None): ##print("***Opening DeviceRegistry") self.store = KVS(filename) + self.fsk_router = None + + def set_fsk_router(self, fsk_router): + self.fsk_router = fsk_router def load_from(self, filename=None): """Start with a blank in memory registry, and load from the given filename""" @@ -106,11 +111,12 @@ """Get the description for a device class from the store, and construct a class instance""" c = self.store[name] - if c.can_receive(): - if isinstance(c, Devices.MiHomeDevice): - ##print("Adding rx route for receive enabled device %s" % c) - address = (c.manufacturer_id, c.product_id, c.device_id) - fsk_router.add(address, c) + if self.fsk_router != None: + if c.can_receive(): + if isinstance(c, Devices.MiHomeDevice): + ##print("Adding rx route for receive enabled device %s" % c) + address = (c.manufacturer_id, c.product_id, c.device_id) + self.fsk_router.add(address, c) return c def rename(self, old_name, new_name): @@ -165,10 +171,10 @@ #TODO: Might move this to energenie.init() so that it is optional #will make it possible to run all the test cases together also. -registry = DeviceRegistry() -import os -if os.path.isfile(DeviceRegistry.DEFAULT_FILENAME): - registry.load_from(DeviceRegistry.DEFAULT_FILENAME) +##registry = DeviceRegistry() +##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. @@ -398,60 +404,60 @@ #TODO: Name is not completely representative of function. # This is the Energenie 433.92MHz with OpenThings -fsk_router = Router("fsk") +##fsk_router = Router("fsk") #OOK receive not yet written #It will be used to be able to learn codes from Energenie legacy hand remotes ##ook_router = Router("ook") -#TODO: Improve this interface -# (temporary) helpful methods to switch between different discovery methods -# Note that the __init__ automaticall registers itself with router - -def discovery_none(): - fsk_router.when_unknown(None) - -def discovery_auto(): - d = AutoDiscovery(registry, fsk_router) - ##print("Using auto discovery") - -def discovery_ask(ask_fn): - d = ConfirmedDiscovery(registry, fsk_router, ask_fn) - ##print("using confirmed discovery") - -def discovery_autojoin(): - d = JoinAutoDiscovery(registry, fsk_router) - ##print("using auto join discovery") - -def discovery_askjoin(ask_fn): - d = JoinConfirmedDiscovery(registry, fsk_router, ask_fn) - ##print("using confirmed join discovery") - - -def ask(address, message): - MSG = "Do you want to register to device: %s? " % str(address) - try: - if message != None: - print(message) - y = raw_input(MSG) - - except AttributeError: - y = input(MSG) - - if y == "": return True - y = y.upper() - if y in ['Y', 'YES']: return True - return False - -#TODO: Might move this to energenie.init() so that it is optional -#will make it possible to run all the test cases together also. - -# Default discovery mode, unless changed by app -##discovery_none() -##discovery_auto() -##discovery_ask(ask) -discovery_autojoin() -##discovery_askjoin(ask) +## #TODO: Improve this interface +## # (temporary) helpful methods to switch between different discovery methods +## # Note that the __init__ automaticall registers itself with router +## ## +## def discovery_none(): +## fsk_router.when_unknown(None) +## ## +## def discovery_auto(): +## d = AutoDiscovery(registry, fsk_router) +## ##print("Using auto discovery") +## ## +## def discovery_ask(ask_fn): +## d = ConfirmedDiscovery(registry, fsk_router, ask_fn) +## ##print("using confirmed discovery") +## ## +## def discovery_autojoin(): +## d = JoinAutoDiscovery(registry, fsk_router) +## ##print("using auto join discovery") +## ## +## def discovery_askjoin(ask_fn): +## d = JoinConfirmedDiscovery(registry, fsk_router, ask_fn) +## ##print("using confirmed join discovery") +## ## +## +## def ask(address, message): +## MSG = "Do you want to register to device: %s? " % str(address) +## try: +## if message != None: +## print(message) +## y = raw_input(MSG) +## ## +## except AttributeError: +## y = input(MSG) +## ## +## if y == "": return True +## y = y.upper() +## if y in ['Y', 'YES']: return True +## return False +## ## +## #TODO: Might move this to energenie.init() so that it is optional +## #will make it possible to run all the test cases together also. +## ## +## # Default discovery mode, unless changed by app +## ##discovery_none() +## ##discovery_auto() +## ##discovery_ask(ask) +## discovery_autojoin() +## ##discovery_askjoin(ask) # END diff --git a/src/energenie/__init__.py b/src/energenie/__init__.py index 7481b1a..2e9560a 100644 --- a/src/energenie/__init__.py +++ b/src/energenie/__init__.py @@ -7,6 +7,7 @@ # Future versions of this *might* also start receive monitor or scheduler threads. import time +import os try: # Python 3 @@ -21,14 +22,41 @@ import Registry import OpenThings -registry = Registry.registry -fsk_router = Registry.fsk_router + +registry = None +fsk_router = None +ook_router = None + def init(): """Start the Energenie system running""" + + global registry, fsk_router, ook_router + radio.init() OpenThings.init(Devices.CRYPT_PID) + fsk_router = Registry.Router("fsk") + + #OOK receive not yet written + #It will be used to be able to learn codes from Energenie legacy hand remotes + ##ook_router = Registry.Router("ook") + + registry = Registry.DeviceRegistry() + registry.set_fsk_router(fsk_router) + ##registry.set_ook_router(ook_router + + if os.path.isfile(registry.DEFAULT_FILENAME): + registry.load_from(registry.DEFAULT_FILENAME) + + + # Default discovery mode, unless changed by app + ##discovery_none() + ##discovery_auto() + ##discovery_ask(ask) + discovery_autojoin() + ##discovery_askjoin(ask) + def loop(receive_time=1): """Handle receive processing""" @@ -64,4 +92,47 @@ radio.finished() + +def discovery_none(): + fsk_router.when_unknown(None) + + +def discovery_auto(): + d = Registry.AutoDiscovery(registry, fsk_router) + ##print("Using auto discovery") + + +def discovery_ask(ask_fn): + d = Registry.ConfirmedDiscovery(registry, fsk_router, ask_fn) + ##print("using confirmed discovery") + + +def discovery_autojoin(): + d = Registry.JoinAutoDiscovery(registry, fsk_router) + ##print("using auto join discovery") + + +def discovery_askjoin(ask_fn): + d = Registry.JoinConfirmedDiscovery(registry, fsk_router, ask_fn) + ##print("using confirmed join discovery") + + +def ask(address, message): + MSG = "Do you want to register to device: %s? " % str(address) + try: + if message != None: + print(message) + y = raw_input(MSG) +## + except AttributeError: + y = input(MSG) +## + if y == "": return True + y = y.upper() + if y in ['Y', 'YES']: return True + return False + + + + # END \ No newline at end of file diff --git a/src/energenie/crypto.py b/src/energenie/crypto.py index 7156718..3fbea58 100644 --- a/src/energenie/crypto.py +++ b/src/energenie/crypto.py @@ -3,7 +3,6 @@ # Crypto engine for OpenThings, including crc calculation - ran = None #static uint16_t ran; diff --git a/src/registry.kvs b/src/registry.kvs index e32c79e..0647b56 100644 --- a/src/registry.kvs +++ b/src/registry.kvs @@ -1,7 +1,12 @@ -ADD tv +IGN tv type=MIHO005 device_id=1675 ADD fan type=ENER002 device_id=[822412, 1] + +ADD tv +type=MIHO005 +device_id=1675 + diff --git a/src/setup_tool.py b/src/setup_tool.py index 87e4618..5d3457f 100644 --- a/src/setup_tool.py +++ b/src/setup_tool.py @@ -132,7 +132,7 @@ """Discover any mihome device when it sends reports""" print("Discovery mode, press Ctrl-C to stop") - energenie.Registry.discovery_ask(energenie.Registry.ask) + energenie.discovery_ask(energenie.ask) try: while True: energenie.loop() # Allow receive processing