Weather station for Blackbox

Started by zoneblue, May 21, 2016, 12:58:08 AM

Previous topic - Next topic

zoneblue

OK so we had an awful run of weather, and what better reason to work on the weather station.

I had previously scored an older metereological grade tipping bucket rain gauge off trademe. Take an arduino nano, add a ethernet module, a barometric module, an outdoor temp sensor and you have everything you need, right?

AVR floats are pretty awful, so the temps are x16, and the barometer is hPa offset from 1000hPa. Rain is just tips, and blackbox can convert those later.

That ENC ethernet module runs pretty hot and draws 0.4W. The nano also draws around that, so going to pro mini for the production board makes sense.  And for the networking, probably RS485.

Had hours of fun with the laptop at the kitchen sink, calibrating the rain bucket. The mrs thought i was right mad.


#include <OneWire.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <EtherCard.h>

//ethernet stuff
static byte myip[] = { 10,1,1,10 };// ethernet interface ip address
static byte gwip[] = { 10,1,1,1 }; // gateway ip address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
byte Ethernet::buffer[500]; // tcp-ip send and receive buffer
BufferFiller bfill;

//other lib instantiations
OneWire  ds(4); //D4
Adafruit_BMP085 bmp;

//functions
int dallas(byte start);
int ringfilter(int val, int *total, int *ring);
static word homePage();

//misc globals
unsigned long lastmillis= 0;
unsigned long thismillis= 0;
byte      ringindex= 0;
const int ringsize= 16;       //how many readings to moving average
const int altitude= 459;    //meters asl.

volatile unsigned long raintipcount= 0;
volatile unsigned long rainlaststamp= 0;
volatile unsigned long rainlastdur= 0;
int rainled= 0;

//itemp
int itemp_ring[ringsize];
int itemp_total= 0;
int itemp= 0;

//otemp
int otemp_ring[ringsize];
int otemp_total= 0;
int otemp= 0;

//baro
int baro_ring[ringsize];
int baro_total= 0;
int baro= 0;


void setup() {
  //rain tip debug led/buzzer
  pinMode(5, OUTPUT);
  Serial.begin(9600);
   
  //set up rain tip interupt
  pinMode(2, INPUT); //D2 is INT0
  digitalWrite(2 ,HIGH);  //turn on the internal Pull Up Resistor
  attachInterrupt(0, rain_tip_interupt, FALLING);
  interrupts();
 
  //init bmp085 and DS18B20
  bmp.begin();
  dallas(1); //initilisation call

  //init ethernet
  if (ether.begin(sizeof Ethernet::buffer, mymac) == 0) Serial.println( "Nano failed to reach the ethernet controller");
  ether.staticSetup(myip, gwip); 
}

void loop() {
 
//rain debugging info, buzzer attached to D5
  long diff= millis()-rainlaststamp;
  if (!rainled and diff<5) {
      digitalWrite(5 ,HIGH);
      Serial.print(raintipcount);
      Serial.print(" - ");
      Serial.println(rainlaststamp);
      rainled= 1;
  }
  else if (rainled and diff>10) {
      digitalWrite(5 ,LOW);
      rainled= 0;
  }
 
  // wait for an incoming TCP packet, ignore its contents, and serve our page
  if (ether.packetLoop(ether.packetReceive())) ether.httpServerReply(homePage());
 
  //beyond this point its one second sample rate
  thismillis= millis();
  if ((thismillis-lastmillis) < (unsigned long)1000) return;
  lastmillis= thismillis; 
   
  //bmp085
  itemp=  ringfilter(bmp.readTemperature()*16, &itemp_total, itemp_ring);
  int b= bmp.readSealevelPressure(altitude)- 100000;    //bmp returns long pascals eg 101325, so well just store the offset from 1000hPa, thus 1325
  baro=  ringfilter(b, &baro_total, baro_ring);
 
  //ds18B20
  otemp=  ringfilter(dallas(0), &otemp_total, otemp_ring); //comes premultiplied by 16
 
  //ring filter increment
  ringindex=  (ringindex + 1) % ringsize;

  //all done
}


static word homePage() {
  bfill= ether.tcpOffset();
  bfill.emit_p(PSTR(
    "HTTP/1.0 200 OK\r\n"
    "Content-Type: text/plain\r\n"
    "Pragma: no-cache\r\n"
    "\r\n"
    "itemp:$D\n"
    "otemp:$D\n"
    "baro:$D\n"
    "raintips:$D\n"
    ),
    itemp,otemp,baro,raintipcount
  );
  return bfill.position();
}


// RAIN GAUGE INTERRUPT
// there seems to be very little bounce from this actual reed switch
// if there is any it will come in two bursts per tip, leading and trailing
// but the fastest it can cycle from tip to tip is approx 300ms (funnel flooded), and the fastest expected real world interval is about one per second (20mm rain /hr)
// the tip rate seems to be about 1/3 mm of rain per tip
void rain_tip_interupt() {
  long diff= millis()-rainlaststamp;
  if (diff>100) { //debounce period (ms)
      raintipcount++;
      rainlastdur= diff;
      rainlaststamp= millis();
   }
}

//circular buffer to effect a 16s moving average
//readings get inserted in the index position, and overwriting the last in reading
int ringfilter(int val, int *total, int *ring) {
  *total-= ring[ringindex];
  *total+= val; 
  ring[ringindex]= val;
  return (*total/ringsize);
}

//a clever async DS18B20 implementation from www.scargill.net/reading-dallas-ds18b20-chips-quickly/
int dallas(byte start){
  byte i;
  byte data[2];
  int16_t result;
  do {
    ds.reset();
    ds.write(0xCC);
    ds.write(0xBE);
    for (i=0; i<2;i++) data[i]= ds.read();
    result=(data[1]<<8) | data[0];
    ds.reset();
    ds.write(0xCC);
    ds.write(0x44,1);   
    if (result<600) break; else delay(800);
    if (start) delay(1000);
  }
  while (start--);
  return result;
}
6x300W CSUN, ground mount, CL150Lite, 2V/400AhToyo AGM,  Outback VFX3024E, Steca Solarix PL1100
http://www.zoneblue.org/cms/page.php?view=off-grid-solar

ClassicCrazy

Nice job .
I recently bought  a LaCrosse weather station for 50 dollars from factory outlet. Thought it was worth it just for the sensors and rain gauge , let alone it works all on it's own.  Runs on batteries for a long time and is wireless to the base unit . That has a wireless to usb ouput  which you can plug  into a raspberry pi or other linux device and run Weewx program to make a webpage for it.
I see they went up in price since I bought mine.
http://www.lacrossetechnologyoutlet.com/featured-products/c86234-professional-weather-station-reconditioned

Larry
system 1
Classic 150 , 5s3p  Kyocera 135watt , 12s Soneil 2v 540amp lead crystal for 24v pack , Outback 3524 inverter
system 2
 5s 135w Kyocero , 3s3p 270w Kyocera  to Classic 150 ,   8s Kyocera 225w to Hawkes Bay Jakiper 48v 15kwh LiFePO4 , Outback VFX 3648 inverter
system 3
KID / Brat portable

dgd

Nice project  ;)
The nano replacement, the pro mini is nice as it is lower power without the USB port hardware and physically smaller too. The ENC ethernet also real cheap but I gave up as they get unreliable, of the 4 I had 2 are now dead. The Wiznet 5100 ethernet nano card with micro SD slot seems to be a lot more reliable but is usd20.
How are you meausring the power needed by these cards?
I see there is now a mini version of the 3300 wifi ethernet controller for nano/pro mini and the mini mega 2560, I'm using the usb portless mega, 3rd below, inside a Classic SL

dgd

http://www.ebay.com/itm/NANO-W5100-Ethernet-Shield-Network-Expansion-Board-for-Arduino-Nano-V3-0-/321974452312?hash=item4af72c4058:g:nsgAAOSwZkJURi1m
http://www.ebay.com/itm/162072364415?_trksid=p2060353.m1438.l2649&ssPageName=STRK%3AMEBIDX%3AIT
http://www.ebay.com/itm/221502571388?_trksid=p2060353.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT
Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

zoneblue

CC that wx station indeed a steal, the rain gauge is a lot bigger than most of the ones those units tend to have. 6" seems to be the standard for serious applications, measured mine at 164mm. If it wasnt for the horendous overseas shipping id get one to play with. However for my purposes (control freak) hand picking the sensors i need , and being able to custom present the data in blackbox does lend toward the arduino approach quite well.

Dgd, Given how little it does, 0.4W seems a lot for the nano. As for the ethernet, well that seems to be par for the course, having previously measured several hubs and switches clocking in at 0.6W per port. I measured the nano and ENC figures using your bog standard usb power monitor. Yes, i heard thoses ENC things suck, but its what i had laying around to test the rain bucket. If the distances from the bucket to the nano and nano to blackbox were more favorable i think id just use usb to serial. However its like 2m, then 15m. Without adding a bunch of radios (trying to keep RF down) i need to be mindful of surges and lightning etc, capacitance on the bucket line etc etc. Thus the lowest power atmel i can find, just insde the building, and rs485 to usb into the cubie was what i was thinking. Ethernet is easy for me to get up and running, but its inelegant for transmitting such trivial amounts of data.  Thanks for those links, ill order some for the parts box.
6x300W CSUN, ground mount, CL150Lite, 2V/400AhToyo AGM,  Outback VFX3024E, Steca Solarix PL1100
http://www.zoneblue.org/cms/page.php?view=off-grid-solar

zoneblue

Everything you ever wanted to know about AVR interupts: http://gammon.com.au/interrupts

Optimised ISR code:


volatile unsigned long stamp= 0;
volatile unsigned long lastrainstamp= 0;
volatile byte newtip= 0;
unsigned long tiplog[64];
unsigned int tiplogindex= 0;
unsigned long lastloopstamp= 0;
unsigned long tipcount= 0;

void setup() {
  Serial.begin(9600);
  pinMode(2,INPUT);
  attachInterrupt(0,raintip,RISING);
  interrupts();
}

//rain bucket executes this each tip with 2uS hardware debounce plus 200ms software for luck
//tip pulse absolute max interval is about 300ms
//tip pulse is about 80mS wide
//all this ISR does is flag to loop that theres a newtip
//everything youll ever need to know about interupts  http://gammon.com.au/interrupts
void raintip(){
  if ((stamp-lastrainstamp)>250) newtip= 1;
}

void loop() {
 
  //single call to millis
  stamp= millis();

  //push the new tip on to the stack
  if (newtip) {
    tipcount++;
    tiplog[tiplogindex++]= stamp;
    lastrainstamp= stamp;
    newtip= 0;
  }

  //dump stack on request via 60s "ethernet" lookups
  if ((stamp-lastloopstamp) > 60000) {
    lastloopstamp= stamp;
    int i; int d;   
    Serial.println(stamp/100);
   
    if (tiplogindex) {
      for (i=0;i<tiplogindex; i++) {
        d= (stamp-tiplog[i])/1;
        //if (d>999) continue; //ignore anything older than 100 seconds
        Serial.print("  ");
        Serial.print(i+1);
        Serial.print(" - ");
        Serial.println(d);
      }
      tiplogindex= 0;
    }
  }

  //beyond this point its one second sample rate
  //if ((stamp-lastloopstamp) < (unsigned long)1000) return;
  //lastloopstamp= stamp; 
  //sample the other sensors here

  //loop done
}

6x300W CSUN, ground mount, CL150Lite, 2V/400AhToyo AGM,  Outback VFX3024E, Steca Solarix PL1100
http://www.zoneblue.org/cms/page.php?view=off-grid-solar

danda

happy weewx user here too.   my two most used bookmarks are my blackboxproject and weewx installs!   :)

ArchOlson

#6
Hi....i am a new user here. I thought it was worth it just for the sensors and rain gauge , let alone it works all on it's own.  Runs on batteries for a long time and is wireless to the base unit . That has a wireless to usb ouput  which you can plug  into a raspberry pi or other linux device and run Weewx program to make a webpage for it.

cheap pcb assembly

ClassicCrazy

Just thought I would mention that running the weewx on the raspberry pi - it kept crashing every day.  I put in a new high quality Samsung EVO sd card and hasn't crashed since. 

Larry
system 1
Classic 150 , 5s3p  Kyocera 135watt , 12s Soneil 2v 540amp lead crystal for 24v pack , Outback 3524 inverter
system 2
 5s 135w Kyocero , 3s3p 270w Kyocera  to Classic 150 ,   8s Kyocera 225w to Hawkes Bay Jakiper 48v 15kwh LiFePO4 , Outback VFX 3648 inverter
system 3
KID / Brat portable