Bakgrund

Har du en balkong med massor av växter? Kanske några som står i sol medans andra står i skugga?
Det är precis det som jag har!
Medans jorden torkade ut för alla växter som stod i solen så var ju fortfarande de i skuggan fuktiga. Det gjorde att jag var tvungen att vattna varannan dag för vissa växter skulle ta sig bra. Och samtidigt kunde jag övervattna de som stod i skuggan.

I detta inlägg tänkte jag visa hur jag löste problemet, frigjorde tid samt fick sinnesfrid 🙂

Vänligen notera att jag använder mig av www.mysensors.org arduino bibliotek. Det som specas nedan är en sk NOD och den skickar information till en gateway som sedan snackar med valfri controller. Det finns jättefina beskrivningar på deras sida för att bygga gatewayen samt andra saker. Det går såklart att skriva en sketch till Arduinon som är självförsörjande utan allt detta.
Men jag vill ha informationen och kunna styra allt via mitt hemmaautomationssystem.

 

Detta behöver du för att styra 2 krukor eller rabatter:

1 Arduino Nano
1 Relämodul för arduino med 2st relä
1 NRF24l01+ 2.4GHz Wireless Module, ta gärna den med stora antennen.
1 Socket Adapter plate Board for 8Pin NRF24L01 Wireless Transceive module 51
1 2 Arduino Fuktighetssensorer
2 Minivattenpumpar som kan vara helt under vatten och är på 12V
1 DC-DC konverter som omvandlar 12V till 5V
1 Switchat Nätaggregat 12V (rekommenderar minst 3A)
1 SI7021 temperatur/luftfuktighets modul till Arduino
1 Låda som kan husera elektroniken
1 set bevattningssystem med små mikrosprinklers
1 Hink/balja som skall hålla mycket vatten.
Diverse kabel, kopplingsplintar etc
Det är viktigt att inte låta sig avskräckas om du är en nybörjare! Jag kan inte påstå att jag är duktig på att skriva kod och jag har spenderat många timmar på enkla misstag.
Men jag lyckades få ihop allt 🙂

Så här gjorde jag:

Fuktighetssensor:

Fuktsensor

Koppla in en fuktighetssensor till pin A0-A1 och en till pin A2-A3 på Arduinon.
Det spelar ingen roll vilken polaritet så bara in med kablarna.
På själva sensorn är det bäst om man kluddar över lite vanligt smältlim på kabelytorna så att de vattentätas lite.

Kopplingsplintar:

Märk upp 4st kopplingsplintar som kan heta “5V”, “5V GND”, “12V” samt “12V GND”. Vi kommer använda flera kopplingar än det finns pins så vi drar ut 5V och GND från arduinon samt behöver även separera inkommande 12V och GND.
Börja med att dra en kabel mellan Arduinons pin GND till kopplingsplinten “5V GND”.
Samt en kabel mellan Arduinons pin 5V till “5V” kopplingsplinten.

Luftfuktighetssensor:

Koppla in SI7021 modulen som har 4 pins, VCC, GND, SDA samt SCL. SDA går till pin A4 och SCL går till pin A5 på Arduinon. Denna modul fungerar med 3.3V så koppla in VCC till pin 3.3V på Arduinon och GND till “5V GND” kopplingsplinten.

Relämodul:

Koppla nu in relämodulen. Ditt relä bör ha en bygel, med bland annat en pin som heter JDVcc. Plocka bort bygeln. Koppla JDVcc till “5V” och den GND pin som finns precis bredvid till “5V GND”.
Det finns en till GND på relämodulen men den skall vi INTE använda. Dra sedan en kabel från pin 5v på relät till “5V” kopplingsplinten. In1 samt In2 pinnarna på relät dras till pin D3 respektive pin D4 på arduinon.

Vattenpumpar:

Vi vill bryta på plus-sidan i relät så sätt vattenpumpens pluskabel in till mittenuttaget på relät. Repetera med den andra pumpen till det andra relät. Koppla minus-sidan på vattenpumpen till “12V GND”, repetera för den andre vattenpumpen. Dra sedan en kabel från “12V” kopplingsplinten till den vänstra sidan av relät. Beroende på relä så kommer det vara NC, normally closed.
Repetera för för det andra relät. Det är vad vi vill ha för om relät bråkar så skall strömmen brytas och pumparna stanna.

Spänningsmatning:

På DC konvertern så har den input sida samt output sida. På outputsidan drar du pluspolen till “5V” samt minuspolen till “5V GND”. På DC konverterns inputsida drar du pluspolen till “12V” och minuspolen går till “12V GND”

Ovan är det som krävs för att styra allt om endast arduino är styrenheten.
Jag vill kunna styra den på distans så då behövs detta tillägget.

Trådlös styrning

NRF24L01+ är en sändnings/mottagningsmodul och har 8 pinnar. Denna trycks ner i motsvarande pinnar på socket adaptern. Detta chip fungerar med 3.3V men adaptern behöver 5V och omvandlar sedan till 3.3V.  Anledningen till att vi gör så här är att vi vill säkerställa chipet får tillräckligt med bra ström.  En Arduino kan inte leverera tillräckligt med ström på 3.3V pin och man kan få missade sändningar/mottagningar. På socket board kopplas pin VCC till “5V” och pin GND till “5V GND” kopplingsplintarna. Resterande pins kopplas till arduinon enligt följande:
CE till 9, CSN till 10, MOSI till 11, MISO till 12 samt SCK till 13.
IRQ används ej.

230V
Kvar som finns att göra är att koppla in nätaggregatets pluspol samt minuspol till “12V” respektive “12V GND”.
Nu är elektroniken färdig!

Stoppa dock inte in strömadaptern i vägguttaget än. Koppla vattenslang till pumparna och dra snyggt till krukorna/rabatterna.
Dra samtidigt jordfuktighetsgivarna och placera allt strategiskt i krukorna för maximal effekt.
Fyll hinken/baljan med vatten och stoppa ner pumparna.

All elektronik behöver skyddas så in med det i en skyddad miljö, exempelvis en elektroniklåda i plast.
SI7021 modulen får hänga utanför för är den inne i lådan kommer den rapportera den värme som kommer från elektroniken.

Arduino Nano

Programmering av Arduino

Koppla upp Arduinon till din dator med en micro usb till vanlig USB. Starta arduino programmet som finns att ladda ner på https://www.arduino.cc/en/Main/Software
Se till att ni har mysensors bibliotek inläst.  Hur ni sätter upp detta finns en jättefin beskrivning och film här https://www.mysensors.org/about/arduino

Sketchen som jag använt mig av finns här:

/* **SKETCH BEGINNING**

/**
* 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.
*
* Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2015 Sensnology AB
* Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors
*
* Documentation: http://www.mysensors.org
* Support Forum: http://forum.mysensors.org
*
* 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.
*
*******************************
*
* REVISION HISTORY
* Version 1.0 - Henrik Ekblad
*
* DESCRIPTION
* Example sketch showing how to control physical relays.
* This example will remember relay state after power failure.
* http://www.mysensors.org/build/relay
*/

// Enable debug prints to serial monitor
//#define MY_DEBUG
//Network
#define MY_NODE_ID 8 // I have hardcoded the ID
#define MY_PARENT_NODE_ID 0 // I have hardcoded the gateway
#define MY_PARENT_NODE_IS_STATIC
#define MY_RADIO_NRF24 //What type of radio
#define MY_RF24_PA_LEVEL RF24_PA_MAX //The radio is one with antenna so we must set this to max
//Signing makes everything secure. Arduino must be prepared before according to mysensors.org
#define MY_SIGNING_SOFT
#define MY_SIGNING_SOFT_RANDOMSEED_PIN 7
#define MY_SIGNING_REQUEST_SIGNATURES
//Includes
#include <SPI.h>
#include <MySensors.h>
#include <SI7021.h>
#include <RunningAverage.h>
//Define Relay
#define RELAY_1 3 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define RELAY_2 4 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define RELAY_3 5 // Arduino Digital I/O pin number for first relay (second on pin+1 etc)
#define NUMBER_OF_RELAYS 3 // Total number of attached relays
#define RELAY_ON 1 // GPIO value to write to turn on attached relay
#define RELAY_OFF 0 // GPIO value to write to turn off attached relay
#define RELEASE "1.4"
//Define Moisture things
#define AVERAGES 2 //we use 2 readings to smooth the readings
#define STABILIZATION_TIME 1000 // Let the sensor stabilize before reading
//Change direction on moisture could help with corrosion
byte direction = 0;
//Moisture sensor pins
const int SENSOR_ANALOG_PINS[] = {A0, A1}; // Sensor1 is connected to these two pins.
const int SENSOR_ANALOG_PINS2[] = {A2, A3}; // Sensor2 is connected to these two pins.
// Child sensor ID's
#define CHILD_ID_TEMP 5
#define CHILD_ID_HUM 6
#define CHILD_ID_MOISTURE 7
#define CHILD_ID_MOISTURE2 8
#define CHILD_ID_BUTTON 9
#define CHILD_ID_BUTTON2 10
// How many milli seconds between each measurement of temp and humidity
#define MEASURE_INTERVAL 30000
// FORCE_TRANSMIT_INTERVAL, the sensor is forced to report all values to the controller
#define FORCE_TRANSMIT_INTERVAL 2000 // 20minutes
// TRANSMIT_THRESHOLD tells how much the humidity/remperature should have changed since last time it was transmitted. 
#define HUMI_TRANSMIT_THRESHOLD 1.0
#define TEMP_TRANSMIT_THRESHOLD 0.2
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
#define N_ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
SI7021 humiditySensor;
RunningAverage raHum(AVERAGES);

// Sensor messages, here I define different channels where the info is sent
MyMessage msgHum(CHILD_ID_HUM, V_HUM);
MyMessage msgTemp(CHILD_ID_TEMP, V_TEMP);
MyMessage msgMoist(CHILD_ID_MOISTURE, V_HUM);
MyMessage msgMoist2(CHILD_ID_MOISTURE2, V_HUM);
MyMessage msgButton(CHILD_ID_BUTTON, V_HUM);
MyMessage msgButton2(CHILD_ID_BUTTON2, V_HUM);
MyMessage msgR1(RELAY_1, V_STATUS);
MyMessage msgR2(RELAY_2, V_STATUS);
// Global settings
const unsigned long tUpdateMoist = 3600000; // update interval for the moisture sensor1, 1hour
const unsigned long tUpdateMoist2 = 3600000; //update interval for the moisture sensor2, 1hour
unsigned long t1; //defining t1
unsigned long t2; //defining t2
int measureCount = 0; //defining measureCount
boolean isMetric = true;
boolean highfreq = true; //delete, is probably not needed
boolean transmission_occured = false; //reset so it starts at false

// Storage of old measurements, reset them all to 0
float lastTemperature = -100;
int lastHumidity = -100;
int oldMoistureLevel = -1;
int oldMoistureLevel2 = -1;
int button = -1;
int button2 = -1;

void before()
{
for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS; sensor++, pin++)
{
// Then set relay pins in output mode
pinMode(pin, OUTPUT);
// Set relay to last known state (using eeprom storage)
digitalWrite(pin, loadState(sensor)?RELAY_ON:RELAY_OFF);
}
}

void setup()
{
Serial.begin(115200);
humiditySensor.begin();
isMetric = getControllerConfig().isMetric;
Serial.print(F("isMetric: ")); Serial.println(isMetric);
raHum.clear();
t1=millis();
t2=millis();
//sendTempHumidityMeasurements(true);
sendMoistureMeasurements();
sendMoistureMeasurements2();
delay(250);
for (int i = 0; i < N_ELEMENTS(SENSOR_ANALOG_PINS); i++)
{
pinMode(SENSOR_ANALOG_PINS[i], OUTPUT);
digitalWrite(SENSOR_ANALOG_PINS[i], LOW); 
}
for (int j = 0; j < N_ELEMENTS(SENSOR_ANALOG_PINS2); j++)
{
pinMode(SENSOR_ANALOG_PINS2[j], OUTPUT);
digitalWrite(SENSOR_ANALOG_PINS2[j], LOW); 
}
}

void presentation()
{
// Send the sketch version information to the gateway and Controller
sendSketchInfo("RelayTempHumMoist", "1.0");
for (int sensor=1, pin=RELAY_1; sensor<=NUMBER_OF_RELAYS; sensor++, pin++)
{
// Register all sensors to gw (they will be created as child devices)
present(sensor, S_BINARY,"Relays");
}
present(CHILD_ID_TEMP,S_TEMP,"Temperature");
present(CHILD_ID_HUM,S_HUM,"Humidity");
present(CHILD_ID_MOISTURE, S_HUM,"Moisture");
present(CHILD_ID_MOISTURE2, S_HUM,"Moisture2");
present(CHILD_ID_BUTTON, S_HUM,"Button");
present(CHILD_ID_BUTTON2, S_HUM,"Button2");

}


void loop()
{
measureCount ++;
bool forceTransmit = false;
transmission_occured = false;
if (measureCount > FORCE_TRANSMIT_INTERVAL)
{
forceTransmit = true; 
measureCount = 0;
Serial.print(F("inne i loopen :"));
}
if ((millis() - t1) > tUpdateMoist) sendMoistureMeasurements();
if ((millis() - t2) > tUpdateMoist2) sendMoistureMeasurements2();
sendTempHumidityMeasurements(forceTransmit);
}

void sendTempHumidityMeasurements(bool force)
{
wait(MEASURE_INTERVAL);
bool tx = force;
si7021_env data = humiditySensor.getHumidityAndTemperature();
raHum.addValue(data.humidityPercent);
float diffTemp = abs(lastTemperature - (isMetric ? data.celsiusHundredths : data.fahrenheitHundredths)/100.0);
float diffHum = abs(lastHumidity - raHum.getAverage());
Serial.print(F("TempDiff :"));Serial.println(diffTemp);
Serial.print(F("HumDiff :"));Serial.println(diffHum);
if (isnan(diffHum)) tx = true; 
if (diffTemp > TEMP_TRANSMIT_THRESHOLD) tx = true;
if (diffHum > HUMI_TRANSMIT_THRESHOLD) tx = true;

if (tx)
{
measureCount = 0;
float temperature = (isMetric ? data.celsiusHundredths : data.fahrenheitHundredths) / 100.0;

int humidity = data.humidityPercent;
Serial.print("T: ");Serial.println(temperature);
Serial.print("H: ");Serial.println(humidity);

send(msgTemp.set(temperature,1));
send(msgHum.set(humidity));
lastTemperature = temperature;
lastHumidity = humidity;
transmission_occured = true;
}
}

void sendMoistureMeasurements()
{
pinMode(SENSOR_ANALOG_PINS[direction], INPUT_PULLUP); // Power on the sensor
analogRead(SENSOR_ANALOG_PINS[direction]);// Read once to let the ADC capacitor start charging
sleep(STABILIZATION_TIME);
int moistureLevel = (1023 - analogRead(SENSOR_ANALOG_PINS[direction]));

// Turn off the sensor to conserve battery and minimize corrosion
pinMode(SENSOR_ANALOG_PINS[direction], OUTPUT);
digitalWrite(SENSOR_ANALOG_PINS[direction], LOW);

direction = (direction + 1) % 2; // Make direction alternate between 0 and 1 to reverse polarity which reduces corrosion
// Always send moisture information so the controller sees that the node is alive

// Send rolling average of 2 samples to get rid of the "ripple" produced by different resistance in the internal pull-up resistors
// See http://forum.mysensors.org/topic/2147/office-plant-monitoring/55 for more information
if (oldMoistureLevel == -1)
{ // First reading, save value
oldMoistureLevel = moistureLevel;
}
if (button == 1)
{
send(msgButton.set((moistureLevel + oldMoistureLevel + 0.5) / 2 / 10.23, 1));
oldMoistureLevel = moistureLevel;
t1 = millis();
Serial.print(F("inne i button :"));
}
if (button == 0)
{
send(msgMoist.set((moistureLevel + oldMoistureLevel + 0.5) / 2 / 10.23, 1));
oldMoistureLevel = moistureLevel;
t1 = millis();
}
button = 0; 
}

void sendMoistureMeasurements2()
{
pinMode(SENSOR_ANALOG_PINS2[direction], INPUT_PULLUP); // Power on the sensor
analogRead(SENSOR_ANALOG_PINS2[direction]);// Read once to let the ADC capacitor start charging
sleep(STABILIZATION_TIME);
int moistureLevel2 = (1023 - analogRead(SENSOR_ANALOG_PINS2[direction]));

// Turn off the sensor to conserve battery and minimize corrosion
pinMode(SENSOR_ANALOG_PINS2[direction], OUTPUT);
digitalWrite(SENSOR_ANALOG_PINS2[direction], LOW);

direction = (direction + 1) % 2; // Make direction alternate between 0 and 1 to reverse polarity which reduces corrosion
// Always send moisture information so the controller sees that the node is alive

// Send rolling average of 2 samples to get rid of the "ripple" produced by different resistance in the internal pull-up resistors
// See http://forum.mysensors.org/topic/2147/office-plant-monitoring/55 for more information
if (oldMoistureLevel2 == -1)
{ // First reading, save value
oldMoistureLevel2 = moistureLevel2;
}
if (button2 == 1)
{
send(msgButton2.set((moistureLevel2 + oldMoistureLevel2 + 0.5) / 2 / 10.23, 1));
oldMoistureLevel2 = moistureLevel2;
t2 = millis();
Serial.print(F("inne i button2 :"));
}
if (button2 == 0)
{
send(msgMoist2.set((moistureLevel2 + oldMoistureLevel2 + 0.5) / 2 / 10.23, 1));
oldMoistureLevel2 = moistureLevel2;
t2 = millis();
}
button2 = 0;
}

void receive(const MyMessage &message)
{
// Here I can send messages to the node.
if (message.type==V_STATUS)
{
// Change relay state
digitalWrite(message.sensor-1+RELAY_1, message.getBool()?RELAY_ON:RELAY_OFF);
// Store state in eeprom
saveState(message.sensor, message.getBool());
// Write some debug info
Serial.print("Incoming change for sensor:");
Serial.print(message.sensor);
Serial.print(", New status: ");
Serial.println(message.getBool());
}
if (message.type==V_TRIPPED)
{
// Change relay state
button = 1;
button2 = 1;
sendMoistureMeasurements();
sendMoistureMeasurements2();
}
}

**SKETCH END** */

 

Det som jag får ut är temperatur samt relativ luftfuktighet genom SI7021 modulen. Den mäter detta var 30e sekund. Men om inte temperaturen ändrats med mer än 0.2C eller luftfuktigheten med 1%RH så skickas inget. Dock skickar jag en uppdatering var 20e minut för vissa loggfunktioner kräver värden då och då.

Fuktigheten i jorden mäts 1 gång i timmen och skickar då värdena. Viktigt här är att varje Arduino är lite känslig för yttre omständigheter. Fuktigheten i jorden får bestämmas från kruka till kruka och sedan får man beakta de värden man får. Jag har därför lagt in en kalibreringsfunktion. När jag stoppar ner sensorn så vattnar jag krukan. Sedan skickar jag en notis till arduinon att jag vill ha info om vad fuktigheten är just då. Det värdet jag får (brukar ligga mellan 60-80) blir sedan en referens till 100%.
Jag kan sedan skapa en regel eller dyligt för att starta bevattningen vid ett värde på 30 eller 40 “fuktighet” eller som 50% referens. Det är viktigt att inte be om för regelbundna mätningar.
Det som egentligen händer är att vi skickar lite ström genom 1 Arduino pin och mäter vad vi får i den andra. Ström plus vatten plus järn/koppar etc gör att det korroderar. Och 1 gång per timme, alternativt mer sällan och kanske aldrig på natten gör att sådana sensorer förmodligen kan hålla i flera år. Fast de kostar ändå väldigt lite att byta ut.

Reläna styrs genom notiser som jag skickar till Arduinon. Så reglerna om hur allt skall skötas görs i mitt hemmaautomationssystem och inte lokalt i Arduinon.
Men det går bra att starta från min sketch och skriva om den för att vara fristående.

Om allt gjorts korrekt så är det dags att ansluta nätaggregatet till vägguttaget. Sedan kan man kalla på närmsta person och stolt visa resultatet och njuta av en häftigt automatiserad balkong!

Disclaimer: Ta det alltid lugnt med el och säkerställ att du vet vad du gör.
Koden är inte optimerad och kan säkerligen förbättras. Berätta gärna om det i kommentarerna!

Färdig lösning i låda

Fuktighetssensor i jord

Sprinkler

Sprinkler Monterad

Hink med vatten

 

 

 

 

 

 

Slut!