Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

Contrôleur d'irrigation intelligent

Composants et fournitures

Arduino Nano R3
× 1
Extenseur IO
× 1
Bundle d'extension d'IO
× 1

Applications et services en ligne

Arduino IDE

À propos de ce projet

Créez un contrôleur d'irrigation intelligent avec Arduino

Irriguez intelligemment votre jardin avec des cycles d'eau dynamiques. Arrêtez d'arroser votre jardin s'il pleut ou s'il a plu depuis votre dernier arrosage. Utilisez le capteur de lumière pour détecter l'heure du lever du soleil et ajustez automatiquement les heures de démarrage de l'eau en conséquence. Arrêtez d'arroser votre jardin s'il fait trop froid.

Liste des fonctionnalités

  • Capteur de température extérieure
  • Capteur de pluie extérieur
  • Capteur de lumière extérieure
  • Horloge en temps réel avec batterie pour la programmation hebdomadaire
  • Stockage non volatile - ne perdez jamais un arrosage en raison d'une panne de courant
  • Détection de lever de soleil
  • L'arrosage intelligent permet d'économiser sur votre facture d'eau
  • Arrosez avant le lever du soleil pour permettre un temps de trempage approprié
  • Arrêtez d'arroser quand il fait trop froid dehors
  • Réduire la croissance des champignons
  • Contrôle facile des horaires

Pièces nécessaires pour construire le contrôleur d'irrigation intelligent

  • Extenseur d'E/S
  • x2 1-Wire vers I2C.
  • Jonction à 1 fil
  • Connecteur optique
  • Séparateur
  • Arduino Nano.
  • Relais CC 5 V à 4 canaux.
  • Capteur de lumière TSL2561.
  • Capteur de température étanche DS18B20.
  • Capteur de niveau d'eau infrarouge optique.
  • DS3231 AT24C32 IIC Horloge temps réel de précision.
  • Écran I2C SSD1306 OLED 128 x 64.
  • Boîtier en plastique transparent étanche de 200 x 120 x 75 mm.
  • Boîtier en plastique transparent étanche de 100 x 68 x 50 mm.
  • Presse-étoupe en nylon étanche ip68 pg7.
  • Presse-étoupe en nylon étanche ip68 pg11.
  • Prise de borne à vis Keystone RJ11.
  • Câble RJ11 4C4P 50 ft.
  • Câble RJ11 4C4P de 1,8 m.
  • Fil d'en-tête de 2,54 mm.
  • x2 micro-interrupteur à bouton-poussoir momentané SPST à 2 broches
  • Alimentation pour adaptateur mural 12VDC 1A.

Schéma de câblage

Écran OLED

Appuyez sur le bouton Menu pour afficher le menu et continuez d'appuyer sur le bouton pour parcourir toutes les options du menu. Le menu sera automatiquement supprimé après 30 secondes d'inactivité. Appuyez sur le bouton Select pour exécuter la fonction de menu souhaitée.

Alors pourquoi utiliser l'extension IO ?

  • Plus simple à concevoir
  • Pièces du commerce
  • Pas de pilote 1-Wire à écrire
  • Pas de pilote DS3231 RTC à écrire
  • Aucun pilote EEPROM à écrire
  • Aucun pilote d'affichage OLED à écrire
  • Pas de polices d'affichage pour occuper l'espace de code Arduino
  • Aucun pilote de capteur de température à écrire
  • Aucun lecteur de capteur de pluie optique à écrire
  • Économise de l'espace de code sur Arduino ; seulement 12710 octets (39%)
  • Seulement trois jours pour écrire le code
  • Facile à câbler à l'aide d'un câble téléphonique RJ11 standard
  • Aucun problème de longueur de câble de capteur
  • Moins cher à construire que des systèmes commerciaux similaires
  • Facile à apporter des modifications pour s'adapter aux besoins individuels
  • Alimentation simple

Construire le système

Connectez l'Arduino Nano à l'extenseur IO et programmez-le avec le code suivant. L'en-tête à 6 broches est le port de débogage série du logiciel et n'est pas nécessaire dans l'installation finale.

Assurez-vous de modifier l'adresse définie ONEWIRE_TO_I2C_ROM1 et ONEWIRE-TO_I2C_ROM2 pour qu'elle corresponde à votre adresse 1-Wire vers I2C.

/* Esquisse d'extension IO optimisée
*
* Système d'irrigation v1.1
*
*/

#include
#include // Fichier situé \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"
#define ONEWIRE_TO_I2C_ROM2 "i6s8/> "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 Y 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)
#IN_WEEK DAYS
#define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK)

#define SUN 0x01
#define MON 0x02
#define TUE 0x04
#define WED 0x08
#define THR 0x10
#define VEN 0x20
#define SAT 0x40
#define TOUS LES JOURS (SUN | LUN | MAR | MER | THR | VEN | SAM)

#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_DEBUG
SoftwareSerial swSerial(8,7 );
#endif

char jour de la semaine[][4] ={"DIM","LUN","MAR","MER","JEU","VEN"," 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 jours;
int8_t heure;
int8_t min;
uint8_t durée;
} 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 {
RELAIS1 =1,
RELAIS2,
RELAIS3,
RELAIS4
} ;

ZONE zone[] ={
{"Avant Droit", RELAIS1},
{"Avant Gauche", RELAIS2},
{"Buissons", RELAIS3},
{"Côté gauche", RELAIS4},
} ;

HORAIRE horaire[] ={
{ZONE1, LEVER DU SOLEIL | TOUS LES JOURS, -1, 0, 4},
{ZONE2, TOUS LES JOURS, 6, 15, 5},
{ZONE3, TOUS LES JOURS, 6, 0, 10},
{ZONE4, TOUS LES JOURS , 6, 10, 6},
};

NVRAM nvram;
bool update_nvram =false;

uint8_t crc8(uint8_t* data, uint16_t longueur)
{
uint8_t crc =0;

while (longueur--) {
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) CelsiusÀFahrenheit(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(decimal, 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;

pour (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 =schedule[i].hour;
clk.tm_min =schedule[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;
si (++wday> SAMEDI) wday =DIMANCHE;
si (wday ==clk.tm_wday) pause ; // Ne vérifie qu'une semaine
}
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;
// Vérifier s'il a plu
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);
}

boucle vide() {
static tm rtc;
tm clk, sunrise_clk;
time_t rtc_time;
time_t clk_time;
static 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() peut changer la structure tm
rtc_time =mktime(&clk);
localtime_r(&rtc_time, &rtc); // Obtenir 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 ! ");
// Initialise 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 update_nvram =true;
}
// Vérifier l'heure du dernier point d'eau au moins une semaine
if (rtc_time - nvram.last_water_time> SEC_IN_WEEK) nvram.last_water_time =rtc_time - SEC_IN_WEEK;
// Vérifier l'heure du lever du soleil
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;
}
}
}

// Traiter une seule fois par minute
if (rtc.tm_min !=last_min)
{
// Demander une mesure de température 1-Wire. Lisez-le plus tard.
error_temp =!SerialCmdNoError(ONEWIRE_TEMPERATURE);
if (!error_temp) SerialCmdDone("tt");

error_light =!SerialCmdNoError(ONEWIRE_TO_I2C_ROM2 ";oo0" );
if (!error_light) {
SerialCmdDone(I2C_LIGHT); // Ne pas utiliser overdrive
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();
}

// Est-ce le lever du soleil ?
if (lux if (sunrise_counter> 0) sunrise_counter--;
else check_sunrise =true;
}
else {
si (sunrise_counter sunrise_counter++;
if (check_sunrise &&sunrise_counter ==MIN_IN_HOUR) {
nvram.sunrise_time =rtc_time + (SEC_IN_DAY - SEC_IN_HOUR);
check;_sun
update_nvram =true;
}
}
}

// Il pleut ?
if (pluie <=RAIN_DETECT_LEVEL) {
pour (i =0; i si (nvram.rain[i] <-1) nvram.rain[i]++; }
update_nvram =true;
}

// Vérifier le calendrier
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;
}
}

// Avons-nous besoin d'arroser ?
si (nvram.water_duration) {
WaterScheduleTime();
if (!nvram.water_duration)
water_time =NextScheduleTime(water_time, &water_schedule);
}

last_min =rtc.tm_min;
update_oled =true;
}

// Vérifier les boutons
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 ;
cas MENU_CLOCK_MIN_MINUS :
clk_time -=SEC_IN_MIN;
pause ;
cas MENU_CLOCK_HOUR_PLUS :
clk_time +=SEC_IN_HOUR;
break;
case MENU_CLOCK_HOUR_MINUS:
clk_time -=SEC_IN_HOUR;
break;
case 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;
}

si (update_oled) {
si (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 ("Rain");
else if (temp <=DO_NOT_WATER_TEMP) Serial.print("Froid");
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 localtime_r(&water_time , &clk);
if (water_time - rtc_time> 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);
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();
}

Remarque : Si vous utilisez le port USB pour programmer l'Arduino Nano, vous devez le déconnecter de l'extenseur IO car il utilise également le même port série unique, à la place, si vous souhaitez déboguer, utilisez le port ICSP pour programmer l'ATmega328P. Pour activer le port de débogage du logiciel, décommentez la définition SERIAL_DEBUG.

Le répartiteur doit d'abord être configuré pour isoler la ligne de données du capteur infrarouge optique de la ligne du capteur à distance 1-Wire. Souder dans une résistance 0 ohm 0603 à R2.

Percez un trou de 7/16" dans le petit boîtier et un trou de 11/16" dans le plus grand boîtier du côté droit pour les PG7 et PG11. Utilisez un outil Dremel pour agrandir légèrement les trous jusqu'à ce que le presse-étoupe soit bien ajusté. Le PG7 alimentera les capteurs à distance et le PG11 pour les fils 12VDC, 24VAC, du collecteur et le fil des capteurs à distance RJ11.

Câblez le micro-interrupteur à bouton-poussoir momentané SPST et connectez-le à la borne à vis RJ11. Utilisez une gaine thermorétractable pour isoler les contacts.

Connectez tous les fils et assemblez/alimentez toutes les pièces dans le grand boîtier. Votre fil RJ11 de 50 pieds pour les capteurs à distance doit simplement passer à travers le presse-étoupe PG11 sans avoir à le couper.

Percez un trou de 9/16" dans la partie supérieure du petit boîtier pour le capteur d'eau infrarouge optique. Utilisez un outil Dremel pour agrandir légèrement le trou jusqu'à ce que le capteur s'adapte. Le petit boîtier du capteur à distance est bien ajusté, mais si le contenu sont posés dans l'orientation recommandée, il doit juste s'adapter. Rendre les fils RJ11 aussi courts que possible aidera à tout entasser dans le plus petit boîtier. Une fois assemblé, il est recommandé d'ajouter de la colle marine dans la rondelle de l'écrou du presse-étoupe avant de visser l'écrou, pour créer une meilleure étanchéité.

Installez le boîtier du capteur à distance à l'extérieur et montez-le sur le côté est de votre maison avec le capteur d'eau infrarouge optique et le capteur de lumière pointant vers le ciel sans obstruction.

Percez des trous de 1/4" en haut au milieu et en bas du grand boîtier et montez les boutons. Utilisez un outil dremel pour agrandir légèrement le trou jusqu'à ce que les boutons s'emboîtent.

Testez le système et assurez-vous que tout fonctionne correctement. Pour tester le relais et les capteurs, déconnectez l'Arduino de l'extenseur IO et connectez-le directement à votre ordinateur pour le contrôler manuellement. Une fois que vous avez vérifié que tout fonctionne, assemblez toutes les pièces dans l'enceinte à l'aide de ruban adhésif double face et de mousse d'emballage pour sécuriser vos planches, et profitez des avantages et des économies de votre contrôleur d'irrigation intelligent.

Vidéo en fonctionnement

Mise à jour 9/12/2019

Sortie de la v1.1 qui corrigeait un problème de démarrage si le système perdait de l'énergie pendant plusieurs jours.

Mise à jour 02/10/2019

Lors de la connexion du 1-Wire à I2C au DS3231, puis à l'écran OLED SSD1306, vous aurez un total de trois pullups différents sur les lignes SDA et SCL, comme indiqué dans l'image ci-dessous encerclée. Cela entraînera effectivement un pullup de 4,7k/3 =1,56k qui peut être trop fort et entraîner des corruptions d'écran aléatoires.

Étant donné que le DS3231 utilise un pack de résistances utilisé par d'autres lignes, supprimez les autres résistances de rappel :

  • 1-Wire vers I2C R3 et R4.
  • SSD1306 OLED R6 et R7.

Code

  • Contrôleur d'irrigation intelligent
Contrôleur d'irrigation intelligentC/C++
Utilisez votre Arduino pour arroser intelligemment votre cour ou votre jardin.
/* IO Expander sketch optimisé * * Irrigation System v1.1 * */#include #include  // Fichier situé \Program Fichiers (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 "i603TC_8f"define"#603TC800WENSte" 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_NRECT_BEFORE_SU#define WATER_NRECT_BEFORE_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_DAY (HOUR_IN_HOUR OUR)#define DAYS_IN_WEEK 7#define SEC_IN_WEEK (SEC_IN_DAY * DAYS_IN_WEEK)#define SUN 0x01#define MON 0x02#define TUE 0x04#define WED 0x08#define THR 0x10#define FRI 0x20#define SAT 0x40DAY LUN | MAR | MER | THR | VEN | 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 weekday[][4] ={"SUN","MON","MAR","MER","JEU","VEN","SAT"};char menu[][13] ={"Suivant", "Eau", "Réinitialiser" , "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 jours ; int8_t heure ; int8_t min; uint8_t duration;} SCHEDULE;typedef struct { time_t sunrise_time; time_t last_water_time; uint8_t water_schedule; uint8_t water_duration; uint8_t pluie[MAX_ZONES] ; état uint8_t ; uint8_t crc;} NVRAM;enum { ZONE1, ZONE2, ZONE3, ZONE4};enum { RELAIS1 =1, RELAIS2, RELAIS3, RELAIS4};ZONE zone[] ={ {"Avant droit", RELAIS1}, {"Avant gauche" , RELAIS2}, {"Buissons", RELAIS3}, {"Côté gauche", RELAIS4},};HORAIRE horaire[] ={ {ZONE1, LEVER DU SOLEIL | TOUS LES JOURS, -1, 0, 4}, {ZONE2, TOUS LES JOURS, 6, 15, 5}, {ZONE3, TOUS LES JOURS, 6, 0, 10}, {ZONE4, TOUS LES JOURS, 6, 10, 6},} ; NVRAM nvram;bool update_nvram =false;uint8_t crc8 (données uint8_t*, longueur uint16_t){ uint8_t crc =0; while (longueur--) { 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 (erreur) Serial.print(F("NA")); else Serial.print(décimal, 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 jour; for (i =0; i  SAMEDI) wday =DIMANCHE; if (wday ==clk.tm_wday) pause ; // Ne vérifie qu'une semaine } if (clk_time  0) { if (nvram.rain[i]> nvram.water_duration) nvram.water_duration =0; sinon nvram.water_duration -=nvram.rain[i]; nvram.rain[i] =0; }}void WaterScheduleTime(void) { uint8_t i; nvram.water_duration--; update_nvram =vrai; i =planning[nvram.water_schedule].zone; if (i  0) Serial.println("o"); else Serial.println("f"); SerialReadUntilDone(); }}void setup() { Serial.begin(115200);#ifdef SERIAL_DEBUG swSerial.begin(115200);#endif pinMode(led, OUTPUT); //délai(1000); wdt_enable(WDTO_8S);}boucle vide() { tm rtc statique ; tm clk, sunrise_clk; time_t rtc_time; time_t clk_time; statique time_t next_time; statique uint8_t last_sec; statique uint8_t last_min; bool error_rtc; bool error_light; bool error_temp; lux long statique =0 ; température du flotteur statique, pluie; statique uint8_t sunrise_counter =MIN_IN_HOUR; static bool check_sunrise =false; uint8_t i; static bool read_nvram =true; statique time_t water_time; statique uint8_t water_schedule ; uint8_t sz; uint8_t jour; long n; bool bouton1, bouton2; statique int8_t menu_select =-1; static time_t menu_time =0; Serial.println(); if (SerialReadUntilDone()) { if (init_board) { SerialCmdDone(INIT_BOARD); init_board =faux ; } 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); Pause; case MENU_WATER:StartScheduleTime(water_time, water_schedule); WaterScheduleTime(); Pause; case MENU_CLOCK_MIN_PLUS:clk_time +=SEC_IN_MIN; Pause; case MENU_CLOCK_MIN_MINUS:clk_time -=SEC_IN_MIN; Pause; case MENU_CLOCK_HOUR_PLUS:clk_time +=SEC_IN_HOUR; Pause; case MENU_CLOCK_HOUR_MINUS:clk_time -=SEC_IN_HOUR; Pause; case MENU_ON_OFF:nvram.state ^=STATE_ON_OFF; update_nvram =true; Pause; } 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();}

Schémas

Intelligently water your yard or garden

Processus de fabrication

  1. Concevoir des systèmes d'agriculture intelligents open source
  2. La carte de capteur intelligent accélère le développement de l'IA de pointe
  3. Contrôleur Smart Home 433MHz avec Sensorflare et RaspberryPi
  4. Capteur de température Raspberry Pi
  5. IdO cellulaire :poubelle intelligente
  6. Barman intelligent
  7. Capteur d'émotion/EEG
  8. Contrôleur d'irrigation Win10 IOT avec capteurs d'humidité
  9. Capteur ultra-sensible et résilient pour les textiles intelligents