Any idea on what the Control port (default 27000) is used for and command syntax (if any?) I haven’t been able to do anything on this port.
I’m writing a Unix daemon to talk to a Brultech ECM-1220 Zigbee Power monitor via a ConnectPort X2. While I am talking to the ECM-1220 via the ConnectPort C2 on it’s assigned TCP port, there’s a certain amount of hit and miss determining what the TCP port will be. When I add a 2nd Xbee end device to the network, it will become a complete guess as to how zb_tcp_serial.py assigns TCP ports to devices in the PAN.
I’m hoping the control port provides a way to determine the TCP port given the devices Node ID or Address.
The zb_tcp_serial.py script is intended to be a demonstration of the Python-based application functionality of the ConnectPort X and not a finished feature for use in a production environment.
That said, the zb_tcp_serial.py is a good starting point to start writing your own application.
If you unzip the zb_tcp_serial.zip file that is distributed along with the zb_tcp_serial.py script you will notice that it will unpack into a directory called Zts (for “Zigbee-to-Serial”). In this directory there is a file called, “ServiceManager.py” In this file there is a function which belongs to the TCPControl class called discover_and_bind(). This function performs a node list dicovery on the Zigbee network and creates the TCP port to Zigbee node mappings.
This function creates its mappings by calling the method create_multiple() on the _Bindings class. A reference to a _Bindings instance is created in the TCPControl class and is called “self._bindings”
Here are some modifications you could follow to write the application you need:
Create your own method in TCPControl, perhaps call it bind_using_list(), which takes in a data object which defines a mapping between XBee addresses and TCP ports.
Create a method on the _Bindings class, perhaps called create_mapping(), which will taking in an XBee address and a TCP port and create a binding, using the code in create_multiple() as a template.
Call the method create_mapping() instead of discover_and_bind() in zb_tcp_serial.py and you’ll have the functionality you need!
If you need any assistance achieving any of these steps, please write us here and we’ll be happy to help!
I think I see what you’re talking about, but this brings up a larger point on the ConnectPort X2 box.
The ConnectPort X2 is billed as a Zigbee-to-Network gateway. Unlike the X4 or X8. Zigbee is ALL it does. So the ability to access Zigbee devices via TCP/IP from the Ethernet Port certainly sounds to me like Core functionality of the machine. So after spending $199 plus shipping, I’m supposed to accept the idea that I have to write code for core functionality of the only thing the machine does?
At this point, I’m able to use the box using the “demo” Python code. But without the code, all the box can do is be a PAN coordinator, which I could have done for $50 with an Xbee module. I really think Digi needs to rethink this and sell a machine that actually provides the functionality they market it for.
I don’t want to be a jerk and am happy with the machine thus far. But I think there’s a real divergence between your response and how Digi markets this box on their website. If I had known that writing code would be required, I would have bought the box knowing it was required. OK, I’ve ranted enough!
I’ll take a look in the places you mentioned and see what I can see in the code. Even though I write Python code regularly, I’m sure I’ll have some seriously dumb questions as I get into this. I looked at the code once before and think I know what you’re talking about. I guess that after I get an enumeration, I’ll need to create a way to read it via a TCP session. We’ll see…
I started looking at the code and would like to see the data structures to get an idea of how to use them. Any hints on how to get program output? If there a way I can send them to the event log, or is there another method?
OK, another stupid question. The RemoteAPI class defines some methods (like list) that appear to provide (at least) some of what I’m looking for. Any idea what the URL would look like to access these methods? If it would work, I could use the Python xmlrpclib to read what I need. If I need to write sode, I still need to know the URL path to access the new methods. Maybe I’m being dense, but I don’t see how to determine the path in the code.
I’ve passed your comments on internally. Thank you for your product feedback. It is always valuable.
As far as the XML-RPC interface goes, it is defined in the RemoteAPI object. This object is registered with the Python SimpleXMLRPCServer class (see: http://docs.python.org/lib/module-SimpleXMLRPCServer.html) in order to define its methods.
You should be able to use just about any XML-RPC compliant library to speak to this server. It registers it self on TCP port 27000 (27000 is defined in the “control_port” argument passed to the TCPControl class constructor). Therefore, the url will be: http://ip.of.device:27000/RPC2
The following methods are available:
discover()
list()
get_temperatures()
It would be best to make the first call by your daemon the discover() call (in order to initialize any bindings which need to occur) and then every subsequent call a list() call unless you have reason to suspect that a device was added to the network. Then you will need to call discover() again.
Each and every XML-RPC library will represent the return values from these XML-RPC functions a bit differently. It will be best to try them out and see what the return data object representation looks like. Rest assured, by using these methods you will be able to find the mapping from TCP port to XBee node.
Please let us know if we can be of further assistance!
Ah! I am sorry! I just realized I neglected your first question about how to send output to the event log.
There are two ways actually.
The first way is to take a look at the printf trace buffer. If you telnet to the IP of your X2 device you will receive a command line prompt that will looks like this:
#>
If you type:
#> set trace state=on mask=printf:*
You will receive all trace messages that end up calling printf() in the system including all calls to “print” in Python.
The second method is much simpler: if you bring up the Web UI of the X2 and navigate to Applications->Python->Auto-start Settings and uncheck the zb_tcp_serial.py application you can stop the zb_tcp_serial.py application from starting when the X2 boots. Reboot the X2.
Next, telnet to the X2 and type the following at the console prompt:
#> python zb_tcp_serial.py
You will see the output of the program’s “print” statements in your telnet session. If you terminate your telnet session, your application will still run. There is no way to kill or break your Python application other than by rebooting the device.
Thanks for your gracious reply to my rant. I was really bothered as I’ve used Digi products for years and they were always a class act. A production quality box calls for production-quality software. But enough of that.
Thanks for the XML-RPC help. I had looked in ServiceManager.py and seen the three methods you mention. I assumed these were reachable across the network but hadn’t put together how what the URL would look like. I’ll try making a short Python program (for my PC) to hit the control port and see what’s available. Your instructions seem more than sufficient to get through this. I’ll post my code when (if?) I get it working.
Also, thanks for the help with geting python output. Not being a particularly great programmer, I was wondering how I was going to see the tracebacks I’m guaranteed to generate. This helps a lot.
Got it working! Here’s the python code that runs on my PC to obtain the Zigbee address to TCP port mapping (I used the list method as the discover output was identical - I presume that if I’ve discovered new devices through the Web interface, they’ll show up in list):
import xmlrpclib
Define the Host and port
HOST=‘192.168.1.54’
PORT=‘27000’
Create the XML-RPC object instance
server = xmlrpclib.ServerProxy(‘http://’ + HOST + ‘:’ + PORT + ‘/RPC2’)
Obtain the result of the list method
list=server.list()
Loop through the results and list relevant fields
for x in list:
# NOTE: Everything from here to the end is indented to part of the “for” list
# Get the 64-bit address and clean it up
ExtendedAddress=x[‘addr_extended’]
ExtendedAddress=ExtendedAddress.replace(‘[’,‘’)
ExtendedAddress=ExtendedAddress.replace(‘]’,‘’)
ExtendedAddress=ExtendedAddress.replace(‘!’,‘’)
# Get the Node ID
NodeID=x[‘label’]
# Get the TCP Port
TCPPort=x[‘port_number’]
print '64-bit Address: ’ + ExtendedAddress + ', NodeID: ’ + NodeID + ', TCP Port: ’ + str(TCPPort)
Here’s the output from a program run from the command prompt:
I just discovered that the auto-removal of whitespace when posting python code can be thwarted with the “pre” tag. Click on the bold or italic button when editing - replace the b or i with pre. Example result: