diff --git a/doc/devices_classes_branch.txt b/doc/devices_classes_branch.txt index 3c2f38b..f6b8da3 100644 --- a/doc/devices_classes_branch.txt +++ b/doc/devices_classes_branch.txt @@ -403,18 +403,13 @@ Router written and integrated in energenie.loop() Design for discovery done -Test cases for 5 discovery variants done +Test cases for 5 discovery variants done and work -------------------------------------------------------------------------------- TODO NEXT -joinauto with join_ack is working - -Code up and test join_autoask - - - +Add auto join semantics to monitor_mihome ---- PERSISTENT REGISTRY diff --git a/src/energenie/OpenThings_test.py b/src/energenie/OpenThings_test.py index e785946..72ae5bd 100644 --- a/src/energenie/OpenThings_test.py +++ b/src/energenie/OpenThings_test.py @@ -8,6 +8,7 @@ from OpenThings import * import pprint import unittest +from lifecycle import * def printhex(payload): @@ -153,32 +154,7 @@ #TODO: Break dependence on Devices.MIHO005_REPORT (makes tests brittle) -#i.e. put a test vector in this test harness -#TODO: Capture and compare outputs from each method (using decorators??) -def test_0(m): - #print("test disabled:%s" % m) - def run(*args, **kwargs): - print("running:%s" % m) - r = m(*args, **kwargs) - print("finished:%s" % m) - return r - - def nothing(*args, **kwargs): - print("test disabled:%s" % m) - return None - - ##return nothing # DISABLE - return run # ENABLE ALL - -def test_1(m): - def run(*args, **kwargs): - print("running:%s" % m) - r = m(*args, **kwargs) - print("finished:%s" % m) - return r - - return run class TestMessage(unittest.TestCase): diff --git a/src/energenie/Registry.py b/src/energenie/Registry.py index c0b8b6b..81ac25b 100644 --- a/src/energenie/Registry.py +++ b/src/energenie/Registry.py @@ -288,28 +288,28 @@ router.when_unknown(self.unknown_device) def unknown_device(self, address, message): - print("message from unknown device:%s" % str(address)) + pass##print("message from unknown device:%s" % str(address)) # default action is to drop message # override this method in sub classes if you want special processing def reject_device(self, address, message): - print("message rejected from:%s" % (str(address))) + pass##print("message rejected from:%s" % (str(address))) # default action is to drop message # override this method if you want special processing def accept_device(self, address, message, forward=True): - print("accept_device:%s" % str(address)) + ##print("accept_device:%s" % str(address)) # At moment, intentionally assume everything is mfrid=Energenie product_id = address[1] device_id = address[2] - print("**** wiring up registry and router for %s" % str(address)) + ##print("**** wiring up registry and router for %s" % str(address)) ci = Devices.DeviceFactory.get_device_from_id(product_id, device_id) self.registry.add(ci, "auto_%s_%s" % (str(hex(product_id)), str(hex(device_id)))) self.router.add(address, ci) # Finally, forward the first message to the new device class instance if forward: - print("**** routing first message to class instance") + ##print("**** routing first message to class instance") ci.incoming_message(message) ##self.registry.list() @@ -346,7 +346,7 @@ Discovery.__init__(self, registry, router) def unknown_device(self, address, message): - print("unknown device auto join %s" % str(address)) + ##print("unknown device auto join %s" % str(address)) #TODO: need to make this work with correct meta methods ##if not OpenThings.PARAM_JOIN in message: @@ -361,7 +361,6 @@ # but don't forward the join request as it will be malformed with no value ci = self.accept_device(address, message, forward=False) ci.join_ack() # Ask new class instance to send a join_ack back to physical device - #TODO: MiHomeDevice needs this join_ack() added to it class JoinConfirmedDiscovery(Discovery): @@ -371,20 +370,25 @@ self.ask_fn = ask def unknown_device(self, address, message): - ####HERE#### - print("TODO: unknown device confirmed join %s" % str(address)) - # if it is not a join req - # route to unhandled message handler - # if it is a join req - # ask app - # if no - # reject device - # if yes - # accept device - # send join ack back to device (using new device class instance) - pass #TODO + print("**** unknown device confirmed join %s" % str(address)) + #TODO: need to make this work with correct meta methods + ##if not OpenThings.PARAM_JOIN in message: + try: + j = message[OpenThings.PARAM_JOIN] + except KeyError: + j = None + if j == None: # not a join + self.unknown_device(address, message) + else: # it is a join + y = self.ask_fn(address, message) + if y: + # but don't forward the join request as it will be malformed with no value + ci = self.accept_device(address, message, forward=False) + ci.join_ack() # Ask new class instance to send a join_ack back to physical device + else: + self.reject_device(address, message) # Might rename these, especially when we add in other protocols diff --git a/src/energenie/Registry_test.py b/src/energenie/Registry_test.py index 9fe1bdd..b6e2a70 100644 --- a/src/energenie/Registry_test.py +++ b/src/energenie/Registry_test.py @@ -11,6 +11,7 @@ import unittest from Registry import * import radio +from lifecycle import * radio.DEBUG=True @@ -24,6 +25,7 @@ # test the auto create mechanism registry.auto_create(self) + @test_1 def test_capabilities(self): print("tv switch:%s" % self.tv.has_switch()) print("tv send:%s" % self.tv.can_send()) @@ -33,18 +35,21 @@ print("fan send:%s" % self.fan.can_send()) print("fan receive:%s" % self.fan.can_receive()) + @test_1 def test_ook_tx(self): """Test the transmit pipeline""" self.fan.turn_on() self.fan.turn_off() + @test_1 def test_fsk_tx(self): """Test the transmit pipeline for MiHome FSK devices""" self.tv.turn_on() self.tv.turn_off() + @test_1 def test_fsk_rx(self): """Test the receive pipeline for FSK MiHome adaptor""" @@ -92,7 +97,8 @@ self.msg = OpenThings.Message(Devices.MIHO005_REPORT) self.msg[OpenThings.PARAM_VOLTAGE]["value"] = 240 - def XXtest_discovery_none(self): + @test_0 + def test_discovery_none(self): discovery_none() # Poke synthetic unknown into the router and let it route to unknown handler @@ -102,7 +108,8 @@ # expect unknown handler to fire - def XXtest_discovery_auto(self): + @test_0 + def test_discovery_auto(self): discovery_auto() # Poke synthetic unknown into the router and let it route to unknown handler @@ -114,7 +121,8 @@ registry.list() fsk_router.list() - def XXtest_discovery_ask(self): + @test_0 + def test_discovery_ask(self): def yes(a,b): return True def no(a,b): return False @@ -138,8 +146,8 @@ registry.list() fsk_router.list() - - def XXXtest_discovery_autojoin(self): + @test_0 + def test_discovery_autojoin(self): discovery_autojoin() # Poke synthetic unknown JOIN into the router and let it route to unknown handler @@ -155,8 +163,7 @@ registry.list() fsk_router.list() - #----- HERE ----- - + @test_1 def test_discovery_askjoin(self): def no(a,b): return False def yes(a,b): return True @@ -173,17 +180,17 @@ (Devices.MFRID_ENERGENIE, Devices.PRODUCTID_MIHO005, UNKNOWN_SENSOR_ID), self.msg) # expect reject - ##registry.list() - ##fsk_router.list() + registry.list() + fsk_router.list() - ##discovery_askjoin(no) + discovery_askjoin(yes) - ##fsk_router.incoming_message( - ## (Devices.MFRID_ENERGENIE, Devices.PRODUCTID_MIHO005, UNKNOWN_SENSOR_ID), self.msg) + fsk_router.incoming_message( + (Devices.MFRID_ENERGENIE, Devices.PRODUCTID_MIHO005, UNKNOWN_SENSOR_ID), self.msg) # expect auto accept and join_ack logic to fire - ##registry.list() - ##fsk_router.list() + registry.list() + fsk_router.list() if __name__ == "__main__": diff --git a/src/energenie/lifecycle.py b/src/energenie/lifecycle.py index 88422d3..d820e44 100644 --- a/src/energenie/lifecycle.py +++ b/src/energenie/lifecycle.py @@ -9,16 +9,19 @@ return m() return inner + def disabled(m): """Load-time waring about disabled function""" print("warning: method is disabled:%s" % m) def nothing(*args, **kwargs):pass return nothing + def untested(m): print("warning: untested method %s" % str(m)) return m + def log_method(m): def inner(*args, **kwargs): print("CALL %s with: %s %s" % (m, args, kwargs)) @@ -27,10 +30,37 @@ return r return inner + def deprecated(m): print("warning: deprecated method %s" % str(m)) return m + +def test_0(m): + #print("test disabled:%s" % m) + #def run(*args, **kwargs): + # print("running:%s" % m) + # r = m(*args, **kwargs) + # print("finished:%s" % m) + # return r + + def nothing(*args, **kwargs): + print("test disabled:%s" % m) + return None + + return nothing # DISABLE + ##return run # ENABLE ALL + + +def test_1(m): + def run(*args, **kwargs): + print("running:%s" % m) + r = m(*args, **kwargs) + print("finished:%s" % m) + return r + + return run + # END