Monday, December 29, 2014

AcuRite Weather Station, Raspberry Pi, Refining the readings Part 7

The previous part of this project is here <link>

Yes, another post on this device.  Even with this one, I'm not done; there will be others since I want to sample the RF from the sensor at some point and also bring up a separate little computer for just the weather station.  But I was extremely lucky and one of my readers double checked my work and found a couple of mistakes.

Thanks go to Heath Paddock <link>; he double checked the wind speed and direction and found mistakes, then gave me code to correct my mistakes.  Thank you Heath.  Due to a couple of factors completely within my control I misread the wind direction conversion.  He noticed it when he was testing the device and dropped me a line.  Then he double checked the wind speed and noticed a mistake there as well.

I was getting the bits correctly, but the conversion was off; let's look at the wind direction first.  The correct table for this sensor to convert from a number to direction looks like this:

// Array to translate the integer direction provided to text
char *Direction[] = {
    "NW",  // 0
    "WSW", // 1
    "WNW", // 2
    "W",   // 3
    "NNW", // 4
    "SW",  // 5
    "N",   // 6
    "SSW", // 7
    "ENE", // 8
    "SE",  // 9
    "E",   // 10
    "ESE", // 11
    "NE",  // 12
    "SSE", // 13
    "NNE", // 14
    "S"  };

Every single value is different; when I mess up, I do it in style.  When he sent me the code, I climbed up on the roof and brought down the station to check and see what is happening.  Yep, North was a six coming out of the USB port in report R1.  I went through each of the other directions and they matched his numbers exactly, then I looked at my console and it was wrong.  That just didn't make sense at all, so like all good computer users, I reset the darn thing.  It was still wrong.  I finally unplugged the console from the USB port on the Pi, pulled the batteries out of the console, and just to be complete, pulled the batteries out of the weather head.  This is a sure sign of desperation, when you do something that you know won't help just because you can't think of anything else.

But that did it.  A value of six (the pointer on the weather station was taped in place by now) corresponded to a N reading on the console.  I have no explanation for what was going on, but it works fine now.  No, I'm not going to try and recreate the situation.  I'm quite happy with the way it works and will double check the readings each time I have to change batteries in either the console or the weather head.

At any rate, the wind direction seems to be working really well now.  Next is the wind speed; Heath noticed an odd reading and asked me about it.  I had seen the reading the day before I left for Christmas, so I knew what he was talking about, but I didn't have time to look into it.  He took the time to examine the data he was receiving and found the solution.  The wind speed sensor is granular to .5 MPH; yes MPH, not KPH, and is reported back doubled.  The console does the usual 8 bit math and puts up a reading that is slightly off and loses the .5 granularity.  It also does some degree of smoothing and only reports the speed at intervals so you have to be somewhat patient to see what's going on.  Here's the code I'm currently using:

int getWindSpeed(char *data){
    int leftSide = (data[3] & 0x1f) << 3;
    int rightSide = (data[4] & 0x70) >> 4;
    float speed = (leftSide | rightSide) / 2.0;

Notice that I'm using a float to preserve the .5 granularity?  I did that to get the most out of my sensor and because it looks cool on my web display.  It won't match the console exactly, but that isn't really my goal.

There will probably be something else some clever person turns up that I missed or interpreted wrong, but that's part and parcel of hacking into a device with little or no information up front.  The point is that multiple people have participated in this project over many miles of separation, and we all get to use it.  I'll have the code updated in Github in an hour or so as well. <GitHub link>

Now I have to climb back up on the roof and put it in place.  There's a storm coming and I don't want to miss it.

The next part to this series is here <link>


  1. Thanks so much for your posts on this. I just received one as a gift and was hoping someone had a RPi solution that allowed me to upload date to the WUnderground site.
    BTW, I don't think the chips in the base station were obscured -- I think that's the cheap way to package them instead of using discrete packages.

    1. Regarding the chip, when I took the picture I had a mess of wires running across the top of it. I was just too lazy to take another picture.

      I haven't looked into sending it to weather underground. Maybe later in the year I'll get into that, but for now my set of gauges is working just fine. It would be fun to set up a fancy weather station though.

  2. Do you have all of the code in one place to parse the byte array?

  3. Yes, sort of. By that I mean that github has all the latest code, but I didn't parse all the data that may be available in the array. There's still some bits in there to conquer, but I got out all I want for now except the battery level. I know that's in there somewhere.

    1. Do you have a link to the github repo? I don't see a link in the article.

    2. Well, I'm embarrassed. I planned on coming back and adding the link after I put the code in place, and forgot.

      It's up there now, down near the bottom.


  4. I finally got the code to compile but when I run it I get the following errors:

    "[ 0.000000] [000024a0] libusbx: error [op_clear_halt] clear_halt failed error -1 errno 16

    ./weatherstation: symbol lookup error: ./weatherstation: undefined symbol: libusb_strerror

    Any ideas what I' doing incorrectly?


    1. I commented out line 357 "err = libusb_clear_halt(weatherStation.handle, 0x81);" and line 438 and now it is running.

      Now I have some questions about the output.

      All of the times are 10 digits long. How do I see the correct time?
      On my display the WS & T are integers.
      What is the rainCounter? On my display it shows as xx.yy inches.


    2. Yep, you fell into the trap of having the wrong version of libusb. Back in part 2 I discussed this and the comments in the top fo the c file talk about it as well. This can be a bit tricky to resolve, but the commaand 'ldd' is your friend.

      Wind Speed is described in this piece and an earlier part also. It's measured to .5 MPH, so you should be able to get it. Temperature similarly.

      Rain counter is described in an earlier part as well. It's an accumulator that bumps each time .01 inch of water goes through it. So, to to use it, you have to keep track of the count from an earlier time and compare it. I haven't done anything with it yet because I haven't figured out what I want to do. Do I want daily, highest day, weekly, monthly, last hour? Too many decisions.

      The time is in unix seconds from 1970 and can be converted with about a jillion routines out there depending on what you want to do. This piece of code is meant to feed something else, so keeping seconds so they can be manipulated seemed the way to go. I keep it for each sensor so you can tell if one of the sensors gets stuck or dies. Back in part 3 I gave python code to print this data it looked like this:

      print "On", time.strftime("%A, %B, %d at %H:%M:%S",time.localtime(float(data["windSpeed"]["t"]))),

      I spent a lot of time describing what I did in the various parts as I brought this device up, go poke around.

    3. Yesterday I was getting errors so I had to UNCOMMENT those lines & it worked. Now tonight I am getting the errors again so I RECOMMENTED those lines & it works again.

    4. There's a shell variable LD_LIBRARY_PATH that controls where the runtime-loadable libraries are looked for. This sounds like what causing you grief. Check to see if you have the variable set to anything and you can probably figure out why the symptoms are changing.

      just 'echo $LD_LIBRARY_PATH" to see it.

      To see which library the executable is trying to pull in, 'ldd and then look at the output. It should point to /usr/local

      Here's what mine looks like:
      pi@deserthome:~/src/house$ ldd getweather
      /usr/lib/arm-linux-gnueabihf/ (0xb6f0e000) => /usr/local/lib/ (0xb6ef3000) => /lib/arm-linux-gnueabihf/ (0xb6db9000) => /lib/arm-linux-gnueabihf/ (0xb6da4000) => /lib/arm-linux-gnueabihf/ (0xb6d95000) => /lib/arm-linux-gnueabihf/ (0xb6d76000)
      /lib/ (0xb6f1b000) => /lib/arm-linux-gnueabihf/ (0xb6d4e000)

      pi@deserthome:~/src/house$ echo $LD_LIBRARY_PATH

      It might be a good idea for me to put together instructions on this and add it to the comments in the code. You're the second person that had to mess around with it, so I guess it isn't common knowledge.

    5. A cheat way to check if indeed it's the ol' Linux not using the right lib issue; just run a "export LD_LIBRARY_PATH=/usr/local/lib" and rerun the binary to see if that fixes the issue. If it does, just look for a solution to perm fix it.

  5. Just FYI, looks like weewx has support for this acurite. Works great on my Acurite 2032C (in mode 4 of course!) on ubuntu.
    Lots of technical info (with a credit to this blogs author) in the driver header:

    1. Looks like he might have located the battery level. I'll have to look at that more closely.