Aquaponics Sensor Node

This node is located in the greenhouse at the aquaponics fish tanks. The node is powered by a DC power supply plugged in to the same circuit as the aquaponics pump. This node has the following sensors:

  • Fish Tank Water Temperature
  • Air Temperature
  • Air Humidity
  • Light Intensity

In the future we would like to add a pH sensor and a Dissolved Oxygen sensor as well as possibly an automated fish feeder and a LCD display.



Bill of Materials

  • Arduino Uno (Arduino, Sparkfun, Adafruit, aliexpress, ebay) – for this project a board with an adapter for a power supply and both 5volts and 3.3 volt outputs
  • DS18B20 Waterproof Temperature Sensor (Sparkfun, Adafruit, aliexpress, ebay)
  • DHT22 Air Humidity and Temperature Sensor (Sparkfun,Adafruit, aliexpress, ebay) – Can also be DHT11
  • BH1750 Breakout Board (Sparkfun,Adafruit, aliexpress, ebay)
  • NRF24L01+PA+LNA 2.4GHz Radio (Sparkfun,Adafruit, aliexpress, ebay) can use short range version if not far from gateway. Also may need a 4.7uF capactor
  • DC Power Supply preferably in the 7-12 volt range, 1000mA (Sparkfun,Adafruit, aliexpress, ebay, amazon)

MySensors has a shopping page with good links for most items –


The BH1750 is using I2C and are connected to the A4 (SDA) and A5 (SCL) pins.

DHT22 is connected to pin 6.

DS18B20 is connected to pin 5

The radio must be attached following the instructions on MySensors – Connection the Radio.



To reduce power consumption the arduino will be in sleep mode most of the time. When it wakes it will check the sensors and if needed will transmit the values via the radio to the gateway. Transmitting via the radio takes the most energy so we only want to transmit when necessary. Our arduino is therefore programmed to only send data when a measurement changes or if a threshold of skipped measurements has occurred. This means that if the measurement does not change at a certain point it will transmit the measurement anyway. The timing depends on how long the sleep time is and the allowed number of skipped measurements. Also the Light Intensity is always changing so a 3% change threshold was added t reduce noisy data.

The full sketch –

* This sketch was created by Brit Pair although it builds from all the great sketches
* on MySensors and elsewhere. I include the description of mysensors here:
* The MySensors Arduino library handles the wireless radio link and protocol
* between your home built sensors/actuators and HA controller of choice.
* The sensors forms a self healing radio network with optional repeaters. Each
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
* network topology allowing messages to be routed to nodes.
* Documentation:
* Support Forum:
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
* Version 1.0 - Brit Pair
* Water Temperature, Light, Air Humidity, Air Temperature
//Humidity Temp
//Water temp
#include// Define a static node address, remove if you want auto address assignment
#define NODE_ADDRESS 50//Child Sensor ID
#define CHILD_ID_H2O_TEMP 0
#define CHILD_ID_HUM 20
#define CHILD_ID_TEMP 21
#define CHILD_ID_LIGHT 30

//How often to send
unsigned long SLEEP_TIME = 30000; // Sleep time between reads (in milliseconds)
int maxSkippedReadings = 30;

#define HUMIDITY_SENSOR_DIGITAL_PIN 6 //Pin for Humisity Sensor

#define MAX_ATTACHED_DS18B20 16
#define ONE_WIRE_BUS 5 // Pin where dallas sensor is connected

BH1750 lightSensor;
// Must use the A4 (SDA) and A5 (SCL) pins

MySensor gw;
DHT dht;
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature.

boolean metric = false;

float lastTemp;
int skippedTempReadings = 0;
float lastHum;
int skippedHumReadings = 0;

MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);

float lastTemperature[MAX_ATTACHED_DS18B20];
int skippedH2OTempReadings = 0;
int numSensors=1;
boolean receivedConfig = false;

// Initialize temperature message

// Initialize LUX light level.
MyMessage msgLux(CHILD_ID_LIGHT, V_LEVEL);
uint16_t lastLux;
int skippedLuxReadings = 0;
float luxChangeThrashold = 0.03;

void setup()

// Startup up the OneWire library
// requestTemperatures() will not block current thread


gw.begin(NULL, NODE_ADDRESS, false);


// Send the Sketch Version Information to the Gateway
gw.sendSketchInfo(“GHS_Aquaponics”, “1.0”);

// Fetch the number of attached temperature sensors
numSensors = sensors.getDeviceCount();

// Register all sensors to gw (they will be created as child devices)
gw.present(CHILD_ID_HUM, S_HUM);
gw.present(CHILD_ID_TEMP, S_TEMP);

// Present all h2O sensors to controller
for (int i=0; i maxSkippedReadings) {
skippedTempReadings = 0;
lastTemp = temperature;
if (!metric) {
temperature = dht.toFahrenheit(temperature);
gw.send(msgTemp.set(temperature, 1));
Serial.println(“Humidity – T: “);
} else {
skippedTempReadings = skippedTempReadings + 1;

float humidity = dht.getHumidity();
if (isnan(humidity)) {
Serial.println(“Humidity – Failed reading humidity from DHT”);
} else if (humidity != lastHum || skippedHumReadings > maxSkippedReadings) {
skippedHumReadings = 0;
lastHum = humidity;
gw.send(msgHum.set(humidity, 1));
Serial.println(“Humidity – H: “);
} else {
skippedHumReadings = skippedHumReadings + 1;


void loopH2O()

// Fetch temperatures from Dallas sensors

// query conversion time and sleep until conversion completed
int16_t conversionTime = sensors.millisToWaitForConversion(sensors.getResolution());
// sleep() call can be replaced by wait() call if node need to process incoming messages (or if node is repeater)
// Serial.println(“H2O: conversion time wait” );
// Serial.print(conversionTime );
// Serial.println(“”);

// Read temperatures and send them to controller
for (int i=0; i

// Fetch and round temperature to one decimal
float temperature = static_cast(static_cast((metric ? sensors.getTempCByIndex(i):sensors.getTempFByIndex(i)) * 10.)) / 10.;

//filter bad readings
if ( temperature > -10.00 && temperature < 110.00) { // Only send data if temperature has changed if (lastTemperature[i] != temperature || skippedH2OTempReadings > maxSkippedReadings ) {
skippedH2OTempReadings = 0;
// Send in the new temperature
// Save new temperatures for next compare
Serial.println(“H2O: sensor#”);
Serial.print(” temperature: “);
} else {
skippedH2OTempReadings = skippedH2OTempReadings + 1;

void loopLux()
uint16_t lux = lightSensor.readLightLevel();// Get Lux value
if (isnan(lux)) {
Serial.println(“LUX – Failed reading lux”);
} else {
Serial.println(“LUX = “);
float maxLux = lastLux * (1 + luxChangeThrashold);
float minLux = lastLux * (1 – luxChangeThrashold);
if (lux > maxLux || lux < minLux || skippedLuxReadings > maxSkippedReadings ) {
skippedLuxReadings = 0;
lastLux = lux;
} else {
skippedLuxReadings = skippedLuxReadings + 1;



Used a plastic box with a snap on lid. I don’t expect the system to get wet except for some occasional splashing from the fish. This picture does not show the install location but it is on the side of an IBC tank.


Live Data!

Sorry the hotspot at the greenhouse unfortunately disappeared so the data is no longer available online.

If things are working smoothly you can follow the live data on the dashboard below. If the graphs below show “No Datapoints” the internet may be down at the greenhouse. You can view older data by selecting “Zoom Out” in the upper right and increasing the time range.