Design for discovery agents done
1 parent ef68775 commit 5cb6e61036b9998a2346f878ce0c1ead870574d7
@David Whale David Whale authored on 25 May 2016
Showing 3 changed files
View
56
doc/devices_classes_branch.txt
PRESENT STATUS
 
Router written and integrated in energenie.loop()
 
No Discovery yet in Registry
Design for discovery done
 
 
--------------------------------------------------------------------------------
TODO NEXT
 
* think a bit about discovery, we might actually be able to get this
working as a separate service first time round
 
* implement auto device registration in the router (poor mans discovery)
when a message comes from an unknown sensorid,
build a device class instance wrapper for it
put it in the registry
knit it to the router
then call it's receive handler
 
* make the above auto device registration optional with a config flag in router
 
* Write discovery properly as a service in Registry
When an unknown device is found, add it to the registry
if the discovery process is enabled, and route it's address.
* check design for discovery with user requirements
 
* implement discovery code
 
* write test cases in Registry_test.py to test the 4 different discovery types
 
* put a discovery agent configuration in monitor_mihome.py and re test
 
 
 
----
 
* Need the registry to be persistent with save and load
 
choose a file format that is human readable, like a config file?
mostly the registry is read, occasionally it is written
 
----
 
Consider whether there is a need for a general update notify
 
 
----
 
* when a join request comes in, should optionally schedule a join_ack
going back, so that the device turns it's light off. This could also
be a way to manually pair up devices with an app, as it means
the user has pressed the join button, so they have physical
sight of the device.
 
----
 
Test with real radio
 
* add back in the loop() call in the monitor_mihome.py program
 
 
----
At this point, probably ready to write a set of test cases,
run the tests, and merge back to master to release this new
functionality to the wild.
 
-----
 
* update the test instructions and re-test everything before merge
 
* merge to master after test
 
END
View
94
src/energenie/Registry.py
# When a message comes in for this address, it will be routed to its handle_message() method
# address might be a string, a number, a tuple, but probably always the same for any one router
self.routes[address] = instance
 
def incoming_message(self, address, payload):
def incoming_message(self, address, message):
if self.incoming_cb != None:
self.incoming_cb(address, payload)
self.incoming_cb(address, message)
 
if address in self.routes:
ci = self.routes[address]
ci.incoming_message(payload)
ci.incoming_message(message)
 
else: # unknown address
self.handle_unknown(address, payload)
self.handle_unknown(address, message)
 
def when_incoming(self, callback):
self.incoming_cb = callback
 
"""Register a callback for unknown messages"""
#NOTE: this is the main hook point for auto discovery and registration
self.unknown_cb = callback
 
def handle_unknown(self, address, payload):
def handle_unknown(self, address, message):
if self.unknown_cb != None:
self.unknown_cb(address, payload)
self.unknown_cb(address, message)
else:
# Default action is just a debug message, and drop the payload
# Default action is just a debug message, and drop the message
print("Unknown address: %s" % str(address))
 
 
class Discovery():
"""A Discovery agent that just reports any unknown devices"""
def __init__(self, registry, router):
self.registry = registry
self.router = router
router.when_unknown(self.unknown_device)
 
def unknown_device(self, address, message):
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)))
# default action is to drop message
# override this method if you want special processing
 
def accept_device(self, address, message):
pass
# create device class instance from id information
# add to registry
# add to router
# forward message to new class instance for processing
#TODO: return the new device class instance to caller
 
 
class AutoDiscovery(Discovery):
"""A discovery agent that auto adds unknown devices"""
def __init__(self, registry, router):
Discovery.__init__(self, registry, router)
 
def unknown_device(self, address, message):
self.accept_device(address, message)
 
 
class ConfirmedDiscovery(Discovery):
"""A discovery agent that asks the app before accepting/rejecting"""
def __init__(self, registry, router, ask):
Discovery.__init__(self, registry, router)
self.ask_fn = ask
 
def unknown_device(self, address, message):
y = self.ask_fn(address, message)
if y:
self.accept_device(address, message)
else:
self.reject_device(address, message)
 
 
class JoinAutoDiscovery(Discovery):
"""A discovery agent that looks for join requests, and auto adds"""
def __init__(self, registry, router):
Discovery.__init__(self, registry, router)
 
def unknown_device(self, address, message):
# if it is not a join req
# route to unhandled message handler
# if it is a join req
# accept the device
# send join ack back to device (using new device class instance?)
pass
 
 
class JoinConfirmedDiscovery(Discovery):
"""A discovery agent that looks for join requests, and auto adds"""
def __init__(self, registry, router, ask):
Discovery.__init__(self, registry, router)
self.ask_fn = ask
 
def unknown_device(self, address, message):
# 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
 
 
# Might rename these, especially when we add in other protocols
# such as devices that are 868 wirefree doorbells etc.
View
src/monitor_mihome.py