Enclosure

In my original version of my weather station, the enclosure sat inside my greenhouse and was protected from the elements as well as being powered by electricity coming from the house.  I’ve since gotten rid of the greenhouse and attempted to use a rubbermaid enclosure and purchased some solar power equipment to make it wireless.  I had issues with the battery not lasting long in the winter time due to the reduced sunlight as well as the rubbermaid could not handle the elements.  This has led to me not having my weather station for several years now.  With a renewed interest, I am attempting a new enclosure and adding battery monitoring. I’ll be listing the parts that I’m using as well as linking to where you can purchase them.

Hardware:

Power Equipment:

Electronics & Sensors

  • Raspberry Pi Zero W
  • MCP 3008 ADC – could use something smaller, I just had this so I used it
  • BMP180 Pressure Sensor – this has been discontinued, but linking to a newer version that should work
  • MOD-1016 Lightning Sensor – I really want this sensor to work correctly, but I’m still ironing out the details

Mounting Hardware:

As you can see above, the cable gland is placed on one side of the junction box, the solar panel requires a hole in the top to run the wire, but I use velcro to attach. (Have not placed the velcro on the lid of the junction box yet)  The electronics are mounted to a piece of the clear acrylic sheet using the nylon standoffs arranged in a way that everything fits nicely.  The battery sits underneath the acrylic sheet.

There are some wires that come from the different hardware pieces that I wanted to call out now and will discuss more in the next post regarding the perma-proto board and the sensor communication with the Raspberry Pi.  As you can see there is a cat 5 cable that runs from the cable gland to the perma-proto board.  This is the communication from the mast.  There are also two wires that come from the power boost to the perma-proto board.  One is from the low battery indicator pin, and the other is the ground pin.

Solar Charging circuit:

Just a quick explanation of how this is wired.

  1. Solar panel plugs into the USB/DC/Solar Li/LiPO charger as well as the battery into the “BATT” terminal
  2. Using a 2 female JST cable from “LOAD” on the Li/LIPO charger to the black JST connector on the Powerboost 1000 Basic
  3. USB A to USB micro from the Powerboost 1000 to the raspberry pi.  I used a small 6″ cable.

 

 

With this new enclosure, I have created a new sensor board that brings all my sensors together in one location as well as setting up 10 pins on the board for bringing together like wires for communication back to the Pi.  Due to the need of the mast needing 5V, I am using 2 separate voltages on the opposite rails.  The rail on the left is 5v and the one on the right is 3.3v

There are 3 sections that I’m going to cover:

  • Battery Circuit – for monitoring of the battery charge
  • Sensors – The wiring of the sensors within the enclosure as well as the communication back from the mast
  • Sensor board to RPi communication

Battery Circuit Wiring:

  • GND from Powerboost to GND on board
  • Low Battery indicator from Power boost to voltage divider on board.  Resistors: R1 = 2.2kΩ, R2 = 5.1kΩ (If you’re not familiar with how this works, LBI goes to rail containing one side of R1, Other side of R1 goes to rail that contains one side of R2 as well as read wire.  Other side of R2 goes to ground.  This is used to cut down voltages.  The powerboost is outputting 5V, but the MCP30008 ADC can only handle 3.3v which is why the divider circuit)
  • Voltage divider read wire to CH0 on MCP3008
  • MCP3008 wiring
    • Vdd & Vref to pin 10 on board (3.3V power rail)
    • AGND & DGND to pin 9 on board (3.3v ground rail)
    • CLK to pin 5 on board
    • Dout to pin 6 on board
    • Din to pin 7 on board
    • CS to pin 8 on board

Sensor Wiring

  • BMP180
    • Vin to pin 1 on board (5V power rail)
    • GND to pin 0 on board (5V ground rail)
    • SCL to pin 3 on board
    • SDA to pin 2 on board
  • MOD-1016
    • Vcc to pin 1 on board (5V power rail)
    • IRQ to pin 4 on board (interrupt pin on RPi)
    • SCL to pin 3 on board
    • SDA/MOSI to pin 2 on board
    • GND to pin 0 on board (5V ground rail)
  • Mast
    • Blue-white to pin 0 on board (5V ground rail)
    • Blue to pin 1 on board (5V power rail)
    • Green-white to pin 3 on board
    • Green to pin 2 on board

Board pinout to Rasberry Pi

  • Pin 0 (5V GND) to pin 7 on Pi
  • Pin 1 (5V Power) to pin 4 on Pi
  • Pin 2 (SDA) to pin 3 on Pi
  • Pin 3 (SCL) to pin 5 on Pi
  • Pin4 (Int) to pin 11 on Pi (GPIO 17)
  • Pin 5 (SPI CLK) to pin 12 on Pi (GPIO 18)
  • Pin 6 (SPI OUT) to pin 16 on Pi (GPIO 23)
  • Pin 7 (SPI IN) to pin 18 on Pi (GPIO 24)
  • Pin 8 (SPI SC) to pin 22 on Pi (GPIO 25)
  • Pin 9 (3V GND) to pin 20 on Pi
  • Pin 10 (3V Power) to pin 17 on Pi

 

it will take a while before I post the Python code on the Pi.  I am still testing/working on the code for the battery monitoring.  Once I’m done, I’ll post it all here as well as on Github.

Anemometer Reading

It was too late last night when I finished the post about building the anemometer that I didn’t want to get into the code to read the wind speed. As I said before, basically what I do is I count the number of “triggers” within a 10 second period and then feed that into the formula that came from testing it with our car.

Here is the code I use for Raspberry Pi…I run this every 5 minutes (with the rest of my measurements) to get the wind speed at that time.

# calculate windspeed
# set up the GPIO to be an input and activate the internal resistor to pull down the pin to low
GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

# This is the interrupt function. It opens a file, pulls the number from the file and adds one to it, then rewrites it to the file.
def wind_callback(channel):
windfile = open("/home/pi/wind_count.txt")
windtext = windfile.readline()
windfile.close()

wind_count = int(windtext)
wind_count += 1
windfile = open("/home/pi/wind_count.txt", "w")

windfile.write(str(wind_count))
windfile.close()

# Here is the interrupt setup. We are setting it up on pin 22, looking for it to rise, calling the function "wind_callback" when it is triggered and
# debouncing it by 100ms
GPIO.add_event_detect(22, GPIO.RISING, callback=wind_callback, bouncetime=100)
# Before we start the count, we open the file and set the number to 0
windfile_clear = open("/home/pi/wind_count.txt", "w")
wind_count_clear = 0
windfile_clear.write(str(wind_count_clear))
windfile_clear.close()

# now we sleep for 10 seconds to get the readings
time.sleep(10)

# After sleeping, we open the file and read the number
wind_file = open("/home/pi/wind_count.txt")
wind_count = wind_file.readline()
wind_file.close()

# in order to use it in some math, we need to convert it to an int
wind_count_comp = int(wind_count)

# here is the formula created from testing. Basically it is .0023427x^2 + .46244x
windspeed_a = wind_count_comp * wind_count_comp * .0023427
windspeed_b = wind_count_comp * .46244
windspeed = windspeed_a + windspeed_b

# round it off to 1 decimal.
windspeed = round(windspeed, 1)

I am actually in the middle of a redesign on my weather station due to the Raspberry Pi not being the best at interrupts for the rain gauge. For the one at my father-in-laws farm, I will be using an Adafruit trinket to capture all the data from the anemometer, rain gauge, and wind direction sensor before relaying it to the Pi. This type of sensing is better for a micro controller than it is for a Linux computer such as the Pi. For my home weather station, I’ll be using a Arduino Pro Mini as I have a lot more sensors on my mast. The Trinket code is a little more difficult due to the ATTiny85 that runs it. I’ll post info on how to connect it to a Raspberry Pi later.

Here is the code for the same principal as above on a trinket. The big difference here is that this runs constantly. Every 10 seconds I have a wind speed reading, although I only pull it every 5 minutes.


#include avr/interrupt.h

// setup cbi & sbi for interrupts
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// Set up variables used
volatile int windSpeed = 0; // keep track of interrupts from anemometer
volatile int windSpeedSend = 0; // used to send 10 second interrupt value to pi
long debouncing_time_wind = 100; //Debouncing Time in Milliseconds for anemometer
volatile unsigned long last_micros_wind; // micros since last anemometer interrupt
volatile int val2 = 0; // pin 4 value at interrupt

void setup()
{
// Setup Pins for interrupts
pinMode(4,INPUT);

sbi(GIMSK,PCIE); // Turn on Pin Change interrupt
sbi(PCMSK,PCINT4); // Which pins are affected by the interrupt. Turn on Pin 2

}

void loop()
{

// anemometer counts interrupts for 10 second interval. This is sent to master for calculation
windSpeed = 0;
tws_delay(10000);
windSpeedSend = windSpeed;

}

// debounce anemometer. make sure new reading is greater than old reading + debounce wind micros
void debounceWindSpeed() {
if((long)(micros() - last_micros_wind) >= debouncing_time_wind * 1000) {
windSpeedFunc();
last_micros_wind = micros();
}
}

// function to increment anemometer count
void windSpeedFunc() {
windSpeed = windSpeed + 1;
}

// interrupt service routine. What to do when an interrupt occurs as all pin change interrupts
// on ATTiny85 trigger PCINT0 vector.
ISR(PCINT0_vect) {
// get value of pin 4 @ interrupt
val2 = digitalRead(4);

// if pin 4 is HIGH (caused the interrupt), proceed with wind speed (anemomether) increment function
if (val2 == HIGH) {
debounceWindSpeed();
}

}

Gemma Neopixel Jewel Earrings

I like projects! I NEED projects!

I’ve wanted to do something in the wearables category for a while, but couldn’t think of something. I was out at the mall one evening with my beautiful wife looking through some of the department stores. I decided to call my sister-in-law (for a reason I can’t remember right now) and the idea popped into my head that I should make her some of the neopixel earrings I’ve seen in the Adafruit Learning System. So I told her I was going to make them and when I got home I went onto Adafruit’s site to purchase what I would need.

The original plans for the earrings include neopixel rings, but I noticed that they had just released a new neopixel “platform” called the “Jewel”. This has 7 neopixels arranged in a circle with 1 more in the middle. I thought these would be more fun to have than the rings, so they were added instead. The only other parts you need are a tiny lipo battery and of course an Adafruit Gemma. (Don’t forget the charger for the batteries as well if you don’t have one)

I feel bad that I didn’t take pictures of the entire process, but it’s really, really simple. The first thing I did was shorten the battery leads. There’s no need for all that length of wire. After that, I wired the Jewel to the Gemma with silicon wire with enough room to slide the battery between the 2. (They are back to back.) 3vo on the Gemma to +5V on the Jewel, Ground to Ground & D0 on the Gemma to input on the Jewel.

To keep them together, I did a no-no and used hot glue. You slide the battery in position and make sure it all will align well (I aligned one of the mounting holes on the Jewel to D1 on the Gemma). Slightly lift the battery on one side so you have room to place the hot glue on the back side of the Gemma, then press the battery down into place. Repeat the same process with the Jewel on the battery making sure it’s aligned.

For the code, I took what was given on the Adafruit tutorial for the ring earrings and modified it to only sparkle and to sparkle specifically in teal (my sister-in-law’s favorite color).

// Low power NeoPixel earrings example. Makes a nice blinky display
// with just a few LEDs on at any time…uses MUCH less juice than
// rainbow display!

#include

#define PIN 0

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(7, PIN);

uint8_t mode = 0, // Current animation effect
offset = 0; // Position of spinny eyes
uint32_t color = 0xffae00; // Start red
uint32_t prevTime;

void setup() {
pixels.begin();
pixels.setBrightness(60); // 1/3 brightness
prevTime = millis();
}

void loop() {
uint8_t i;
uint32_t t;

switch(mode) {

case 0: // Random sparks – just one LED on at a time!
i = random(7);
pixels.setPixelColor(i, pixels.Color(0,128,128));
pixels.show();
delay(100);
pixels.setPixelColor(i, 0);
break;

}

}

Add some earring pieces from Walmart and they should sparkle like these:

Youtube Video

I2C sensors using Adafruit Trinket

I finally completed migrating the weather sensors for the weather station that is at my father-in-law’s farm. I had issues with the rain gauge not working too well with the pi directly, so I decided to use an Adafruit Trinket to capture the values of the sensors and send them to the pi for tracking. The communication between the two is accomplished using I2C.

image

Here’s the completed mast with sensors attached. (This is actually a pic of it at my house for testing) What you’ll need for this is 1 of each of an anemometer, wind vane & rain gauge. It works with the sensors I built, but I’m sure you could incorporate it to use any sensors you have as well.

I’ve used PVC to build all my sensors as it’s easy to connect together. In my anemometer & wind vane posts I have used certain PVC pieces to allow for connection to my mast. For the rain gauge, it’s a little different. I used a piece of cedar fence board to secure the sensor, then some u-bolts to attach the board to a 1 inch pvc pipe, plugged one end and drilled a hole for the wire to run through.

For the rest of the top part of the mast I use a 1″ T-connector at the top with about 8 or so inches of 1″ pipe to connect the anemometer & wind vane. I run the wires down through the pipes. I then use a small piece of 1 inch pipe (about 3 or so inches) to connect another T-connector for the anemometer. I then use another portion of 3 or so inches of 1″ pvc pipe to connect to the lower portion. (Sorry, but I don’t have any pics of this…)

The lower mast is where the trinket comes in…I connect all the sensor wires to a single cat 5 cable to connect to trinket and then another wire for the I2C communication. The idea is to house the trinket in some 3/4″ pipe that is waterproofed and have it sit inside some 1 1/2″ pipe. (You can see this bulge in the pic above) I use some connectors to move from 1″ to 1 1/2″ pipe. Then a portion of 1 1/2″ pipe (I think it’s 12 inches long) and then connect it back to another 1″ piece of pipe to mount it.

Before wiring up your trinket, make sure you upload the code to it. Here is what I use which tracks the sensors and sends the data via I2C:

#include avr/interrupt.h
#include TinyWireS.h

// setup cbi & sbi for interrupts
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

//Define address of device
#define I2C_SLAVE_ADDRESS 0x04

// Set up registers to hold data to send
volatile uint8_t reg[] =
{

0xDE,
0xAD,
0xBE,
0xEF,
0xEE,
0xED
};

// Set up variables used

volatile byte reg_position; // keep track of reg position sent from master
volatile int rainGauge = 0; // keep track of interrupts from rain gauge
volatile int windSpeed = 0; // keep track of interrupts from anemometer
volatile int windDirection = 0; // keep track of value of wind direction sensor
volatile int windSpeedSend = 0; // used to send 10 second interrupt value to pi
long debouncing_time_rain = 300; //Debouncing Time in Milliseconds for rain gauge
volatile unsigned long last_micros_rain; // micros since last rain gauge interrput
long debouncing_time_wind = 100; //Debouncing Time in Milliseconds for anemometer
volatile unsigned long last_micros_wind; // micros since last anemometer interrupt
volatile int val1 = 0; // pin 1 value at interrupt
volatile int val2 = 0; // pin 4 value at interrupt

// Function to send data when it is requested. Sends 2 register positions
// for each request
void onRequest()
{

// Load all values into registers. (even though only 2 will go to master)
reg[0] = lowByte(windDirection);
reg[1] = highByte(windDirection);
reg[2] = lowByte(windSpeedSend);
reg[3] = highByte(windSpeedSend);
reg[4] = lowByte(rainGauge);
reg[5] = highByte(rainGauge);

// send 2 reg positions to master
TinyWireS.send(reg[reg_position]);
reg_position++;

}
// Function to set which register positions you wish to receive
void receiveEvent(uint8_t howMany)
{
reg_position = TinyWireS.receive();

// if requested position is 7, reset rain gauge variable. Will be sent at midnight each day
if(reg_position == 7) {
rainGauge = 0;
}

}

// Setup for connection
void setup()
{
TinyWireS.begin(I2C_SLAVE_ADDRESS);
TinyWireS.onReceive(receiveEvent);
TinyWireS.onRequest(onRequest);
pinMode(1,INPUT);
pinMode(4,INPUT);

sbi(GIMSK,PCIE); // Turn on Pin Change interrupt
sbi(PCMSK,PCINT1); // Which pins are affected by the interrupt. Turn on Pin 1
sbi(PCMSK,PCINT4); // Which pins are affected by the interrupt. Turn on Pin 2
}

void loop()
{

// anemometer counts interrupts for 10 second interval. This is sent to master for calculation
windSpeed = 0;
tws_delay(10000);
windSpeedSend = windSpeed;

// read pin 3 analog value of wind direction sensor
windDirection = analogRead(3);

// Check for connection to be stopped.
TinyWireS_stop_check();
}

// debounce rain gauge. make sure new reading is greater than old reading + debounce rain micros
void debounceRainGauge() {
if((long)(micros() – last_micros_rain) >= debouncing_time_rain * 1000) {
rainGaugeFunc();
last_micros_rain = micros();
}
}

// debounce anemometer. make sure new reading is greater than old reading + debounce wind micros
void debounceWindSpeed() {
if((long)(micros() – last_micros_wind) >= debouncing_time_wind * 1000) {
windSpeedFunc();
last_micros_wind = micros();
}
}

// function to increment rain gauge count
void rainGaugeFunc() {
rainGauge = rainGauge + 1;
} // end of rainGauge

// function to increment anemometer count
void windSpeedFunc() {
windSpeed = windSpeed + 1;
} // end of rainGauge

// interrupt service routine. What to do when an interrupt occurs as all pin change interrupts
// on ATTiny85 trigger PCINT0 vector.
ISR(PCINT0_vect) {
// get value of pin 1 @ interrupt
val1 = digitalRead(1);
// get value of pin 4 @ interrupt
val2 = digitalRead(4);

// if pin 1 is HIGH (caused the interrupt), proceed with rain gauge increment functions
if (val1 == HIGH) {
debounceRainGauge();
}

// if pin 4 is HIGH (caused the interrupt), proceed with wind speed (anemomether) increment function
if (val2 == HIGH) {
debounceWindSpeed();
}

}

So, now to the wiring:
image

Here is the wiring diagram I drew out that shows how everything is connected. When connecting, make sure you use solder and shrink tube to protect the joints.

image

After all the wires are connected, drill a hole in a 3/4″ pvc plug and push the wire through that hole prior to connecting to the trinket. You may want to run it through a piece of 3/4″ pipe as well (about 8 or so inches).

All 3 sensors will need 1 wire connected to the +3v on the sensor. I managed to get all 3 of the cat 5 wires into the hole on the trinket. The read wires will need to go different pins. For the anemometer and rain gauge, you will need to connect a 10k resistor to ground to pull the pin to ground. The rain gauge read wire should go to pin 1 and the read side of the anemometer should go to pin 4. The read wire for the wind vane should go to pin 3. Connecting all the ground wires was fun. What I did was run 1 wire out of the trinket and connected all the ground wires to it and put shrink tube over all of them. (You can see it in the pics below.)

image

image

I didn’t take a lot of single step pics on this and I apologize. You can see the connections for the I2C wire as well in these pics. The last part is connecting the wires for the I2C communications. You’ll want to put the wire through hole in another 3/4″ pvc plug before you connect them to the trinket to allow for waterproofing. Connect the +v to the battery pin (I use 5 volts out of my raspberry pi to power, but you can power it any way you want. I used a 3 volt trinket for this setup). Ground to your ground wire, SDA to pin 0 and SCL to pin 2. Once this is done, slide it all into the 3/4″ pvc and plug the other side. It should look like this:

image

Place some hot glue on each plug where the wires go in to keep the water out, then shove this into the 1 1/2″ pvc pipe and then connect the rest of your mast.

This is really set up to communicate with a pi, but I’m pretty sure it would work with an Arduino as well. In the code you basically send the trinket a number and it will give you the response. Sending 0 will give you the wind direction reading, 2 will give you the wind speed reading and 4 will give you the rain gauge reading. Sending it 7 will cause the rain gauge count to reset. Here’s a quick bit of code you can use for the pi:


#!/usr/bin/python
# Import needed libraries
import smbus
import time

# Set I2C address of device you wish to access
DEV_ADDR = 0x04

bus = smbus.SMBus(1)

# Request values from device. Number is start register position.
while True:
print 'Testing for connection...'
while True:
try:
wind_dir_read = bus1.read_word_data(DEV_ADDR, 0)
wind_count = bus1.read_word_data(DEV_ADDR, 2)
rain_count = bus1.read_word_data(DEV_ADDR, 4)
break
except IOError:
print 'No connection...'
time.sleep(5)
#break
if wind_dir_read < 1030: break else: print 'Value too high.' time.sleep(5) # Use this to reset a variable: #d_val = bus.read_word_data(DEV_ADDR, 7)

It doesn't seem that wordpress knows how to deal with indents in it's code sections, so make sure you indent it properly. Sometimes the trinket can give you some funny business which I've handled via the error trapping above. If you keep this bit of code you shouldn't run into any problems.

When I finished building my weather station it was on a large full size breadboard. I didn’t like that it there was so much space on there that was just wasted and I had a half size sitting around that I thought would work well. Unfortunately, the ADC wouldn’t let everything else fit properly. I did some research and found that Microchip also produced a 2 channel ADC called the MCP3002. Since I was using only 2 channels on the MCP3008, I thought this would work nicely and I counted all the slots on the half size breadboard and it would fit perfectly! So I ordered a couple from Newark…

When they came in I had to test to make sure it was going to work, so I placed in the half size breadboard, wired up a TMP36 analog temp sensor, and connected the breadboard to my spare Pi. Well, come to find out, the driver I had didn’t work. Neither did the other one I found online nor the others I found. I was a bit depressed because I really wanted it to work.

My last hope laid on the Adafruit forums. (Love Adafruit by the way!) I was a bit worried as they don’t sell the MCP3002 and they have messages on there about only supporting their products. So, reluctantly I posted a question on the forum asking if the driver they provide for the MCP3008 would work for the MCP3002. At first their people informed me that it would work, but I told them I had tested it and it didn’t. In one of my responses I made sure that I mentioned that I had wired it as per the datasheet and added a link.

Come to find out, the reason their driver wouldn’t work is because the 3002 only wanted 4 bits sent to it for the request and the 3008 wanted 5. So, Rick (who I think works for Adafruit) helped with adapting that part of the driver. When I added his piece to the 3008 driver, it still didn’t work. I then took another look at the datasheet and found another difference in the 3008 vs the 3002. The 3002 only provided a 11 bit response vs the 12 that the 3008 provided. I then updated the code to account for that and voila! it worked like a charm.

After I got it working, I posted about having to make the other change. Rick then asked me to post the full driver so that it could be added to their python library. So yeah, that’s the story of writing my first driver…

Here it is by the way if you need it:

def readadc(adcnum, clockpin, mosipin, misopin, cspin):
if ((adcnum > 1) or (adcnum < 0)): return -1 GPIO.output(cspin, True) GPIO.output(clockpin, False) # start clock low GPIO.output(cspin, False) # bring CS low commandout = adcnum << 1; commandout |= 0x0D # start bit + single-ended bit + MSBF bit commandout <<= 4 # we only need to send 4 bits here for i in range(4): if (commandout & 0x80): GPIO.output(mosipin, True) else: GPIO.output(mosipin, False) commandout <<= 1 GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout = 0 # read in one null bit and 10 ADC bits for i in range(11): GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout <<= 1 if (GPIO.input(misopin)): adcout |= 0x1 GPIO.output(cspin, True) adcout /= 2 # first bit is 'null' so drop it return adcout # change these as desired - they're the pins connected from the # SPI port on the ADC to the Cobbler. There are 2 Chip Select pins. # one for each ADC SPICLK = 18 SPIMISO = 23 SPIMOSI = 24 SPICS = 25 # set up the SPI interface pins GPIO.setup(SPIMOSI, GPIO.OUT) GPIO.setup(SPIMISO, GPIO.IN) GPIO.setup(SPICLK, GPIO.OUT) GPIO.setup(SPICS, GPIO.OUT) Read the rest of this entry

Weather Station

20131128-093102.jpg

I know it’s been a while since I posted something, I guess it was just getting difficult to find time to post something after completing a sensor before bed. My most recent project has been building my own weather station. This sort of came from the greenhouse automation project. Once I was able to measure humidity, that was it; I wanted to measure everything else about the weather that I could.

In building this, I feel I learned a lot about some other aspects of the raspberry pi, coding and some other sensors (reed switches specifically). In some places, I kind of took the easy route and took something someone else made and re-wired it to work for me, (rain gauge & wind direction pointer) but this still involved a lot of innovation on the coding side to use it. I plan to write other posts detailing the building of the other sensors; just plan to space them out some as some of them are pretty involved. I think eventually I might make a wireless self-contained version (wifi, batteries, & solar power), but that’ll be a while 😉

Oh…..forgot to mention the first time I published it…..you can see the current weather at my house by clicking on the “Current Weather” page on my blog…

Today, I put the cover on the greenhouse to get ready for the winter. I know it’s a couple weeks early (as I don’t think we have the first frost here in Texas until around mid to late November. This year, I decided to use zip ties instead of rope to attach all the pieces and I think it worked a lot better. For those who haven’t seen it before here is my little greenhouse with all my citrus trees…

20131026-212217.jpg

I’ve recently came to the understanding that I probably don’t need my automatic watering system nearly as much in the winter time, so I’m not in a rush anymore to get it built. When I will need it though is next summer. Now the fact that I need it most when I don’t have the cover on the greenhouse means that I need to find a way to waterproof everything. I’ve been looking into waterproof boxes I can put the computer in and have some ideas, but one of the other things I’ll need are waterproof moisture/light sensors for the trees. I had a revelation the other day that I can probably use some PVC to accomplish this. When I was at Lowes picking up the zip ties for the greenhouse, I went to the the plumbing section and found my parts.

20131026-212352.jpg

So, here it is, the new and improved waterproof (mostly. You can’t dip the whole thing in and expect it to survive. I haven’t really tested it’s waterproofness yet, but I believe it is)

20131026-212226.jpg

What you’ll need (besides many of the parts from the previous sensor) are a 1 1/2″ plug & a 1 1/2″ cap. (These should fit into each other.) The plug has a flat end and the cap has a rounded end. At first I had a hard time finding something that would work. I had planned on using some 1″ pipe with caps on either end, but I just didn’t think that the cap would be the right shape. When I was about to give up, I went back through one more time and found these!!! I was pretty excited that I found this combo.

20131026-212233.jpg

The first step to building this new sensor is to drill some holes in the cap and plug. You’ll need to drill a 7/32″ hole in the middle of both the cap and the plug. The plug also needs 2 1/8″ holes drilled on either side of the middle hole for the moisture sensor wire. The middle hole of the plug is for the cat 5 cable and the middle hole in the cap is for the light sensor.

20131026-212241.jpg

Again like the previous sensor, you’ll need to use some 12 gauge wire (10″ of romex is what I use). Remove some of the insulation from both sides like before and put some solder (tin) the side that will go into the dirt. When this is complete you’ll need to make your wires look like the above picture. The way to do this is the put the wire through it’s hole and then press the end against the side of the plug and hold it there. While holding the inside, bend the outside. You’ll want the part of the wire that has the insulation removed to be above the end of the plug. (I think this is shown later).

20131026-212248.jpg

After you have the wires bent to the correct shape, you’ll need to “attach” the probes to the plug. Put them through the hole and then place some hot glue at around the probe where it meets the hole.

20131026-212255.jpg

Next, flip the plug over and put a good amount of glue in the plug to hold the wire in place. (You can see in this picture how I said to place the part of the wire with the insulation removed above the top of the plug.) Do this with both sides one side at a time.

20131026-212314.jpg

Now we go to the wiring part. Just like in the previous sensor, we’ll need a LDR and a 10 ohm resistor. Green to one side of the LDR, blue and one side of the 10 ohm resistor to the other side of the LDR, and green/white to the other side of the 10 ohm resistor. Solidify this connections with some solder and cover them with some shrink tube. (Make sure when you remove the insulation from the cat 5 cable that you have a good amount to work with.)

20131026-212321.jpg

The next step is really annoying. You need to place the LDR in the hole in the cap and secure it. Do do this, I pushed the LDR through the hole and used some hot glue to tack it down. (Wait for it to dry so you have some hold.) Once it’s try, turn it over and place a lot of hot glue into the cap. Let this dry, then fill in the holes around the LDR on the other side of the cap. (It took me 5 tries to get this right.

20131026-212332.jpg

Almost finished. Lets solder the brown wire to the black probe and the brown/white wire to the white probe. Should be pretty easy if you gave yourself enough wire and placed the top of the probe above the top of the plug. After you finished this you can carefully press the plug inside the cap. Once together, hot glue around where the cat 5 cable went enters the plug.

20131026-212359.jpg

20131026-212404.jpg

Finally, just as last time, place the rj45 jack on the end. I use the above pattern even though it doesn’t match the “standard” ethernet pattern. I’ve had this sensor going all day now and it seems to be working fine. I’d like to make another one to have two to test. I’ll need to do this fairly quickly as it’s getting close to when I need to take the system outside and actually work…

Halloween Costume

For those who do not know, I have recently became a fan of Doctor Who, specifically the 11th doctor. (I have only watched episodes of the 11th, so I really can’t say I’m a fan of the others yet) Because of this I have decided to have a Halloween costume this year and I’ll be doing my best impression of the Doctor….

Now one of the driving reasons behind this, besides the new fandom high, is that I can use pieces of the costume as everyday wear. I can wear the jacket, shirt & bow tie to work and the jeans elsewhere. I could probably wear the suspenders to work and church as well, but I’m not sure I’m really a suspenders type guy. (They were free so I had no qualms about getting expensive ones. That story will be below)

20131016-105630.jpg

For the jacket, I was able to find a used Harris tweed jacket on ebay for around $40. Now the pattern is not exact, but Hey! it’s the same material and way better than any of those $50 knockoffs they sell at the costume sites.

20131016-113132.jpg

The shirt was probably not necessary as I could have just worn a white or cream shirt that I already have. Now that I think about it, the stripes might be a little too much and I might make a decision to not wear the shirt depending on how I look once I try it all on. (Waiting for something to come in the mail…) Its not as though the shirt will be a lost cause though. I got it on sale for 40% off from JC Penny’s and I can add it to my weekly shirt rotation.

20131016-105647.jpg

Ah, the suspenders. A crucial part of the ensemble. I got these at the Men’s Wearhouse for FREE!!! Normally they would set you back $35. Now I know that Matt wears clips on his suspenders, but I these button ones will be close enough. The reason these were free was because I do a lot of shopping at the Men’s Wearhouse; as it is where I purchase a lot of the clothes I wear to work. For every $500 you spend, you get a $50 gift card. The one I used for this actually wasn’t because of my spend, but because I received terrible service one day and reported it to corporate and they like me as a customer so much that they gave it to me to make me happy. 🙂

20131016-105638.jpg

The bow tie…the most crucial part of the ensemble. Bow ties are cool and we actually have a bow tie day at work occasionally. (Usually on Thursdays) I found this one on eBay for about $7.50 with shipping. I really wanted a simple burgundy one and this fits the bill.

20131016-105654.jpg

As for the jeans, I just picked up some cheap black faded glory ones from Wal-Mart for $10. Nothing too exciting. They are relaxed fit instead of skinny jeans though.

The last piece is the boots. I didn’t buy any boots as I couldn’t see spending $40 on something that I wouldn’t normally wear. (The $40 is in reference to some I found on eBay that would probably fit the bill) So I’ll be wearing some black golf shoes…

(I didn’t forget the screwdriver, so don’t worry….)

Python Code

So, I finally got around to cleaning up the code a bit and commenting it in order to share it. First off, this is not in any way professional or “clean”. It is just me throwing some stuff down to get it to work. I am not really an OO guy; I think procedurally and so that’s how I code. I have borrowed pieces from others, specifically from Adafruit (the ADC reading code) and I do realize I could be using a lot of loops to run through things, but hey, I’m not worried about size, speed, or cleanliness; just that it works. 🙂 If you are going to use this, be aware of 3 things:
1. You’ll need to sign up for your own API from Weather Underground.
2. You’ll need make sure you’ve installed all the necessary libraries on your Pi. (Read Adafruit’s reading analog data tutorial for this piece. I’ll try to put something together in order to show all of the steps necessary to get this to work.)
3. You’ll need to change your MySQL connection variables

So without further adieu:

#!/usr/bin/env python
import time
import os
import RPi.GPIO as GPIO
import MySQLdb
import urllib2

#set up some GPIO settings
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)

# set up pin that provides power to moisture probes
GPIO.setup(17, GPIO.OUT)
GPIO.output(17, True)

#read inside temperature sensor. temperature = temp in degrees C
tfile = open("/sys/bus/w1/devices/28-000004d608e1/w1_slave")
text = tfile.read()
tfile.close()
temperaturedata = text.split("\n")[1].split(" ")[9]
temperature = float(temperaturedata[2:])
temperature = temperature / 1000

#go get outside humidity from weather underground using api
#reading json file to line that contains humidity and pulling
#out the numbers in the text
req = urllib2.Request('http://api.wunderground.com/api/****************/conditions/q/TX/Forney.json')
response = urllib2.urlopen(req)

read_until = 52
humid_line = 54

correctline = []
correct_humid_line = []
lines = []

for line_number, line in enumerate(response.readlines()):
if line_number == read_until:
correctline.append(line)
elif line_number == humid_line:
correct_humid_line.append(line)
else:
lines.append(line)

pull_humid = ','.join(correct_humid_line)

out_humid = pull_humid[-6:-4]
out_humid = round(float(out_humid),1)

# convert celsius to fahrenheit for inside temp
temp_F = ( temperature * 9.0 / 5.0 ) + 32

# show only one decimal place for temperature
temp_F = "%.1f" % temp_F
temp_C = temperature

# read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
def readadc(adcnum, clockpin, mosipin, misopin, cspin):
if ((adcnum > 7) or (adcnum < 0)): return -1 GPIO.output(cspin, True) GPIO.output(clockpin, False) # start clock low GPIO.output(cspin, False) # bring CS low commandout = adcnum commandout |= 0x18 # start bit + single-ended bit commandout <<= 3 # we only need to send 5 bits here for i in range(5): if (commandout & 0x80): GPIO.output(mosipin, True) else: GPIO.output(mosipin, False) commandout <<= 1 GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout = 0 # read in one empty bit, one null bit and 10 ADC bits for i in range(12): GPIO.output(clockpin, True) GPIO.output(clockpin, False) adcout <<= 1 if (GPIO.input(misopin)): adcout |= 0x1 GPIO.output(cspin, True) adcout /= 2 # first bit is 'null' so drop it return adcout # change these as desired - they're the pins connected from the # SPI port on the ADC to the Cobbler. Since I am using 2 ADCs #I have 2 chip select pins. 25 for the first one and 8 for the #second one SPICLK = 18 SPIMISO = 23 SPIMOSI = 24 SPICS = 25 SPICS1 = 8 # set up the SPI interface pins GPIO.setup(SPIMOSI, GPIO.OUT) GPIO.setup(SPIMISO, GPIO.IN) GPIO.setup(SPICLK, GPIO.OUT) GPIO.setup(SPICS, GPIO.OUT) GPIO.setup(SPICS1, GPIO.OUT) # set up the pin locations of the different probes. Can only be #0-7 as there are only 8 pins per ADC readadc0 = 0 readadc2 = 2 readadc3 = 3 readadc4 = 4 readadc5 = 5 readadc6 = 6 readadc7 = 7 readadc8 = 0 readadc9 = 1 readadc10 = 2 readadc11 = 3 readadc12 = 4 readadc13 = 5 readadc15 = 7 # read the analog pins. Assigning reads to sensor variables lux_sens0 = readadc(readadc0, SPICLK, SPIMOSI, SPIMISO, SPICS) moisture_sens1 = readadc(readadc2, SPICLK, SPIMOSI, SPIMISO, SPICS) lux_sens1 = readadc(readadc3, SPICLK, SPIMOSI, SPIMISO, SPICS) moisture_sens2 = readadc(readadc4, SPICLK, SPIMOSI, SPIMISO, SPICS) lux_sens2 = readadc(readadc5, SPICLK, SPIMOSI, SPIMISO, SPICS) moisture_sens3 = readadc(readadc6, SPICLK, SPIMOSI, SPIMISO, SPICS) lux_sens3 = readadc(readadc7, SPICLK, SPIMOSI, SPIMISO, SPICS) moisture_sens4 = readadc(readadc8, SPICLK, SPIMOSI, SPIMISO, SPICS1) lux_sens4 = readadc(readadc9, SPICLK, SPIMOSI, SPIMISO, SPICS1) moisture_sens5 = readadc(readadc10, SPICLK, SPIMOSI, SPIMISO, SPICS1) lux_sens5 = readadc(readadc11, SPICLK, SPIMOSI, SPIMISO, SPICS1) moisture_sens6 = readadc(readadc12, SPICLK, SPIMOSI, SPIMISO, SPICS1) lux_sens6 = readadc(readadc13, SPICLK, SPIMOSI, SPIMISO, SPICS1) humid_sens = readadc(readadc15, SPICLK, SPIMOSI, SPIMISO, SPICS1) # convert reading from humidity sensor to humidity based on formula # from datasheet sensor_humid = (((humid_sens*3.3/1023/3.3)-.1515)/.00636) humid = sensor_humid /(1.0546 - .00216 * float(temp_C)) inhumid = round(humid,1) # convert lux into relative terms #lux0 if lux_sens0 < 10: lux0 = "Dark" elif lux_sens0 < 200: lux0 = "Dim" elif lux_sens0 < 500: lux0 = "Light" elif lux_sens0 < 800: lux0 = "Bright" else: lux0 = "Very Bright" #lux1 if lux_sens1 < 10: lux1 = "Dark" elif lux_sens1 < 200: lux1 = "Dim" elif lux_sens1 < 500: lux1 = "Light" elif lux_sens1 < 800: lux1 = "Bright" else: lux1 = "Very Bright" #lux2 if lux_sens2 < 10: lux2 = "Dark" elif lux_sens2 < 200: lux2 = "Dim" elif lux_sens2 < 500: lux2 = "Light" elif lux_sens2 < 800: lux2 = "Bright" else: lux2 = "Very Bright" #lux3 if lux_sens3 < 10: lux3 = "Dark" elif lux_sens3 < 200: lux3 = "Dim" elif lux_sens3 < 500: lux3 = "Light" elif lux_sens3 < 800: lux3 = "Bright" else: lux3 = "Very Bright" #lux4 if lux_sens4 < 10: lux4 = "Dark" elif lux_sens4 < 200: lux4 = "Dim" elif lux_sens4 < 500: lux4 = "Light" elif lux_sens4 < 800: lux4 = "Bright" else: lux4 = "Very Bright" #lux5 if lux_sens5 < 10: lux5 = "Dark" elif lux_sens5 < 200: lux5 = "Dim" elif lux_sens5 < 500: lux5 = "Light" elif lux_sens5 < 800: lux5 = "Bright" else: lux5 = "Very Bright" #lux6 if lux_sens6 < 10: lux6 = "Dark" elif lux_sens6 < 200: lux6 = "Dim" elif lux_sens6 < 500: lux6 = "Light" elif lux_sens6 < 800: lux6 = "Bright" else: lux6 = "Very Bright" # convert moisture into relative terms # moisture1 if moisture_sens1 < 150: moisture1 = "Dry" elif moisture_sens1 < 350: moisture1 = "Moist" else: moisture1 = "Wet" # moisture2 if moisture_sens2 < 150: moisture2 = "Dry" elif moisture_sens2 < 350: moisture2 = "Moist" else: moisture2 = "Wet" # moisture3 if moisture_sens3 < 150: moisture3 = "Dry" elif moisture_sens3 < 350: moisture3 = "Moist" else: moisture3 = "Wet" # moisture4 if moisture_sens4 < 150: moisture4 = "Dry" elif moisture_sens4 < 350: moisture4 = "Moist" else: moisture4 = "Wet" # moisture5 if moisture_sens5 < 150: moisture5 = "Dry" elif moisture_sens5 < 350: moisture5 = "Moist" else: moisture5 = "Wet" # moisture6 if moisture_sens6 < 150: moisture6 = "Dry" elif moisture_sens6 < 350: moisture6 = "Moist" else: moisture6 = "Wet" # get temp from outside sensor. Needed to do this down lower # as to not get readings from sensors confused # they are attached to the same pin tfile1 = open("/sys/bus/w1/devices/28-000004cfffc6/w1_slave") text1 = tfile1.read() tfile1.close() temperaturedata1 = text1.split("\n")[1].split(" ")[9] temperature1 = float(temperaturedata1[2:]) temperature1 = temperature1 / 1000 temp_F1 = ( temperature1 * 9.0 / 5.0 ) + 32 temp_F1 = "%.1f" % temp_F1 #set in and out temps to variables I can understand in_temp = temp_F out_temp = temp_F1 #printing out the readings. Not needed, but used for testing purposes print("temp_F:", temp_F) print("temp_F1:", temp_F1) print("lux0:", lux0) print("moisture1:", moisture1) print("lux1", lux1) print("moisture2:", moisture2) print("lux2", lux2) print("moisture3:", moisture3) print("lux3", lux3) print("moisture4:", moisture4) print("lux4", lux4) print("moisture5:", moisture5) print("lux5", lux5) print("moisture6:", moisture6) print("lux6", lux6) print("Inside humid:", round(inhumid,1), "%") print("Outside humid:", round(float(out_humid),1), "%") print("moisture_sens1:", moisture_sens1) print("moisture_sens2:", moisture_sens2) print("moisture_sens3:", moisture_sens3) print("moisture_sens4:", moisture_sens4) print("moisture_sens5:", moisture_sens5) print("moisture_sens6:", moisture_sens6) #setting the pin that provides the power to the moisture sensors # to an input as to not provide power in between readings GPIO.output(17, False) GPIO.cleanup() #setting up pin for heater switch power_pin = 22 GPIO.setup(power_pin, GPIO.OUT) GPIO.setup(power_pin, False) # if temperature is below a certain point, turn the heater on if float(temp_F1) < 50: GPIO.output(power_pin, True) htr_status = "ON" else: GPIO.output(power_pin, False) htr_status = "OFF" print("heater", htr_status) #setting up pin for pump switch pump_pin = 11 GPIO.setup(pump_pin, GPIO.OUT) GPIO.setup(pump_pin, False) #check to see how many moisture sensors are reading as "Dry" moisture_count = 0 if moisture1 == "Dry": moisture_count = moisture_count + 1 if moisture2 == "Dry": moisture_count = moisture_count + 1 if moisture3 == "Dry": moisture_count = moisture_count + 1 if moisture4 == "Dry": moisture_count = moisture_count + 1 if moisture5 == "Dry": moisture_count = moisture_count + 1 if moisture6 == "Dry": moisture_count = moisture_count + 1 # if more than a certain amount of sensor read "Dry", then turn on the pump if float(moisture_count) > 1:
GPIO.output(pump_pin, True)
pump_status = "ON"
else:
GPIO.output(pump_pin, False)
pump_status = "OFF"

print("pump status:", pump_status)

# alarm setup if pump is not coming on. (Will use this later when I
# add the float sensor to the rain barrel to make sure the pump
# doesn't come on when there's no water.) This will act as my alarm
# if there is no water in the barrel
if moisture_count > 3 and pump_status == "OFF":
moisture_alarm = "ON"
else:
moisture_alarm = "OFF"

# Placing data into the database

# Open database connection
db = MySQLdb.connect(host="IP Address", port=3306, user= "user_name", passwd="Password" )

# prepare a cursor object using cursor() method
cursor = db.cursor()

# Prepare SQL query to INSERT a record into the database.
sql = "INSERT INTO weather_tracking.weather_results (inside_temp, outside_temp, inside_humid, outside_humid, lux0_value, lux0_txt, moisture1_value, moisture1_txt, lux1_value, lux1_txt, moisture2_value, moisture2_txt, lux2_value, lux2_txt, moisture3_value, moisture3_txt, lux3_value, lux3_txt, moisture4_value, moisture4_txt, lux4_value, lux4_txt, moisture5_value, moisture5_txt, lux5_value, lux5_txt, moisture6_value, moisture6_txt, lux6_value, lux6_txt, pump_status, htr_status, moisture_count, moisture_alarm) VALUES (" + str(in_temp) + "," + str(out_temp) + "," +str(inhumid) + "," + str(out_humid) + "," + str(lux_sens0) + ",'" + str(lux0) + "'," + str(moisture_sens1) + ",'" + str(moisture1) + "'," + str(lux_sens1) + ",'" + str(lux1) + "'," + str(moisture_sens2) + ",'" + str(moisture2) + "'," + str(lux_sens2) + ",'" + str(lux2) + "'," + str(moisture_sens3) + ",'" + str(moisture3) + "'," + str(lux_sens3) + ",'" + str(lux3) + "'," + str(moisture_sens4) + ",'" + str(moisture4) + "'," + str(lux_sens4) + ",'" + str(lux4) + "'," + str(moisture_sens5) + ",'" + str(moisture5) + "'," + str(lux_sens5) + ",'" + str(lux5) + "'," + str(moisture_sens6) + ",'" + str(moisture6) + "'," + str(lux_sens6) + ",'" + str(lux6) + "','" + str(pump_status) + "','" + str(htr_status) + "'," + str(moisture_count) + ",'" + str(moisture_alarm) + "')"
print("sql:", sql)
#try:
# Execute the SQL command
cursor.execute(sql)
# Fetch all the rows in a list of lists.
#except:
# print "Error: Unable to Insert Data"

# disconnect from server
db.close()

Such a marvelous little computer…

20131015-110724.jpg