My next step was to modify my software so that it would work with the hub. In order to read a sensor, the software would need to know the switches to enable and disable for each sensor, and would need to enable those switches prior to reading the sensor.
My first thought was to include that information in the configuration file. However this approach would be inflexible, and would not permit multiple hubs as I was only planned to include the information for one switch.
My next idea was to search the network, locate the switch, and map out the path to each sensor. I got that working, but it still limited me to one switch as I was not searching each path for any additional switches.
Further research revealed that there is a NetworkMonitor class included in the 1-Wire API that periodically traverses the 1-Wire net and sends a message whenever a a sensor appears or disappears on the network. It uses the Observer design pattern, where the application wanting to receive notifications provides a class instance with the callback methods to the monitor. The information in the callback includes the full path to the sensor through multiple switches if any. This sounded like exactly what I wanted. Support for multiple switches and the ability to dynamically update whenever a sensor was added, removed, or even moved from one port to another.
Got it working fine in a stand alone program that just monitored the network. When I integrated the network monitor into my program the behavior was different. Every time it traversed the network it showed all the sensors as new. Then it would throw an exception after a few minutes and stop. Some kind of interaction between my code to read the bus and the network monitor. So I moved on to the approach I used as my final solution (for now). This was still my favorite approach, as it permits the network to be dynamic, adapting to sensors coming and going on the bus. I intend to revisit the idea sometime down the road.
For my next attempt, at program start up I manually traversed the entire network, including any nested switches using a breadth first search algorithm. I created an OWPath object (a class provided in the 1-Wire API) for each sensor found on the net so that the path could be opened and closed when reading the sensor. It doesn’t dynamically adapt to sensors moving or coming and going while the application is running, but it works well for building a static map of the network. I will have to restart the application if the sensors change or move in order to build a new map. I also can log any sensors found on the bus but not in my configuration file, or sensors in the configuration file not found on the bus. I may come back to the NetworkMonitor approach again, but I’m satisfied for now.
For anybody interested, here’s my code for traversing the 1-Wire network. There are a few things that are specific to my application, but the logic is hopefully clear enough to adapt. Sorry, but the formatting got a bit munged.
private Hashtable<String, OWPath> walkNet(DSPortAdapter adapter) { // vector for holding a list of paths to be searched Vector<OWPath> pathsToSearch = new Vector<OWPath>(); boolean searchResult = false; // hash table for holding the OWPath objects for each // device container. Hashtable<String, OWPath> devicePathHash = new Hashtable<String, OWPath>(); try { // seed list with main branch pathsToSearch.addElement(new OWPath(adapter)); // acquire the adapter adapter.beginExclusive(true); // setup the search adapter.setSearchAllDevices(); adapter.targetAllFamilies(); adapter.setSpeed(DSPortAdapter.SPEED_REGULAR); // walk path and get all devices on branch. // if any switches are found, add them to the list // of paths to search // search through all of the paths for (int i = 0; i < pathsToSearch.size(); i++) { // set searches to not use reset adapter.setNoResetSearch(); // get the next path to search and open it OWPath path = (OWPath)pathsToSearch.elementAt(i); try { // try to open the current path path.open(); } catch(Exception e) { // if opening the path failed, log an error and // continue on to the next path ErrorLog.logError("walkNet(): Error opening path " + path.toString()); continue; } // get the devices on the currently open path searchResult = adapter.findFirstDevice(); // loop while devices found while (searchResult) { // get the 1-Wire address String address = adapter.getAddressAsString(); // check if the device already exists in the hash // table of addresses if (!devicePathHash.containsKey(address)) { OneWireContainer owc = adapter.getDeviceContainer(address); // check to see if it's a switch. If so, add // it to the paths to be searched // if we haven't already searched it if (owc instanceof SwitchContainer) { SwitchContainer sc = (SwitchContainer)owc; byte[] state = sc.readDevice(); for (int j = 0; j < sc.getNumberChannels(state); j++) { OWPath tmp = new OWPath(adapter, path); tmp.add(owc, j); if (!pathsToSearch.contains(tmp)) { pathsToSearch.addElement(tmp); } } } // save off the address and path synchronized(devicePathHash) { devicePathHash.put(address, path); } } // check if the existing device moved else if (!path.equals((OWPath) devicePathHash.get(address))) { // if it has moved, add the new // address/path pair synchronized(devicePathHash) { devicePathHash.put(address, path); } } // find the next device on this branch path.open(); searchResult = adapter.findNextDevice(); } path.close(); } // clean up after ourselves adapter.setSearchAllDevices(); adapter.endExclusive(); } catch (OneWireException e) { ErrorLog.logError("Error Serching the 1-Wire Bus"); } return devicePathHash; }