Reef Discussion

fishiefarmer

Member
Aug 27, 2013
11
1
This is a view of the whole system. Silver perch in top tanks, koi and minnows in bottom right, yabbies in upper left down the slope and the one underneath is the sump. The sump will soon have glass shrimp which I will be growing as feed. The other shallow tanks and the coiled ag pipe are the grow beds.
 

fishiefarmer

Member
Aug 27, 2013
11
1
Not sure why the image is upside down, it looks fine on my tablet. Also not sure why image did not upload in previous posts.

The pdf attached shows the circuit plan for my interface board. I have had to compromise on numbers of pins for various purposes. I chose 6 switch inputs and 7 open collector outputs. The outputs are not being used yet, but will eventually will control things like pumps, automatic feeders, valves etc. They interface through a ULN2003 chip which has 7 channels. The 8 analog inputs go through an MCP3008 chip and use SPI.

Will post python code soon.
 

Attachments

fishiefarmer

Member
Aug 27, 2013
11
1
The code I am using is in 2 parts. The first reads any change in the siphon state, ie from filling to draining and vice versa. To do this I am using "interrupts". This means the program can run in the background, but does not sit in a loop stopping other things from happening. The program starts up when the Pi is booted and stays running (hopefully).

I am a messy programmer, so please forgive the style. I tend to be an "if it works, don't change it" sort of person, but if anyone has any suggestions about improving it feel free to comment.

Here is the code for this:

#!/usr/bin/env python2.7

# script adapted from Alex Eames http://RasPi.tv/

# http://raspi.tv/2013/how-to-use-interrupts-with-python-on-the-raspberry-pi-and-rpi-gpio


import RPIO

import RPi.GPIO as GPIO, datetime, json

import httplib


#print GPIO.RPI_REVISION

GPIO.setmode(GPIO.BCM)

pins = {14, 15, 18, 23, 24, 25} # Pins I hav used on interface board.

SENSE_API_KEY = "your_key" # Key to connect to open.sen.se website.

Air_Temperature = “an_id” # Each data stream has an id.

Fish_Tank_Temperature = “an_id”

Grow_Bed_Temperature = “an_id”

Light_Level = “an_id”

GB1_Siphon_State = “an_id”

GB2_Siphon_State = “an_id”

GB3_Siphon_State = “an_id”

GB4_Siphon_State = “an_id”

GB5_Siphon_State = “an_id”

GB6_Siphon_State = “an_id”

de_bounce = 5000 # 5 seconds


def senseit(gpio_id, val):

#print "\t=> Sending to OpenSense: %s" % sensedata

#value = GPIO.input(gpio_id)

# prepare data

if gpio_id == 14:

datalist = [{"feed_id" : GB1_Siphon_State, "value" : val}]

if gpio_id == 15:

datalist = [{"feed_id" : GB2_Siphon_State, "value" : val}]

if gpio_id == 18:

datalist = [{"feed_id" : GB3_Siphon_State, "value" : val}]

if gpio_id == 23:

datalist = [{"feed_id" : GB4_Siphon_State, "value" : val}]

if gpio_id == 24:

datalist = [{"feed_id" : GB5_Siphon_State, "value" : val}]

if gpio_id == 25:

datalist = [{"feed_id" : GB6_Siphon_State, "value" : val}]


headers = {"sense_key": SENSE_API_KEY,"content-type": "application/json"}

conn = httplib.HTTPConnection("api.sen.se")

# format a POST request with JSON content

conn.request("POST", "/events/", json.dumps(datalist), headers)

response = conn.getresponse()

conn.close()


def gpio_callback(gpio_id, val):

#pin = gpio_id

#print("gpio %s: %s" % (gpio_id, val))

#value = GPIO.input(pin)

#print("gpio %s: %s" % (gpio_id, value))

senseit(gpio_id, val)


# GPIO interrupt callback with debounce timeout of de_bounce)

GPIO.cleanup()

for pin in pins:

#print pin

#GPIO.setup(pin, GPIO.IN)

#GPIO.remove_event_detect(pin)

RPIO.add_interrupt_callback(pin, gpio_callback, edge='both', debounce_timeout_ms = de_bounce)

#print pin


# Starts waiting for interrupts (exit with Ctrl+C)

RPIO.wait_for_interrupts()
 

fishiefarmer

Member
Aug 27, 2013
11
1
The next program is triggered periodically by "cron". I have it set to read every 10 minutes.

This one is really messy, I will clean it up soon, but it does work. The calibration for the thermisters is done by loading data from a calibration table.

#!/usr/bin/python


import httplib, urllib

# download from <a href="http://code.google.com/p/psutil/" title="http://code.google.com/p/psutil/">http://code.google.com/p/psutil/</a>

import RPi.GPIO as GPIO, spidev, time, math, os, json, datetime


# use P1 header pin numbering convention

#GPIO.setmode(GPIO.BCM)



#Calibration info

DEBUG = 0

Voltage = 0.0

Slope = -534.692

Divider0 = 10000.0

data = json.load(open('./Documents/lookup.json'))

reading = 511


# Open.sen.se info

SENSE_API_KEY = "your_key"

FEED_ID1 = “an_id”

FEED_ID2 = “an_id”

FEED_ID3 = “an_id”

FEED_ID4 = “an_id”

FEED_ID5 = “an_id”

Air_Temperature = “an_id”

Fish_Tank_Temperature = “an_id”

Grow_Bed_Temperature = “an_id”

Light_Level = “an_id”

GB1_Siphon_State = “an_id”

GB2_Siphon_State = “an_id”

GB3_Siphon_State = “an_id”

Sump_Tank_Level = “an_id”

Yabbie_Tank_Level = “an_id”

Water_Level = “an_id”

delay = 0

samples = 5


def get_adc(channel): # Read by SPI

spi = spidev.SpiDev()

spi.open(0,0)

spi.max_speed_hz = 4000

# read SPI data from MCP3008 chip

# Only 8 channels 0 to 7 else return -1

if ((channel > 7) or (channel < 0)):

return -1


#time.sleep(delay)

sum = 0

maximum = 0

minimum = 1023

for value in range(samples):

r = spi.xfer2([1,(8+channel)<<4,0])

ret = ((r[1]&3) << 8) + r[2]

#print minimum, maximum

if ret < minimum:

minimum = ret

if ret > maximum:

maximum = ret

#print ret,

sum = sum + ret

#print "Average = ", ret, " Max = ", maximum, " Min = ", minimum

#Average = (sum/samples)

ret = (sum-maximum-minimum)/(samples-2)

#print "Return = ", ret, " Average = ", Average, " Max = ", maximum, " Min = ", minimum

#time.sleep(1)

# Finished reading so turn off channel

spi.close()

#GPIO.cleanup()

return ret


def calibrate(reading, parameter): # Different calibration for different sensors

#reading = 1023 - reading

#print "Resistance = ", Resistance

if parameter == "Light":

Resistance = ((1023.0*Divider0)/(1023.0-reading))-Divider0

Light = (Resistance)

return Light/100

if parameter == "Temp":

#print reading

# Lookup Temperature from imported data table

reading = int(reading)

#print reading

TempC = data.get(str(reading))

#print TempC

return TempC

if parameter == "Level":

return reading/10.0


def senseit(sensedata):

#print "\t=> Sending to OpenSense: %s" % sensedata


# prepare data

datalist = [{"feed_id" : Air_Temperature, "value" :sensedata['temp1']},

{"feed_id" : FEED_ID2, "value" :sensedata['temp2']},

{"feed_id" : FEED_ID3, "value" :sensedata['temp3']},

{"feed_id" : FEED_ID4, "value" :sensedata['light']},

]


headers = {"sense_key": SENSE_API_KEY,"content-type": "application/json"}

conn = httplib.HTTPConnection("api.sen.se")

# format a POST request with JSON content

conn.request("POST", "/events/", json.dumps(datalist), headers)

response = conn.getresponse()

# you may get interesting information here in case it fails

#print response.status, response.reason

#print response.read()

conn.close()


def doit():

field1 = 0.010

#field2 = 100.0

#field3 = 100.0

#field4 = 100.0

for channel in range(4):

Voltage = get_adc(channel)

#print Voltage

#print channel, Voltage

if Voltage <> 0:

if channel == 0:

para = "Light"

field1 = round(calibrate(Voltage, para),1)

elif channel == 4:

para = "Level"

field5 = calibrate(Voltage, para)

else:

para = "Temp"

if channel == 1:

field2 = calibrate(Voltage, para)

elif channel == 2:

field3 = calibrate(Voltage, para)

elif channel == 3:

field4 = calibrate(Voltage, para)

#time.sleep(1)

#print channel, " ", Voltage, para, round(calibrate(Voltage, para),1)

sensedata = { 'temp1' : field2, 'temp2' : field3, 'temp3' : field4, 'light' : field1}

#print sensedata

senseit(sensedata)


# Run Main

if __name__ == "__main__":

doit()
 

Saec

Member
Sep 21, 2013
1
0
Heya, following this project. Very interested.

@Rob you wouldnt happen to have the instructions in a single file, ive seen a few steps but its easier to follow if its all in one place.
 

Moreno5

Member
Oct 1, 2013
19
0
Guys, this is an awesome project, Rob & Clownfishy you have done so well to get this far.
I am new to Raspberry pi and am currently learning ruby so that I can get stuck into this project to monitor my nano tank. Do you think this will be too much for me?
I wanted to see if you guys thought it would be a good idea to also tie in the project over at theoreticalideations.com so that you could also control lighting and set it to come on with online sunrise/sunset times for your location.

I am running a Fluval Sea M40, so am going to look into seeing if it possible to get the current led lamp to work in this way.
 

Moreno5

Member
Oct 1, 2013
19
0
Also, Rob would you be able to send me all the info and code you have as I cannot PM you to ask for it.

thanks in advance
 

Rob

Member
Apr 26, 2012
743
424
We dd have a reefuge FTP site with a backup which when copied across to your www directory gave you the complete interface and separate read script. Maybe the reefuge FTP site vaporized when the original micro communities were lost. Ill take a look on the weekend
 

Moreno5

Member
Oct 1, 2013
19
0
Thanks Rob, highly appreciated.

WHat do you think about the Pi also controlling the LED's?
 

Rob

Member
Apr 26, 2012
743
424
I have my lights controlled via my profilux 3. It provides spectrum plots, overlays etc etc. after setting these up I think the interface although nice is way overkill. A RPi using maybe the adafruit 16 ch pwm to i2c interface and a simple script lie would work well. The RPi has proved very reliable.

Another Australian forum MASA has someone using it for LEDs.and developing an interface which looks great.. Again I think a script controlling pwm ver time would get you running real fast. You don't need a fancy interface For LED , the tank lighting provides instant feedback if you have it correct.
 

Moreno5

Member
Oct 1, 2013
19
0
Thanks for the advice, I will take a look at it as currently I have a Fluval all in one LED light with day and moonlight settings. It would be nice to be able to switch between the two and control this device instead of having to make my own light.

Let me know if you find the FTP site with all the stuff needed to build my own monitor, am really looking forward to giving it a try. Also, I saw that Clownfish did create a "How to" document, but the google docs link is not working. If you could forward everything that would be awesome, just let me know if you need my email address.

thanks Rob
 
@Moreno5, this is Robs project and it is him who should take the praise. Thanks to him, I have it reading the temp of the tank and room temp then posting it to xively. I did start pulling in all the info and putting into one single doc. More than happy to do this as Rob has most the info on here.
@Rob, what do you think, a single doc linked from the first page of the thread to all the info?
 

Moreno5

Member
Oct 1, 2013
19
0
@Moreno5, this is Robs project and it is him who should take the praise. Thanks to him, I have it reading the temp of the tank and room temp then posting it to xively. I did start pulling in all the info and putting into one single doc. More than happy to do this as Rob has most the info on here.
@Rob, what do you think, a single doc linked from the first page of the thread to all the info?
@Clownfishy that's what I thought, you did start talking about being put all in one place and as I was reading through the whole thread I could not find it. It would be great if you could put the full instructions all under one files, maybe we could PDF it along with offering the Code that Rob kindly spent time on and the front end that I think another user helped with.

It really excited me to see people from all over the world interacting to build something non profit for a group of people with the same passion.