Library Mixup

I have two 1-Wire adapters that permit a computer to act as a bus master on a 1-Wire network.  The DS9097 is a serial to 1-Wire adapter, and requires a computer with a serial port.  The DS9490 is a USB to 1-Wire adapter and requires a USB port. I have used the DS9490 with my Windows workstation, and the DS9097 with my Linux weather station computer.  I needed a different plan with the Guruplug, as it doesn’t have a serial port like the old computer did.  I have an inexpensive USB to serial converter that could be used with the DS9097 if needed.

I had downloaded and installed the 1-Wire API for Java, but haven’t been able to get it to work properly with the DS9490 USB adapter on my current Windows workstation. It worked fine with my DS9097 serial port adapter.  I had it working previously (several years ago), but have since upgraded the OS on my workstation from Windows XP 32 bit to Vista 64 bit and then to Windows 7 64 bit.  Yes, it’s been a while since I tested my weather application on this workstation.  I hadn’t needed to run the application on my workstation since the XP days.  I just made changes as needed on Windows and tested on Linux, where I was running the DS9097 serial port adapter.  When I first ran into problems on my Windows workstation, I switched to the serial port adapter until I could diagnose the problem, chalking it up to a 32bit/64 bit driver issue.

Well, I finally got back to looking at the issue.  I ran the 1-Wire viewer that came with the Java API on my workstation, and it couldn’t see the USB adapter.  When I downloaded and ran the jump start version direct from the Dallas web site, it did see the adapter.  Also, the 64 bit version bundled with the driver could see the adapter as well.  I downloaded the newer source for the one bundled with the drivers, so I could study and compile the code.  It referenced classes and methods that weren’t in my 1-Wire API jar file.  I had  the library source as part of the API, and those classes weren’t there at all.  Also, the source for the 1-Wire viewer used the same methods for discovering and opening the adapter that my application was using.  So I couldn’t compile the viewer locally, and the source used the same methods for opening the adapter that I was using.

After some searching, I found that Dallas has an FTP site, where they had a newer version of the library and source than what was included in the official API.  Once I installed this “secret” library in place of the official one, the USB adapter worked fine.  For anybody stuck with the same problem as I was, here is a link to the FTP site.  Grab the onewireapi.jar file (and the corresponding source file if desired), and replace the one that came with the official API. The one wire viewer application source may provide some useful examples as well.

Hardware Inventory

So now it’s time to check out all the sensors and see what work is required there.  Here’s where things stand

Sensors

  • Barometer – works fine.  Compared the readings with a local weather station and the calibration is still good too.
  • Temperature – work fine
  • Humidity – shows up on net, but humidity value is always 100%.  After several weeks indoors it appears to be reading accurately now.  However I have a replacement Honeywell HIH-4021 humidity sensor chip ready to install on the board.  Should be an easy fix
  • Solar – shows up on net.  Not sure about the photocell.  Ordered a replacement photocell to install.  This part has a lower peak voltage than the previous photocell, so some calibration may be necessary.  The old photocell tended to cause clipping under bright sunlight, so this should be an improvement.
  • Lightning – completely dead.  Ordered a new board from Hobby Boards.
  • Anemometer – Wind speed appears to work.  Direction is intermittent (mostly not working).  Opened up the anemometer and cleaned out all the dirt and bug remains.  Helped some, but I think the best course of action is to replace it.  Ordered an ADS anemometer from Hobby Boards.  Changing anemometer brands required some software changes as well.  Nothing too difficult.  The wind speed sensor is similar to the old AAG one, but with a different formula for calculating the wind speed.  Wind direction is based on one voltage returned rather than four like the old AAG sensor.
  • Rain – seems to work fine after a good cleaning.  However I need to rewire it using an RJ45 rather than RJ11 connector.  I believe it originally came with an RJ45 and I changed it.  But I can’t remember for sure.

Hardware

  • Temp/Humidity/Solar sensor housing (homemade radiation shield) – U/V has taken it’s toll.  The plastic bowls I had used are brittle and cracking.  Need to replace them with something more U/V resistant.  The fan (a computer case fan) still works.
  • Base for rain gauge – this was homemade from a plastic lid from a laundry detergent container.  U/V has made it brittle as well.  Maybe the base for an outdoor flower pot will work as a replacement.
  • Stand and supports – PVC tubing is holding up fine.  Just want to make sure everything is secure.  May even paint it this time around to make it look a little less homemade.

Nothing that can’t be fixed.  I have parts on order, and am scouring the hardware stores for U/V resistant plastic parts.  Future posts will outline all of the fixes as I make them.

Software Update

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;

    }

Hub and Spoke

A simple 1-Wire network connects all the sensors on a bus in a daisy chain configuration. This allows one device to potentially take down the entire bus. It actually worked pretty reliably for me for several years. But it doesn’t lend itself very well to taking one sensor our of the chain for service while keeping the rest of the chain operational.

Another consideration is power for some of the sensors. In a 1-Wire network, the devices draw power from the 1-Wire bus, known as parasitic power. This makes it easy to get power to the sensors. Since this is the same bus used for data and signalling, available power is limited and drawing power from this bus may affect the sensors being read.

Another addition I wanted to make is to add external power for the sensors, again in the name of reliability. I experimented with sending power over some unused wires on my cables before, but never implemented it as the bus architecture without power worked for me initially.

I was able to find a solution to address both of these issues. Another kit from Hobby Boards.

Hobby Boards 1-Wire Hub

This one is their 6 channel hub. It provides 6 channels for connecting 1-Wire devices, and provides regulated external power on the unused wires on the cables. This will allow me to group sensors on separate channels, and to provide external power to them as well.  I built the kit in an evening. Be warned, the Hobby Boards kits use surface mount parts. Easy to lose parts and can be tricky to solder. But I got it built and tested. All channels working and power is available. Next installment is the software updates I made to support the hub.

New Station Computer

While very reliable, my weather station computer was old, outdated, and power hungry.  While searching for an appropriate upgrade, I came across plug computers  They are small (slightly larger than a pack of cigarettes), power efficient (draws less than 5 watts), less expensive than a full size computer, and runs embedded Linux.  I ordered a Guruplug Server from Global Scale Technologies, along with their JTAG accessory in case I managed to brick the computer.  Good thing too, as it took me no time at all (like maybe 2 hours) to render it un-bootable.  How did I manage to do that, you might ask.  I did the following:

  • apt-get update
  • apt-get upgrade
  • apt-get dist-upgrade

After that the computer failed to boot.  That started me down the path of getting the JTAG to work and upgrading uBoot.  Then downloading and installing the kernel and file system.  Now it could boot again.  I ended up adding an 8GB Class 10 microSD card and installing Debian Linux on it.  Then modifying the uBoot parameters to permit booting from the microSD card. There were additional tasks, such as getting it to be a stable wireless client, installing software, and configuring it the way I wanted it to.

Existing Station Hardware

First I should talk about what hardware I already have in place. The weather station consists of several 1-Wire sensors. It has an AAG anemometer for measuring wind speed and direction. The temperature, humidity, solar, barometric pressure, and lightning sensors are all kits sold by Hobby Boards. The rain sensor is made by Rainwise and modified for 1-Wire by Hobby Boards. I built the kits along with the housing and mounting. The base structure is made from PVC tubing. It has a fan aspirated radiation shield I made from threaded rod, plastic bowls, and a computer case fan. The rain gauge is mounted on the plastic lid from a tub of laundry detergent. Several adapters, t-fittings, and a shower drain tie it all together. The problem is that over time, UV radiation caused the plastic bowls and and lid to deteriorate. That, along with the fact that some of the sensors had become intermittent, are the reasons I took down the weather station for a redesign. More on the fix, hopefully with detailed pictures to come. Also coming soon will be a write up of my new weather station computer.  The current computer is an ancient Pentium 3 450 running Fedora Core 6.

Weather Station Revival

I have had a passing interest in the weather ever since the 1970’s. I even took a college course in meteorology, and liked to check the college weather station whenever I passed by the console.  Several years ago, I built a homebrew weather station, and developed my own software in Java to read the weather sensors and publish that information to CWOP, Weather Underground, my personal Web site, and on my local network. After several years, the hardware was due for a rewire and redesign of the topology, moving from a bus to a hub and spoke architecture for better reliability and troubleshooting. This blog will outline that journey, and document the steps in case anybody else has any interest in recreating what I have done.  Although the station has been running for several years and I’ve had a Web site to publish the data, this is my first blog post about it.