Last active
August 29, 2015 14:07
-
-
Save dgomes/7fedf94026761bfa973b to your computer and use it in GitHub Desktop.
Greenhouse Source Code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Greenhouse Interface to read and actuate | |
| #include <Narcoleptic.h> | |
| #include <DHT.h> | |
| #include <SPI.h> | |
| #include <OneWire.h> | |
| #include "nRF24L01.h" | |
| #include "RF24.h" | |
| #include "GreenHouseProtocol.h" | |
| #define DEBUG | |
| #ifdef DEBUG | |
| #define PRINT(X) Serial.print(X) | |
| #define PRINTLN(X) Serial.println(X) | |
| #else | |
| #define PRINT(X) | |
| #define PRINTLN(X) | |
| #endif | |
| #ifdef ARDUINO | |
| int serial_putc( char c, FILE * ) | |
| { | |
| Serial.write( c ); | |
| return c; | |
| } | |
| void printf_begin(void) | |
| { | |
| fdevopen( &serial_putc, 0 ); | |
| } | |
| #else | |
| #error This example is only for use on Arduino. | |
| #endif // ARDUINO | |
| #define PHOTOCELL A5 // the cell and 10K pulldown are connected to a0 | |
| #define HUMIDITY0 A0 | |
| #define HUMIDITY1 A1 | |
| #define HUMIDITY2 A2 | |
| #define HUMIDITY3 A3 | |
| #define HUMPOWER 4 // what pin controls the external BC548 that powers the humidity sensors | |
| #define DHTPIN 3 // what pin DHT connected to | |
| #define RELAY 5 // what pin RELAY connected to | |
| #define DB18B20 8 // what pin the DB18B20 temperature sensor is connected to | |
| DHT dht; | |
| // Set up nRF24L01 radio on SPI bus plus pins 9 & 10 | |
| RF24 radio(9,10); | |
| // Radio pipe addresses for the 2 nodes to communicate. | |
| const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL }; | |
| void powerOnSensors() { | |
| pinMode(HUMPOWER, OUTPUT); | |
| digitalWrite(HUMPOWER, HIGH); //turn ON humidity sensors | |
| #ifdef DEBUG | |
| Serial.begin(115200); | |
| #endif | |
| radio.powerUp(); | |
| dht.setup(DHTPIN, DHT::DHT22); | |
| delay(dht.getMinimumSamplingPeriod()); | |
| pinMode(RELAY, OUTPUT); | |
| pinMode(PHOTOCELL, INPUT); | |
| pinMode(HUMIDITY0, INPUT); | |
| pinMode(HUMIDITY1, INPUT); | |
| pinMode(HUMIDITY2, INPUT); | |
| pinMode(HUMIDITY3, INPUT); | |
| } | |
| void powerOffSensors() { | |
| radio.powerDown(); | |
| //save power on pins by turing them into input | |
| pinMode(HUMPOWER, INPUT); | |
| pinMode(RELAY, INPUT); | |
| } | |
| void setup() { | |
| #ifdef DEBUG | |
| Serial.begin(115200); | |
| printf_begin(); | |
| Serial.println("Greenhouse v4"); | |
| #endif | |
| analogReference(DEFAULT); | |
| pinMode(HUMPOWER, OUTPUT); | |
| pinMode(RELAY, OUTPUT); | |
| pinMode(PHOTOCELL, INPUT); | |
| pinMode(HUMIDITY0, INPUT); | |
| pinMode(HUMIDITY1, INPUT); | |
| pinMode(HUMIDITY2, INPUT); | |
| pinMode(HUMIDITY3, INPUT); | |
| pinMode(DB18B20, INPUT); | |
| dht.setup(DHTPIN); | |
| // | |
| // Setup and configure rf radio | |
| // | |
| radio.begin(); | |
| // enable dynamic payloads | |
| radio.enableDynamicPayloads(); | |
| // optionally, increase the delay between retries & # of retries | |
| radio.setRetries(15,15); | |
| radio.setAutoAck(false); | |
| radio.setDataRate(RF24_250KBPS); | |
| //radio.setPALevel(RF24_PA_MIN); | |
| radio.openWritingPipe(pipes[1]); | |
| radio.openReadingPipe(1,pipes[0]); | |
| // Start listening | |
| radio.startListening(); | |
| // Dump the configuration of the rf unit for debugging | |
| #ifdef DEBUG | |
| radio.printDetails(); | |
| Serial.println("done setup()"); | |
| #endif | |
| } | |
| int readLight() { | |
| pinMode(PHOTOCELL, OUTPUT); | |
| digitalWrite(PHOTOCELL, LOW); | |
| delay(20); | |
| pinMode(PHOTOCELL, INPUT); | |
| delay(20); | |
| analogRead(PHOTOCELL); | |
| delay(10); //give it sometime http://forums.adafruit.com/viewtopic.php?f=25&t=11597 | |
| int photocellReading = analogRead(PHOTOCELL); | |
| return photocellReading; | |
| } | |
| int readHumidityProbe(int num) { | |
| pinMode(num, OUTPUT); | |
| digitalWrite(num, LOW); | |
| delay(20); | |
| pinMode(num, INPUT); | |
| delay(20); | |
| analogRead(num); | |
| delay(10); //give it sometime http://forums.adafruit.com/viewtopic.php?f=25&t=11597 | |
| //Serial.println(analogRead(num)); | |
| int humidityReading = 100 - 100*(analogRead(num)/1023.0); | |
| return humidityReading; | |
| } | |
| boolean switchRelay(boolean val) { | |
| if(val) { | |
| digitalWrite(RELAY, HIGH); | |
| } else { | |
| digitalWrite(RELAY, LOW); | |
| } | |
| PRINT("WATER CMD: "); | |
| PRINTLN(val); | |
| return val; | |
| } | |
| float readDHTHumidity() { | |
| float humidity = dht.getHumidity(); | |
| switch(dht.getStatus()) { | |
| case DHT::ERROR_NONE: | |
| return humidity; | |
| case DHT::ERROR_TIMEOUT: | |
| case DHT::ERROR_CHECKSUM: | |
| return dht.getStatus(); | |
| } | |
| } | |
| long readVcc() { | |
| long result; | |
| // Read 1.1V reference against AVcc | |
| ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); | |
| delay(2); // Wait for Vref to settle | |
| ADCSRA |= _BV(ADSC); // Convert | |
| while (bit_is_set(ADCSRA,ADSC)); | |
| result = ADCL; | |
| result |= ADCH<<8; | |
| result = 1126400L / result; // Back-calculate AVcc in mV | |
| return result; | |
| } | |
| float readDHTTemperature() { | |
| float temp = dht.getTemperature(); | |
| switch(dht.getStatus()) { | |
| case DHT::ERROR_NONE: | |
| return temp; | |
| case DHT::ERROR_TIMEOUT: | |
| case DHT::ERROR_CHECKSUM: | |
| return dht.getStatus(); | |
| } | |
| } | |
| float readInternalTemperature() { | |
| // DS18B20 Temperature chip i/o | |
| // adapted from http://playground.arduino.cc/Learning/OneWire | |
| // tested with http://dx.com/p/ds18b20-digital-temperature-sensor-module-for-arduino-55-125-c-135047 | |
| OneWire ds(DB18B20); | |
| byte i; | |
| byte present = 0; | |
| byte data[12]; | |
| byte addr[8]; | |
| int HighByte, LowByte, TReading, SignBit, Tc_100, Whole, Fract; | |
| if ( !ds.search(addr)) { | |
| PRINT("No more addresses.\n"); | |
| ds.reset_search(); | |
| return -255.0; | |
| } | |
| if ( OneWire::crc8( addr, 7) != addr[7]) { | |
| PRINT("CRC is not valid!\n"); | |
| return -255.1; | |
| } | |
| ds.reset(); | |
| ds.select(addr); | |
| ds.write(0x44,1); // start conversion, with parasite power on at the end | |
| delay(1000); // maybe 750ms is enough, maybe not | |
| // we might do a ds.depower() here, but the reset will take care of it. | |
| present = ds.reset(); | |
| ds.select(addr); | |
| ds.write(0xBE); // Read Scratchpad | |
| for ( i = 0; i < 9; i++) { // we need 9 bytes | |
| data[i] = ds.read(); | |
| } | |
| LowByte = data[0]; | |
| HighByte = data[1]; | |
| TReading = (HighByte << 8) + LowByte; | |
| SignBit = TReading & 0x8000; // test most sig bit | |
| if (SignBit) // negative | |
| { | |
| TReading = (TReading ^ 0xffff) + 1; // 2's comp | |
| } | |
| Tc_100 = (6 * TReading) + TReading / 4; // multiply by (100 * 0.0625) or 6.25 | |
| Whole = Tc_100 / 100; // separate off the whole and fractional portions | |
| Fract = Tc_100 % 100; | |
| if (SignBit) // If its negative | |
| { | |
| return -1*(float(Whole*100+Fract)/100); | |
| } | |
| return (float(Whole*100+Fract)/100); | |
| } | |
| void sendValues() { | |
| // First, stop listening so we can talk | |
| radio.stopListening(); | |
| int hprobe[4] = { readHumidityProbe(HUMIDITY0), readHumidityProbe(HUMIDITY1), readHumidityProbe(HUMIDITY2), readHumidityProbe(HUMIDITY3)}; | |
| digitalWrite(HUMPOWER, LOW); //turn OFF humidity sensors | |
| struct GHDataPacket p = report(readVcc(), readDHTHumidity(), readDHTTemperature(), readInternalTemperature(), readLight(), hprobe, digitalRead(RELAY)); | |
| boolean r = radio.write( &p, sizeof(struct GHDataPacket)); | |
| #ifdef DEBUG | |
| Serial.println(r ? "\nSent VALUES" : "\nFailed to send VALUES"); | |
| printDebug(p); | |
| #endif | |
| // Now, resume listening so we catch the next packets. | |
| radio.startListening(); | |
| } | |
| void loop() { | |
| sendValues(); | |
| delay(250); //give sometime to reply back with command | |
| if ( radio.available() ) { | |
| uint8_t len; | |
| struct GHCommandPacket c; | |
| bool done = false; | |
| while (!done) { | |
| // Fetch the payload, and see if this was the last one. | |
| len = radio.getDynamicPayloadSize(); | |
| if(len == (sizeof(struct GHCommandPacket))) { | |
| done = radio.read(&c, len ); | |
| } else { | |
| PRINTLN("Error receiving GHCommandPacket"); | |
| } | |
| } | |
| switch(c.cmd) { | |
| case GH_GETDATA: | |
| break; | |
| case GH_ONSWITCH: | |
| switchRelay(true); | |
| break; | |
| case GH_OFFSWITCH: | |
| switchRelay(false); | |
| break; | |
| } | |
| sendValues(); | |
| } | |
| powerOffSensors(); | |
| Narcoleptic.delay(30000); // During this time power consumption is minimised | |
| powerOnSensors(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #ifndef GREENHOUSEPROTOCOL_H | |
| #define GREENHOUSEPROTOCOL_H | |
| #include <Arduino.h> | |
| typedef enum { GH_GETDATA = 0, GH_ONSWITCH = 1, GH_OFFSWITCH = 2 } gh_command; | |
| struct GHCommandPacket { | |
| gh_command cmd; | |
| }; | |
| struct GHDataPacket { | |
| long vcc; | |
| float humidity; | |
| float temperature; | |
| float internaltemperature; | |
| int luminosity; | |
| int humidityProbe[4]; | |
| byte water; | |
| }; | |
| struct GHCommandPacket getData() { | |
| struct GHCommandPacket p; | |
| p.cmd = GH_GETDATA; | |
| return p; | |
| } | |
| struct GHCommandPacket turnOnSwitch() { | |
| struct GHCommandPacket p; | |
| p.cmd = GH_ONSWITCH; | |
| return p; | |
| } | |
| struct GHCommandPacket turnOffSwitch() { | |
| struct GHCommandPacket p; | |
| p.cmd = GH_OFFSWITCH; | |
| return p; | |
| } | |
| struct GHDataPacket report(long vcc, float h, float t, float it, int l, int hp[4], byte w) { | |
| struct GHDataPacket p; | |
| p.vcc = vcc; | |
| p.humidity = h; | |
| p.temperature = t; | |
| p.internaltemperature = it; | |
| p.luminosity = l; | |
| for(int i=0; i<4; i++) | |
| p.humidityProbe[i] = hp[i]; | |
| p.water = w; | |
| return p; | |
| } | |
| void printDebug(struct GHDataPacket p) { | |
| Serial.print("VCC: "); | |
| Serial.print(p.vcc); | |
| Serial.println(" v"); | |
| Serial.print("Humidity: "); | |
| Serial.print(p.humidity); | |
| Serial.println(" %"); | |
| Serial.print("Temperature: "); | |
| Serial.print(p.temperature); | |
| Serial.println(" *C"); | |
| Serial.print("Internal Temperature: "); | |
| Serial.print(p.internaltemperature); | |
| Serial.println(" *C"); | |
| Serial.print("Luminosity: "); | |
| Serial.println(p.luminosity); | |
| int probes = sizeof(p.humidityProbe)/2; /* int = 2 bytes */ | |
| Serial.print("Humidity Probes: ["); | |
| for(int i=0; i<probes-1; i++) { | |
| Serial.print(p.humidityProbe[i]); | |
| Serial.print(", "); | |
| } | |
| Serial.print(p.humidityProbe[probes-1]); | |
| Serial.println("]"); | |
| Serial.print("Water: "); | |
| Serial.println(p.water); | |
| } | |
| #endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment