Getting Started¶
Sample Application: Getting Bridge SNAPcore Version¶
In this example we show how to write a Python application using SNAPconnect to retrieve the SNAPcore firmware version of a serially-connected bridge node.
"""BridgeVersion.py"""
import logging
import binascii
import sys
from snapconnect import snap
SERIAL_TYPE = snap.SERIAL_TYPE_RS232
SERIAL_PORT = "/dev/tty.usbserial-AK04R6G3"
class BridgeVersionClient(object):
def __init__(self):
self.bridge_address = None # Set a default value for the bridge address
self.bridge_version = "Unknown" # Set a default value for the bridge version
# You can define what functions can be called remotely on your SNAPconnect instance
# using the `funcs` argument
funcs = {
"major_callback": self.major_callback,
"minor_callback": self.minor_callback
}
# Create a SNAP instance
self.comm = snap.Snap(funcs=funcs)
# You can also define which functions can be called using `add_rpc_func`
self.comm.add_rpc_func("patch_callback", self.patch_callback)
# SNAPconnect also provides hooks for certain events, for example when the serial connection
# is opened or closed
self.comm.set_hook(snap.hooks.HOOK_SERIAL_OPEN, self.hook_open)
self.comm.set_hook(snap.hooks.HOOK_SERIAL_CLOSE, self.hook_close)
# Open a serial connection to your bridge
self.comm.open_serial(SERIAL_TYPE, SERIAL_PORT)
self.log = logging.getLogger("BridgeVersionClient")
snapconnect_addr = self.comm.local_addr()
self.log.info("SNAPconnect Address: %r" % binascii.hexlify(snapconnect_addr))
def hook_open(self, serial_type, port, addr=None):
"""Callback function invoked when a serial connection is opened."""
if addr:
self.bridge_address = addr
self.log.info("Serial connection opened to %s", binascii.hexlify(addr))
self.get_version()
else:
self.log.critical("Unable to open serial connection")
return addr
def hook_close(self, serial_type, port):
"""Callback function invoked when a serial connection is closed."""
self.log.info("Serial connection closed")
def get_version(self):
"""Start the RPC chain to retrieve the bridge SNAPcore version."""
self.comm.rpc(self.bridge_address, 'callback', 'major_callback', 'getInfo', 5)
def major_callback(self, major_version):
"""Callback function invoked when the major version is returned from the bridge."""
self.bridge_version = str(major_version) + "."
self.comm.rpc(self.bridge_address, 'callback', 'minor_callback', 'getInfo', 6)
def minor_callback(self, minor_version):
"""Callback function invoked when the minor version is returned from the bridge."""
self.bridge_version += str(minor_version) + "."
self.comm.rpc(self.bridge_address, 'callback', 'patch_callback', 'getInfo', 7)
def patch_callback(self, patch_version):
"""Callback function invoked when the patch version is returned from the bridge."""
self.bridge_version += str(patch_version)
self.log.info("Bridge SNAPcore version: %s" % self.bridge_version)
self.stop()
def stop(self):
"""Stop the SNAPconnect instance."""
self.comm.close_all_serial() # Close all serial connections opened with SNAPconnect
sys.exit(0) # Exit the program
if __name__ == "__main__":
# Configure Python's built-in logging module to display any info or higher level messages
logging.basicConfig(level=logging.INFO)
client = BridgeVersionClient() # Instantiate a client instance
# Start the SNAPconnect loop, nothing can happen after this point
client.comm.loop()
Details on all of the parameters that SNAPconnect methods take are described in the SNAPconnect API section.
Let’s walk through this simple example to see how it works. The four packages we import in this example are the
standard Python logging package, the sys
package which we use to terminate the program, a package called
binascii
to print our SNAP MAC addresses in human-readable form, and the SNAPconnect package.
Once we define the BridgeVersionClient
class, we instantiate the SNAPconnect instance we will use in the
__init__
function (look for self.comm
in the sample code). When we instantiate the SNAPconnect instance,
we pass it a Python dictionary with the functions we would like to make publicly available to be called by other SNAP
nodes. In this example, we register two callback functions where we want the nodes to send responses to getInfo
requests.
funcs = {
"major_callback": self.major_callback,
"minor_callback": self.minor_callback
}
# Create a SNAP instance
self.comm = snap.Snap(funcs=funcs)
The next function we call is add_rpc_func
to add another publicly available function to be called by other SNAP
nodes. This demonstrates the two ways you can make functions publicly available using SNAPconnect.
self.comm.add_rpc_func("patch_callback", self.patch_callback)
Next we call set_hook
to add hooks for two events that are important in our program lifecycle: when the serial
connection is opened and when it is closed. SNAPconnect provides hooks for a number of other events, see the
Hooks
section in the SNAPconnect API documentation for more information.
self.comm.set_hook(snap.hooks.HOOK_SERIAL_OPEN, self.hook_open)
self.comm.set_hook(snap.hooks.HOOK_SERIAL_CLOSE, self.hook_close)
After we set up our functions and hooks, we call the open_serial
method on our SNAPconnect instance to have it
open a serial connection to the SNAP bridge node.
self.comm.open_serial(SERIAL_TYPE, SERIAL_PORT)
Finally, we create a logging instance to log important events and the output of what we receive from the SNAP bridge node.
self.log = logging.getLogger("BridgeVersionClient")
Within the main section we configure the default logger to print any logged messages to standard out.
logging.basicConfig(level=logging.INFO)
We then create an instance of the client class that we defined earlier in the sample code. At the end we call the loop method of the SNAPconnect instance to start having SNAPconnect continuously send, receive, and process SNAP messages. Until we call the loop method, SNAPconnect will not be able to do anything we ask it to do.
client = BridgeVersionClient() # Instantiate a client instance
# Start the SNAPconnect loop, nothing can happen after this point
client.comm.loop()
To run this program, you should first change the SERIAL_TYPE
and SERIAL_PORT
to those of your bridge device
(see the snapconnect-serial-params section for more information). Use SNAPtoolbelt to
verify the bridge device is working.
At this point, you will be able to run the Python program:
python ``BridgeVersion.py``
INFO:BridgeVersionClient:SNAPconnect Address: '000020'
INFO:BridgeVersionClient:Serial connection opened to 09a199
INFO:BridgeVersionClient:Bridge SNAPcore version: 2.6.9
INFO:BridgeVersionClient:Serial connection closed
If all went well, you will see something that looks like the above messages and the program will print out the SNAPcore version of your bridge.
If your bridge node is not connected or the specified SERIAL_PORT
is not correct, you may see the following error from PyserialDriver
:
ERROR:snaplib.serialwrapper.PyserialDriver:An error occured while setting up the serial port
If you encounter that message, verify that your device is connected and available on the specified port.