Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Intelligente Bewässerungssteuerung

Komponenten und Verbrauchsmaterialien

Arduino Nano R3
× 1
IO-Expander
× 1
IO-Expander-Bundle
× 1

Apps und Onlinedienste

Arduino-IDE

Über dieses Projekt

Erstellen Sie einen intelligenten Bewässerungscontroller mit Arduino

Bewässern Sie Ihren Garten intelligent mit dynamischen Wasserkreisläufen. Hören Sie auf, Ihren Garten zu gießen, wenn es regnet oder seit Ihrer letzten Bewässerung geregnet hat. Verwenden Sie den Lichtsensor, um die Sonnenaufgangszeit zu erkennen und die Wasserstartzeiten automatisch entsprechend anzupassen. Hören Sie auf, Ihren Garten zu bewässern, wenn es zu kalt ist.

Funktionsliste

  • Außentemperatursensor
  • Außen-Regensensor
  • Außenlichtsensor
  • Batteriegestützte Echtzeituhr für die Wochenplanung
  • Nichtflüchtiger Speicher - keine Bewässerung durch Stromausfall verlieren
  • Sonnenaufgangserkennung
  • Intelligente Bewässerung spart Ihre Wasserrechnung
  • Wasser vor Sonnenaufgang, um die richtige Einweichzeit zu gewährleisten
  • Hör auf zu gießen, wenn es draußen zu kalt ist
  • Reduzieren Sie das Pilzwachstum
  • Einfache Zeitplankontrolle

Erforderliche Teile zum Bau der intelligenten Bewässerungssteuerung

  • IO-Expander
  • x2 1-Draht zu I2C.
  • 1-Draht-Verbindung
  • Optischer Anschluss
  • Splitter
  • Arduino Nano.
  • 4-Kanal-DC-5-V-Relais.
  • TSL2561 Lichtsensor.
  • DS18B20 Wasserdichter Temperatursensor.
  • Optischer Infrarot-Wasserstandssensor.
  • DS3231 AT24C32 IIC Präzisions-Echtzeituhr.
  • I2C SSD1306 OLED 128x64-Display.
  • 200 x 120 x 75 mm klares wasserdichtes Kunststoffgehäuse.
  • 100 x 68 x 50 mm klares wasserdichtes Kunststoffgehäuse.
  • ip68 pg7 Wasserdichte Nylon-Kabelverschraubung.
  • ip68 pg11 Wasserdichte Nylon-Kabelverschraubung.
  • RJ11 Keystone Schraubklemmenbuchse.
  • 50 Fuß 4C4P RJ11-Draht.
  • 2 m 4C4P RJ11-Draht.
  • 2,54 mm Header-Draht.
  • x2 2 Pins SPST Momentary Push Button Micro Switch
  • 12 VDC 1A Netzteil für den Wandadapter.

Schaltplan

OLED-Display

Drücken Sie die Menütaste, um das Menü anzuzeigen, und halten Sie die Taste gedrückt, um durch alle Menüoptionen zu blättern. Das Menü wird nach 30 Sekunden Inaktivität automatisch entfernt. Drücken Sie die Auswahltaste, um die gewünschte Menüfunktion auszuführen.

Warum also den IO-Expander verwenden?

  • Einfacher zu gestalten
  • Standardteile
  • Kein 1-Wire-Treiber zum Schreiben
  • Kein DS3231 RTC-Treiber zum Schreiben
  • Kein EEPROM-Treiber zum Schreiben
  • Kein OLED-Displaytreiber zum Schreiben
  • Keine Anzeigeschriftarten, um Arduino-Codeplatz zu belegen
  • Kein Temperatursensortreiber zum Schreiben
  • Kein optischer Regensensor zum Schreiben
  • Speichert Codeplatz auf Arduino; nur 12710 Byte (39%)
  • Nur drei Tage zum Schreiben des Codes
  • Einfache Verkabelung mit Standard-RJ11-Telefonkabel
  • Keine Probleme mit der Sensorkabellänge
  • Billiger zu bauen als vergleichbare kommerzielle Systeme
  • Einfache Änderungen zur Anpassung an individuelle Anforderungen
  • Einzelnes Netzteil

Bauen Sie das System auf

Verbinden Sie den Arduino Nano mit dem IO Expander und programmieren Sie ihn mit dem folgenden Code. Der 6-Pin-Header ist der serielle Debug-Port der Software und wird bei der endgültigen Installation nicht benötigt.

Stellen Sie sicher, dass Sie die von ONEWIRE_TO_I2C_ROM1 und ONEWIRE-TO_I2C_ROM2 definierte Adresse so ändern, dass sie Ihrer 1-Wire-zu-I2C-Adresse entspricht.

/* IO-Expander-Skizze optimiert
*
* Bewässerungssystem v1.1
*
*/

#include
#include // Datei befindet sich \Programme (x86)\Arduino\hardware\tools\avr\avr\include\time.h
#include
#include
#include
#include "IOExpander.h"

#define FAHRENHEIT
#define INIT_BOARD "g5w1;g11w1;g11d0,75;g12w1;g12d0,75;rsf"
#define ONEWIRE_TO_I2C_ROM1 "i4scc"
#define ONEWIRE_TO_I2C_ROM2 "i6s8fine "t6s0300"
#define RTC_SENSOR "s4te"
#define I2C_EEPROM "s4tf"
#define I2C_OLED "s4t10"
#define I2C_LIGHT "s3t9;sc0"
# define OPTICAL_SENSOR "g5a"
#define BUTTON1 "g11d"
#define BUTTON2 "g12d"

#define WATER_TIME_BEFORE_SUNRISE 60
#define SUNRISE_LUX 100
# define RAIN_DETECT_LEVEL 4.0
#define DO_NOT_WATER_TEMP 4.4444 // 40F

#define MAX_ZONES 4

#define HOUR_IN_DA J 24L
#define MIN_IN_HOUR 60L
#define SEC_IN_MIN 60L
#define SEC_IN_HOUR (MIN_IN_HOUR * SEC_IN_MIN)
#define SEC_IN_DAY (HOUR_IN_DAY * SEC_IN_HOUR)WEEK 7
#define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK)

#define SO 0x01
#define MO 0x02
#define DI 0x04
#define WED 0x08
#define THR 0x10
#define FRI 0x20
#define SA 0x40
#define EVERYDAY (SO | MO | DI | MI | THR | FR | SA)

#define SONNENAUFGANG 0x80

#define MENU_OPTIONS 9
#define MENU_TIME 30

#define OFF 0
#define ON 1

#define STATE_ON_OFF 0x01

//#define SERIAL_DEBUG

#ifdef SERIAL_DEBUG
SoftwareSerial swSerial(8,7 );
#endif

char Wochentag[][4] ={"SUN","MO","DI","MI","DO","FRI"," SAT"};

char menu[][13] ={"Next",
"Water",
"Reset",
"Clock Min +" ,
"Clock Min -",
"Clock Hour +",
"Clock Hour -",
"Sunrise",
"ON/OFF"};

enum {
MENU_NEXT,
MENU_WATER,
MENU_RESET,
MENU_CLOCK_MIN_PLUS,
MENU_CLOCK_MIN_MINUS,
MENU_CLOCK_HOUR_PLUS,
MENU_CLOCK_HOUR_MINUS,
MENU_SUNRISE,
MENU_ON_OFF
};

typedef struct {
char description[16];
uint8_t relay;
} ZONE;

typedef struct {
uint8_t Zone;
uint8_t Tage;
int8_t Stunde;
int8_t min;
uint8_t Dauer;
} SCHEDULE;

typedef struct {
time_t sunrise_time;
time_t last_water_time;
uint8_t water_schedule;
uint8_t water_duration;
uint8_t rain[MAX_ZONES];
uint8_t state;
uint8_t crc;
} NVRAM;

enum {
ZONE1,
ZONE2,
ZONE3,
ZONE4
};

enum {
RELAY1 =1,
RELAY2,
RELAY3,
RELAY4
};

ZONE-Zone[] ={
{"Front Right", RELAY1},
{"Front Left", RELAY2},
{"Büsche", RELAY3},
{"Linke Seite", RELAY4},
};

ZEITPLAN Zeitplan[] ={
{ZONE1, SUNRISE | EVERYDAY, -1, 0, 4},
{ZONE2, EVERYDAY, 6, 15, 5},
{ZONE3, EVERYDAY, 6, 0, 10},
{ZONE4, EVERYDAY , 6, 10, 6},
};

NVRAM nvram;
bool update_nvram =false;

uint8_t crc8(uint8_t* data, uint16_t Länge)
{
uint8_t crc =0;

while (Länge--) {
crc =_crc8_ccitt_update(crc, *data++);
}
return crc;
}

int led =13;
bool init_oled =true;
bool update_oled =true;
bool init_board =true;

#ifdef FAHRENHEIT
#define C2F(temp) CelsiusToFahrenheit(temp)
float CelsiusToFahrenheit(float celsius)
{
return ((celsius * 9) / 5) + 32;
}
#else
#define C2F(temp) (temp)
#endif

void SerialPrint( const char* str, float decimal, char error)
{
Serial.print(str);
if (error) Serial.print(F("NA"));
else Serial.print(dezimal, 1);
}

time_t NextScheduleTime(time_t last_time, uint8_t* next_schedule)
{
time_t next_time =-1;
time_t clk_time;
uint8_t i;
tm clk;
uint8_t wday;

for (i =0; i if (schedule[i].days &SUNRISE) {
clk_time =nvram.sunrise_time;
clk_time +=schedule[i].hour * SEC_IN_HOUR;
clk_time +=schedule[i].min * SEC_IN_MIN;
localtime_r(&clk_time, &clk);
}
else {
localtime_r(&last_time, &clk);
clk. tm_hour =Zeitplan[i].Stunde;
clk.tm_min =Zeitplan[i].min;
clk.tm_sec =0;
clk_time =mktime(&clk);
}
wday =clk.tm_wday;
while (clk_time <=last_time || !(schedule[i].days &(1 < {
clk_time + =SEC_IN_DAY;
if (++wday> SATURDAY) wday =SONNTAG;
if (wday ==clk.tm_wday) Pause; // Nur eine Woche prüfen
}
if (clk_time next_time =clk_time;
*next_schedule =i;
}
}
return next_time;
}

void StartScheduleTime(time_t start_time, uint8_t start_schedule)
{
uint8_t i;

nvram. last_water_time =start_time;
nvram.water_schedule =start_schedule;
nvram.water_duration =schedule[start_schedule].duration+1;
update_nvram =true;
// Prüfen ob es geregnet hat
i =schedule[start_schedule].zone;
if (i 0) {
if (nvram.rain[i]> nvram.water_duration) nvram .water_duration =0;
else nvram.water_duration -=nvram.rain[i];
nvram.rain[i] =0;
}
}

void WaterScheduleTime(void)
{
uint8_t i;

nvram.water_duration--;
update_nvram =true;
i =schedule[ nvram.water_schedule].zone;
if (i Serial.print("r");
Serial.print(zone[i].relay);
> if (nvram.water_duration> 0) Serial.println("o");
else Serial.println("f");
SerialReadUntilDone();
}
}

void setup() {
Serial.begin(115200);
#ifdef SERIAL_DEBUG
swSerial.begin(115200);
#endif
pinMode(led, OUTPUT);
//delay(1000);
wdt_enable(WDTO_8S);
}

void loop() {
static tm rtc;
tm clk, sunrise_clk;
time_t rtc_time;
time_t clk_time;
statische time_t next_time;
static uint8_t last_sec;
static uint8_t last_min;
bool error_rtc;
bool error_light;
bool error_temp;
static long lux =0;
static float temp, rain;
static uint8_t sunrise_counter =MIN_IN_HOUR;
static bool check_sunrise =false;
uint8_t i;
static bool read_nvram =true;
static time_t water_time;
static uint8_t water_schedule;
uint8_t sz;
uint8_t wday;
long n;
bool button1, button2;
static int8_t menu_select =-1;
static time_t menu_time =0;

Serial.println();
if (SerialReadUntilDone()) {
if (init_board) {
SerialCmdDone(INIT_BOARD);
init_board =false;
}

if (init_oled) {
if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM1)) {
SerialCmdDone (I2C_OLED ";si;sc;sd");
init_oled =false;
}
}

if (SerialCmdDone(RTC_SENSOR)) {
error_rtc =!SerialReadTime(&rtc);
if (!error_rtc) {
clk =rtc; // mktime() kann struct ändern tm
rtc_time =mktime(&clk);
localtime_r(&rtc_time, &rtc); // Hole wday.
}

if (read_nvram) {
if (SerialCmdNoError(I2C_EEPROM)) {
SerialReadEEPROM((uint8_t*)&nvram, 0, sizeof (nvram));
if (nvram.crc !=crc8((uint8_t*)&nvram, sizeof(nvram)-sizeof(uint8_t))) {
//swSerial.println("CRC8 Fehler! ");
// nvram initialisieren
memset(&nvram, 0, sizeof(nvram));
clk =rtc;
clk.tm_hour =6;
clk .tm_min =0;
clk.tm_sec =0;
nvram.sunrise_time =mktime(&clk);
if (nvram.sunrise_time update_nvram =true;
}
// Letzte Wasserzeit mindestens eine Woche prüfen
if (rtc_time - nvram.last_water_time> SEC_IN_WEEK) nvram.last_water_time =rtc_time - SEC_IN_WEEK;
// Sonnenaufgangszeit prüfen
if (rtc_time> nvram.sunrise_time) {
localtime_r(&nvram.sunrise_time, &sunrise_clk);
clk =rtc;
clk.tm_hour =sunrise_clk.tm_hour;
clk.tm_min =sunrise_clk.tm_min;
clk.tm_sec =sunrise_clk.tm_sec;
nvram.sunrise_time =mktime(&clk);
if (nvram.sunrise_time }
if (nvram.water_duration) {
nvram. water_duration++;
water_time =nvram.last_water_time;
}
else {
clk_time =(nvram.last_water_time) ? nvram.last_water_time :rtc_time;
water_time =NextScheduleTime(clk_time, &water_schedule);
}
read_nvram =false;
}
}
}

// Nur einmal pro Minute verarbeiten
if (rtc.tm_min !=last_min)
{
// 1-Wire-Temperaturmessung anfordern. Später lesen.
error_temp =!SerialCmdNoError(ONEWIRE_TEMPERATURE);
if (!error_temp) SerialCmdDone("tt");

error_light =!SerialCmdNoError(ONEWIRE_TO_I2C_ROM2 ";oo0" );
if (!error_light) {
SerialCmdDone(I2C_LIGHT); // Kein Overdrive verwenden
SerialCmd("sr");
SerialReadInt(&lux);
SerialReadUntilDone();
}

if (SerialCmd (OPTICAL_SENSOR)) {
SerialReadFloat(&rain);
SerialReadUntilDone();
}

error_temp =!SerialCmdNoError(ONEWIRE_TEMPERATURE);
if (! error_temp) {
SerialCmd("tr");
SerialReadFloat(&temp);
SerialReadUntilDone();
}

// Ist es Sonnenaufgang?
if (lux if (sunrise_counter> 0) sunrise_counter--;
else check_sunrise =true;
}
else {
if (sunrise_counter sunrise_counter++;
if (check_sunrise &&sunrise_counter ==MIN_IN_HOUR) {
nvram.sunrise_time =rtc_time + (SEC_IN_DAY - SEC_IN_HOUR);
check_sunrise =;
update_nvram =true;
}
}
}

// Regnet es?
if (regen <=RAIN_DETECT_LEVEL) {
for (i =0; i if (nvram.rain[i] <-1) nvram.rain[i]++; }
update_nvram =true;
}

// Zeitplan prüfen
if (menu_select ==-1 &&!nvram.water_duration) {
while (water_time + (schedule[water_schedule].duration * SEC_IN_MIN) water_time =NextScheduleTime(water_time, &water_schedule);
}
if (water_time <=rtc_time) {
StartScheduleTime(water_time, water_schedule);
if (temp <=DO_NOT_WATER_TEMP || nvram.state &STATE_ON_OFF ==OFF)
nvram.water_duration =0;
}
}

// Müssen wir gießen?
if (nvram.water_duration) {
WaterScheduleTime();
if (!nvram.water_duration)
water_time =NextScheduleTime(water_time, &water_schedule);
}

last_min =rtc.tm_min;
update_oled =true;
}

// Schaltflächen überprüfen
button1 =SerialReadButton(BUTTON1);
if (button1 ) {
if (menu_select ==-1) menu_select =0;
else {
if (++menu_select>=MENU_OPTIONS)
menu_select =0;
}
menu_time =rtc_time;
update_oled =true;
}
if (menu_select>=0) {
button2 =SerialReadButton(BUTTON2);
if ( button2) {
clk_time =rtc_time;
switch(menu_select) {
case MENU_NEXT:
case MENU_RESET:
if (nvram.water_duration) {
nvram .water_duration =1;
WaterScheduleTime();
}
water_time =NextScheduleTime((menu_select ==MENU_NEXT) ? water_time :rtc_time, &water_schedule);
break;
case MENU_WATER:
StartScheduleTime(water_time, water_schedule);
WaterScheduleTime();
break;
case MENU_CLOCK_MIN_PLUS:
clk_time +=SEC_IN_MIN;
Pause;
Fall MENU_CLOCK_MIN_MINUS:
clk_time -=SEC_IN_MIN;
Pause;
Fall MENU_CLOCK_HOUR_PLUS:
clk_time +=SEC_IN_HOUR;
Pause;
Fall MENU_CLOCK_HOUR_MINUS:
clk_time -=SEC_IN_HOUR;
Pause;
Fall MENU_ON_OFF:
nvram.state ^=STATE_ON_OFF;
update_nvram =true;
break;
}
if (clk_time !=rtc_time) {
if (SerialCmdDone(RTC_SENSOR)) {
localtime_r( &clk_time, &clk);
SerialWriteTime(&clk);
rtc_time =clk_time;
}
}
menu_time =rtc_time;
update_oled =true;
}
}
if (menu_select>=0 &&rtc_time - menu_time> MENU_TIME) {
menu_select =-1;
update_oled =true;
}

if (update_oled) {
if (S erialCmdNoError(ONEWIRE_TO_I2C_ROM1)) {
Serial.print("st10;so1;sc;sf0;sa0;sd0,0,\"");
if (nvram.water_duration) Serial.print(nvram. water_duration);
else {
if ((nvram.state &STATE_ON_OFF) ==OFF) Serial.print("OFF");
else if (rain <=RAIN_DETECT_LEVEL) Serial.print ("Regen");
else if (temp <=DO_NOT_WATER_TEMP) Serial.print ("Cold");
else Serial.print ("v1.1");
}
Serial.print("\";sf2;sa1;sd75,0,\"");
if (menu_select ==7) { // Sonnenaufgang
clk_time =nvram.sunrise_time;
localtime_r(&clk_time, &clk);
}
else clk =rtc;
Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0));
Seriendruck(":");
if (clk.tm_min <10) Seriendruck("0");
Seriendruck(clk.tm_min);
Serial.println("\"");
SerialReadUntilDone();

Serial.print("sf1;sa0;sd79,8,\"");
Serial .print((clk.tm_hour>12)?"PM":"AM");
Serial.print("\";sf0;sa1;sd127,1,\"");
Serial .print(Wochentag[clk.tm_wday]);
Seriendruck("\";sd127,13,\"");
Seriendruck(clk.tm_mon+1);
Seriendruck("/");
> Serial.print(clk.tm_mday);
Serial.println("\"");
SerialReadUntilDone();

Serial.print("sf0;sa0;sd1 .) ,36,\"");
i =schedule[water_schedule].zone;
if (i localtime_r(&water_time , &clk);
if (water_time - rtc_time> SEC_IN_DAY) {
Serial.print("\";sa1;sd126,36,\"");
Serial.print(clk. tm_mon+1);
Seriendruck("/");
Seriendruck(clk.tm_mday);
Seriendruck(" ");
Seriendruck (clk.tm_hour-((clk.tm_hour>12)?12:0));
Serial.print(":");
if (clk.tm_min <10) Serial.print(" 0");
Serial.print(clk.tm_min);
Serial.print(" ");
}
else {
Serial.print("\ ";sf1;sa1;sd111,30,\"");
Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0));
Serial.print( ":");
if (clk.tm_min <10) Serial.print("0");
Serial.print(clk.tm_min);
Seria l.print("\";sf0;sd126,36,\"");
}
Serial.print((clk.tm_hour>12)?"PM":"AM");
if (nvram.water_duration) Serial.print("\";so2;sc0,29,128,19");
Serial.println();
SerialReadUntilDone();

if (menu_select ==-1) {
//Serial.print("\";sa0;sd0,52,\"");
//Serial.print(rain);
SerialPrint("\";so1;sa2;sd63,52,\"", C2F(temp), error_temp);
if (!error_temp) Serial.print("\",248,\ ""
#ifdef FAHRENHEIT
"F"
#else
"C"
#endif
);
Serial.print(" /");
Serial.print(lux);
}
else {
Serial.print("\";so0;sc0,51,128,14;sf0;sa2; sd63,52,\"");
if (menu_select ==MENU_ON_OFF) {
Serial.print((nvram.state &STATE_ON_OFF) ? "OFF" :"ON");
}
else Serial.print(menu[menu_select]);
}
Serial.println("\";sd");
SerialReadUntilDone();
update_oled =false;
}
else init_oled =true;
}

if (update_nvram) {
if (SerialCmdNoError(I2C_EEPROM)) {
nvram.crc =crc8((uint8_t*)&nvram, sizeof(nvram)-sizeof(uint8_t));
//swSerial.println(nvram.crc , HEX);
SerialWriteEEPROM((uint8_t*)&nvram, 0, sizeof(nvram));
update_nvram =false;
}
}

delay(50);
}
else {
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
delay(500);
init_board =true;
init_oled =true;
}
wdt_reset();
}

Hinweis: Wenn Sie den USB-Port zum Programmieren des Arduino Nano verwenden, müssen Sie ihn vom IO-Expander trennen, da er auch denselben einzelnen seriellen Port verwendet. Wenn Sie stattdessen debuggen möchten, verwenden Sie den ICSP-Port zum Programmieren des ATmega328P. Um den Software-Debugging-Port zu aktivieren, entkommentieren Sie die SERIAL_DEBUG-Definition.

Der Splitter muss zuerst so konfiguriert werden, dass er die Datenleitung des optischen Infrarotsensors von der 1-Wire-Fernsensorleitung trennt. Löten Sie einen Null-Ohm-0603-Widerstand an R2 ein.

Bohren Sie ein 7/16" Loch in das kleine Gehäuse und ein 11/16" Loch in das größere Gehäuse auf der rechten Seite für das PG7 und PG11. Verwenden Sie ein Dremel-Werkzeug, um die Löcher leicht zu vergrößern, bis die Drüse fest sitzt. Das PG7 speist die Fernsensoren und das PG11 für die 12 VDC, 24 VAC, Verteilerkabel und das RJ11-Fernsensorkabel ein.

Verdrahten Sie den SPST-Taster-Mikroschalter und schließen Sie ihn an die RJ11-Schraubklemme an. Verwenden Sie Schrumpfschläuche, um die Kontakte zu isolieren.

Schließen Sie alle Drähte an und montieren / führen Sie alle Teile in das große Gehäuse ein. Ihr 50-Fuß-RJ11-Kabel für die Fernsensoren sollte gerade durch die PG11-Verschraubung passen, ohne es schneiden zu müssen.

Bohren Sie ein 9/16"-Loch in die Oberseite des kleinen Gehäuses für den optischen Infrarot-Wassersensor. Verwenden Sie ein Dremel-Werkzeug, um das Loch leicht zu vergrößern, bis der Sensor passt. Das kleine Gehäuse des Fernbedienungssensors sitzt fest, aber wenn der Inhalt werden in der empfohlenen Ausrichtung verlegt, es sollte gerade passen. Die RJ11-Drähte so kurz wie möglich zu machen, hilft dabei, alles in das kleinere Gehäuse zu stopfen. Nach dem Zusammenbau wird empfohlen, vor dem Anschrauben der Mutter etwas Schiffskleber in die Unterlegscheibe der Stopfbuchsenmutter zu geben. um eine bessere Abdichtung zu schaffen.

Installieren Sie das Gehäuse des Fernbedienungssensors im Freien und montieren Sie es erhöht an der Ostseite Ihres Hauses, wobei der optische Infrarot-Wassersensor und der Lichtsensor ohne Hindernisse in den Himmel zeigen.

Bohren Sie 1/4" Löcher in die obere mittlere Unterseite des großen Gehäuses und montieren Sie die Knöpfe. Verwenden Sie ein Dremel-Werkzeug, um das Loch leicht zu vergrößern, bis die Knöpfe passen.

Testen Sie das System und stellen Sie sicher, dass alles richtig funktioniert. Um das Relais und die Sensoren zu testen, trennen Sie das Arduino vom IO-Expander und verbinden Sie es direkt mit Ihrem Computer, um es manuell zu steuern. Sobald Sie überprüft haben, dass alles funktioniert, montieren Sie alle Teile mit doppelseitigem Klebeband und Verpackungsschaum in das Gehäuse, um Ihre Boards zu sichern, und genießen Sie die Vorteile und Einsparungen Ihres Smart Irrigation Controllers.

Video in Betrieb

Update 12.09.2019

Veröffentlichung von v1.1, die ein Startproblem behebt, wenn das System mehrere Tage lang die Stromversorgung verliert.

Update 02.10.2019

Wenn Sie 1-Wire an I2C an den DS3231 und dann an den SSD1306 OLED-Bildschirm anschließen, haben Sie insgesamt drei verschiedene Pullups auf den SDA- und SCL-Leitungen, wie in der Abbildung unten eingekreist. Dies führt effektiv zu einem Pullup von 4,7k / 3 =1,56k, der zu stark sein und zu zufälligen Bildschirmbeschädigungen führen kann.

Da der DS3231 ein Widerstandspaket verwendet, das von anderen Leitungen verwendet wird, entfernen Sie die anderen Pullup-Widerstände:

  • 1-Draht zu I2C R3 und R4.
  • SSD1306 OLED R6 und R7.

Code

  • Intelligenter Bewässerungscontroller
Smart Irrigation ControllerC/C++
Verwenden Sie Ihr Arduino, um Ihren Garten oder Garten intelligent zu bewässern.
/* IO-Expander-Skizze optimiert * * Bewässerungssystem v1.1 * */#include #include  // Datei befindet sich \Program Files (x86)\Arduino\hardware\tools\avr\avr\include\time.h#include #include #include #include "IOExpander. h"#define FAHRENHEIT#define INIT_BOARD "g5w1;g11w1;g11d0,75;g12w1;g12d0,75;rsf"#define ONEWIRE_TO_I2C_ROM1 "i4scc"#te_define ONEWIRE_TO_I2C_ROM2"SEN0,SOR0,"TEMPineR ONEtine"#define define I2C_EEPROM "s4tf"#define I2C_OLED "s4t10"#define I2C_LIGHT "s3t9;sc0"#define OPTICAL_SENSOR "g5a"#define BUTTON1 "g11d"#define BUTTON2 "g12d"#define WATER_NRISE_60#define_SU define DO_NOT_WATER_TEMP 4.4444 // 40F#define MAX_ZONES 4#define HOUR_IN_DAY 24L#define MIN_IN_HOUR 60L#define SEC_IN_MIN 60L#define SEC_IN_HOUR (MIN_IN_HOUR * SEC_IN_MIN)#define SEC_IN_DAYHOUR_IN_DAY (HOUR) OUR)#define DAYS_IN_WEEK 7#define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK)#define SO 0x01#define MON 0x02#define DI 0x04#define WED 0x08#define THR 0x10#define FR 0x20#define SATine 0x40 MO | DI | MI | THR | FR | SAT)#define SUNRISE 0x80#define MENU_OPTIONS 9#define MENU_TIME 30#define OFF 0#define ON 1#define STATE_ON_OFF 0x01//#define SERIAL_DEBUG#ifdef SERIAL_DEBUGSoftwareSerial swSerial(8,7);#endifchar Wochentag[][4] ={"SUN","MO","DI","MI","THU","FRI","SA"};char menu[][13] ={"Next", "Water", "Reset" , "Clock Min +", "Clock Min -", "Clock Hour +", "Clock Hour -", "Sunrise", "ON/OFF"};enum { MENU_NEXT, MENU_WATER, MENU_RESET, MENU_CLOCK_MIN_PLUS, MENU_CLOCK_MIN_MINUS, MENU_CLOCK_HOUR_PLUS, MENU_CLOCK_HOUR_MINUS, MENU_SUNRISE, MENU_ON_OFF};typedef struct { Zeichenbeschreibung[16]; uint8_t Relay;} ZONE;typedef struct { uint8_t zone; uint8_t Tage; int8_t Stunde; int8_t min; uint8_t Dauer;} SCHEDULE;typedef struct { time_t sunrise_time; time_t letzte_water_time; uint8_t water_schedule; uint8_t Wasser_Dauer; uint8_t Regen[MAX_ZONES]; uint8_t-Zustand; uint8_t crc;} NVRAM;enum { ZONE1, ZONE2, ZONE3, ZONE4};enum { RELAY1 =1, RELAY2, RELAY3, RELAY4};ZONE zone[] ={ {"Front Right", RELAY1}, {"Front Left" , RELAY2}, {"Büsche", RELAY3}, {"Linke Seite", RELAY4},};ZEITPLAN Zeitplan[] ={ {ZONE1, SONNENAUFGANG | EVERYDAY, -1, 0, 4}, {ZONE2, EVERYDAY, 6, 15, 5}, {ZONE3, EVERYDAY, 6, 0, 10}, {ZONE4, EVERYDAY, 6, 10, 6},}; NVRAM nvram;bool update_nvram =false;uint8_t crc8(uint8_t* Daten, uint16_t Länge){ uint8_t crc =0; while (Länge--) { crc =_crc8_ccitt_update(crc, *data++); } return crc;}int led =13;bool init_oled =true;bool update_oled =true;bool init_board =true;#ifdef FAHRENHEIT#define C2F(temp) CelsiusToFahrenheit(temp)float CelsiusToFahrenheit(float celsius){ return ((celsius * 9) / 5) + 32;} #else #define C2F (temp) (temp) #endifvoid SerialPrint (const char * str, float decimal, char error) {Serial.print (str); if (Fehler) Serial.print (F ("NA")); sonst Serial.print (dezimal, 1);} time_t NextScheduleTime (time_t last_time, uint8_t* next_schedule) {time_t next_time =-1; time_t clk_time; uint8_t i; tm clk; uint8_t wday; for (i =0; i  SAMSDAY) wday =SONNTAG; if (wday ==clk.tm_wday) Pause; // Nur eine Woche prüfen } if (clk_time  0) { if (nvram.rain[i]> nvram.water_duration) nvram.water_duration =0; sonst nvram.water_duration -=nvram.rain[i]; nvram.rain[i] =0; }}void WaterScheduleTime (void) { uint8_t i; nvram.water_duration--; update_nvram =wahr; i =Zeitplan[nvram.water_schedule].zone; wenn (i  0) Serial.println ("o"); sonst Serial.println("f"); SerialReadUntilDone(); }}void setup () { Serial.begin (115200); #ifdef SERIAL_DEBUG swSerial.begin (115200); #endif pinMode (led, OUTPUT); // Verzögerung (1000); wdt_enable (WDTO_8S);}void loop () { static tm rtc; tm clk, sunrise_clk; time_t rtc_time; time_t clk_time; statische time_t next_time; statisch uint8_t last_sec; statisch uint8_t last_min; bool error_rtc; bool error_light; bool error_temp; statisch lang lux =0; statische Schwimmertemperatur, Regen; statisch uint8_t sunrise_counter =MIN_IN_HOUR; static bool check_sunrise =false; uint8_t i; static bool read_nvram =true; statische time_t water_time; statisch uint8_t water_schedule; uint8_t sz; uint8_t wday; langes n; bool button1, button2; statisch int8_t menu_select =-1; statische time_t menu_time =0; Serial.println(); if (SerialReadUntilDone()) { if (init_board) { SerialCmdDone (INIT_BOARD); init_board =false; } if (init_oled) { if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM1)) { SerialCmdDone(I2C_OLED ";si;sc;sd"); init_oled =false; } } if (SerialCmdDone(RTC_SENSOR)) { error_rtc =!SerialReadTime(&rtc); if (!error_rtc) { clk =rtc; // mktime() can change struct tm rtc_time =mktime(&clk); localtime_r(&rtc_time, &rtc); // Get wday. } if (read_nvram) { if (SerialCmdNoError(I2C_EEPROM)) { SerialReadEEPROM((uint8_t*)&nvram, 0, sizeof(nvram)); if (nvram.crc !=crc8((uint8_t*)&nvram, sizeof(nvram)-sizeof(uint8_t))) { //swSerial.println("CRC8 Failure!"); // Initialize nvram memset(&nvram, 0, sizeof(nvram)); clk =rtc; clk.tm_hour =6; clk.tm_min =0; clk.tm_sec =0; nvram.sunrise_time =mktime(&clk); if (nvram.sunrise_time  SEC_IN_WEEK) nvram.last_water_time =rtc_time - SEC_IN_WEEK; // Check sunrise time if (rtc_time> nvram.sunrise_time) { localtime_r(&nvram.sunrise_time, &sunrise_clk); clk =rtc; clk.tm_hour =sunrise_clk.tm_hour; clk.tm_min =sunrise_clk.tm_min; clk.tm_sec =sunrise_clk.tm_sec; nvram.sunrise_time =mktime(&clk); if (nvram.sunrise_time  0) sunrise_counter--; else check_sunrise =true; } else { if (sunrise_counter =MENU_OPTIONS) menu_select =0; } menu_time =rtc_time; update_oled =true; } if (menu_select>=0) { button2 =SerialReadButton(BUTTON2); if (button2) { clk_time =rtc_time; switch(menu_select) { case MENU_NEXT:case MENU_RESET:if (nvram.water_duration) { nvram.water_duration =1; WaterScheduleTime(); } water_time =NextScheduleTime((menu_select ==MENU_NEXT) ? water_time :rtc_time, &water_schedule); brechen; case MENU_WATER:StartScheduleTime(water_time, water_schedule); WaterScheduleTime(); brechen; case MENU_CLOCK_MIN_PLUS:clk_time +=SEC_IN_MIN; brechen; case MENU_CLOCK_MIN_MINUS:clk_time -=SEC_IN_MIN; brechen; case MENU_CLOCK_HOUR_PLUS:clk_time +=SEC_IN_HOUR; brechen; case MENU_CLOCK_HOUR_MINUS:clk_time -=SEC_IN_HOUR; brechen; case MENU_ON_OFF:nvram.state ^=STATE_ON_OFF; update_nvram =true; brechen; } if (clk_time !=rtc_time) { if (SerialCmdDone(RTC_SENSOR)) { localtime_r(&clk_time, &clk); SerialWriteTime(&clk); rtc_time =clk_time; } } menu_time =rtc_time; update_oled =true; } } if (menu_select>=0 &&rtc_time - menu_time> MENU_TIME) { menu_select =-1; update_oled =true; } if (update_oled) { if (SerialCmdNoError(ONEWIRE_TO_I2C_ROM1)) { Serial.print("st10;so1;sc;sf0;sa0;sd0,0,\""); if (nvram.water_duration) Serial.print(nvram.water_duration); else { if ((nvram.state &STATE_ON_OFF) ==OFF) Serial.print("OFF"); else if (rain <=RAIN_DETECT_LEVEL) Serial.print("Rain"); else if (temp <=DO_NOT_WATER_TEMP) Serial.print("Cold"); else Serial.print("v1.1"); } Serial.print("\";sf2;sa1;sd75,0,\""); if (menu_select ==7) { // Sunrise clk_time =nvram.sunrise_time; localtime_r(&clk_time, &clk); } else clk =rtc; Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0)); Serial.print(":"); if (clk.tm_min <10) Serial.print("0"); Serial.print(clk.tm_min); Serial.println("\""); SerialReadUntilDone(); Serial.print("sf1;sa0;sd79,8,\""); Serial.print((clk.tm_hour>12)?"PM":"AM"); Serial.print("\";sf0;sa1;sd127,1,\""); Serial.print(weekday[clk.tm_wday]); Serial.print("\";sd127,13,\""); Serial.print(clk.tm_mon+1); Serial.print("/"); Serial.print(clk.tm_mday); Serial.println("\""); SerialReadUntilDone(); Serial.print("sf0;sa0;sd1,36,\""); i =schedule[water_schedule].zone; if (i  SEC_IN_DAY) { Serial.print("\";sa1;sd126,36,\""); Serial.print(clk.tm_mon+1); Serial.print("/"); Serial.print(clk.tm_mday); Serial.print(" "); Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0)); Serial.print(":"); if (clk.tm_min <10) Serial.print("0"); Serial.print(clk.tm_min); Serial.print(" "); } else { Serial.print("\";sf1;sa1;sd111,30,\""); Serial.print(clk.tm_hour-((clk.tm_hour>12)?12:0)); Serial.print(":"); if (clk.tm_min <10) Serial.print("0"); Serial.print(clk.tm_min); Serial.print("\";sf0;sd126,36,\""); } Serial.print((clk.tm_hour>12)?"PM":"AM"); if (nvram.water_duration) Serial.print("\";so2;sc0,29,128,19"); Serial.println(); SerialReadUntilDone(); if (menu_select ==-1) { //Serial.print("\";sa0;sd0,52,\""); //Serial.print(rain); SerialPrint("\";so1;sa2;sd63,52,\"", C2F(temp), error_temp); if (!error_temp) Serial.print("\",248,\"" #ifdef FAHRENHEIT "F" #else "C" #endif ); Serial.print(" / "); Serial.print(lux); } else { Serial.print("\";so0;sc0,51,128,14;sf0;sa2;sd63,52,\""); if (menu_select ==MENU_ON_OFF) { Serial.print((nvram.state &STATE_ON_OFF) ? "OFF" :"ON"); } else Serial.print(menu[menu_select]); } Serial.println("\";sd"); SerialReadUntilDone(); update_oled =false; } else init_oled =true; } if (update_nvram) { if (SerialCmdNoError(I2C_EEPROM)) { nvram.crc =crc8((uint8_t*)&nvram, sizeof(nvram)-sizeof(uint8_t)); //swSerial.println(nvram.crc, HEX); SerialWriteEEPROM((uint8_t*)&nvram, 0, sizeof(nvram)); update_nvram =false; } } delay(50); } else { digitalWrite(led, HIGH); delay(500); digitalWrite(led, LOW); delay(500); init_board =true; init_oled =true; } wdt_reset();}

Schaltpläne

Intelligently water your yard or garden

Herstellungsprozess

  1. Entwerfen von Open-Source-Smart-Farming-Systemen
  2. Smart Sensor Board beschleunigt die Entwicklung von Edge-KI
  3. 433 MHz Smart Home Controller mit Sensorflare und einem RaspberryPi
  4. Raspberry Pi-Temperatursensor
  5. Mobiles IoT:Intelligenter Mülleimer
  6. Smart Barkeeper
  7. Emotionssensor / EEG
  8. Win10 IOT-Bewässerungssteuerung mit Feuchtigkeitssensoren
  9. Ultraempfindlicher, widerstandsfähiger Sensor für intelligente Textilien
  10. Ultradünner Sensor für intelligente Kontaktlinsen