スマート灌漑コントローラー
コンポーネントと消耗品
> |
| × | 1 | |||
| × | 1 | ||||
| × | 1 |
アプリとオンラインサービス
> |
|
このプロジェクトについて
Arduinoでスマート灌漑コントローラーを作成する
動的な水循環で庭をインテリジェントに灌漑します。雨が降っている場合、または最後の水やり以降に雨が降った場合は、庭への水やりをやめてください。光センサーを使用して日の出時刻を検出し、それに応じて水の開始時刻を自動的に調整します。寒すぎる場合は、庭に水をやるのをやめてください。
機能リスト
- 外気温センサー
- 外部雨センサー
- 外光センサー
- 毎週のスケジュール設定用の電池式リアルタイムクロック
- 不揮発性ストレージ-電力損失のために散水を失うことはありません
- 日の出の検出
- スマートな散水は水道代を節約します
- 適切な浸漬時間を確保するために、日の出前に水をまきます
- 外が寒すぎるときは水やりをやめてください
- 真菌の増殖を抑える
- 簡単なスケジュール管理
スマート灌漑コントローラーを構築するために必要な部品
- IOエキスパンダー
- x21-I2Cに配線します。
- 1-Wireジャンクション
- 光コネクタ
- スプリッター
- ArduinoNano。
- 4チャンネルDC5Vリレー。
- TSL2561光センサー。
- DS18B20防水温度センサー。
- 光学式赤外線水位センサー。
- DS3231 AT24C32IIC高精度リアルタイムクロック。
- I2C SSD1306 OLED128x64ディスプレイ。
- 200x120x75mmの透明な防水プラスチックエンクロージャ。
- 100x68x50mmの透明な防水プラスチックエンクロージャ。
- ip68pg7防水ナイロンケーブルグランド。
- ip68pg11防水ナイロンケーブルグランド。
- RJ11キーストーンネジ留め式端子ジャック。
- 50フィート4C4PRJ11ワイヤー。
- 6フィート4C4PRJ11ワイヤー。
- 2.54mmヘッダーワイヤー。
- x22ピンSPSTモーメンタリプッシュボタンマイクロスイッチ
- 12VDC1Aウォールアダプター電源。
配線図 <図>
OLEDディスプレイ <図>
メニューボタンを押してメニューを表示し、ボタンを押し続けるとすべてのメニューオプションが切り替わります。メニューは、30秒間操作がないと自動的に削除されます。選択ボタンを押して、目的のメニュー機能を実行します。
では、なぜIOエキスパンダーを使用するのですか?
- 設計が簡単
- 既製の部品
- 書き込む1-Wireドライバーはありません
- 書き込むDS3231RTCドライバーはありません
- 書き込むEEPROMドライバーがありません
- 書き込むOLEDディスプレイドライバーはありません
- Arduinoコードスペースを取るための表示フォントはありません
- 書き込む温度センサードライバーがありません
- 書き込み用の光学式雨センサー乾燥機はありません
- Arduinoのコードスペースを節約します。わずか12710バイト(39%)
- コードを書くのにたった3日
- 標準のRJ11電話ケーブルを使用して簡単に配線できます
- センサーケーブルの長さの問題はありません
- 同様の商用システムよりも構築が安価
- 個々の要件に合わせて簡単に変更できます
- 単一電源
システムを構築する
ArduinoNanoをIOExpanderに接続し、次のコードでプログラムします。 6ピンヘッダーはソフトウェアのシリアルデバッグポートであり、最終的なインストールでは必要ありません。
<図>ONEWIRE_TO_I2C_ROM1およびONEWIRE-TO_I2C_ROM2で定義されたアドレスを、1-WireからI2Cアドレスに一致するように変更してください。
/ * IOエキスパンダースケッチの最適化
*
* Irrigation System v1.1
*
* /
#include
注: USBポートを使用してArduinoNanoをプログラムする場合は、IO Expanderから切断する必要があります。これは、同じ単一のシリアルポートも使用しているためです。代わりに、デバッグする場合は、ICSPポートを使用してATmega328Pをプログラムします。ソフトウェアデバッグポートを有効にするには、SERIAL_DEBUG定義のコメントを解除します。
スプリッタは、最初に光赤外線センサーデータラインを1-Wireリモートセンサーラインから分離するように構成する必要があります。 R2のゼロオーム0603抵抗器にはんだ付けします。
<図>PG7およびPG11の右側にある、小さいエンクロージャーに7/16 "の穴を開け、大きいエンクロージャーに11/16"の穴を開けます。ドレメルツールを使用して、グランドがぴったり合うまで穴を少し拡大します。 PG7は、リモートセンサーとPG11を12VDC、24VAC、マニホールドワイヤー、およびRJ11リモートセンサーワイヤーに供給します。
<図>SPSTモーメンタリプッシュボタンマイクロスイッチを配線し、RJ11ネジ留め式端子に接続します。熱収縮チューブを使用して接点を絶縁します。
<図>すべてのワイヤーを接続し、すべての部品を組み立て/フィードして大きなエンクロージャーに入れます。リモートセンサー用の50フィートのRJ11ワイヤーは、PG11グランドを切断せずにぴったりとはまるはずです。
<図>光学赤外線水センサー用に小さなエンクロージャーの上面に9/16 "の穴を開けます。ドレメルツールを使用して、センサーが収まるまで穴を少し拡大します。小さなリモートセンサーエンクロージャーはぴったりとはまりますが、中身がRJ11ワイヤーをできるだけ短くすると、すべてを小さなエンクロージャーに詰め込むのに役立ちます。組み立てたら、ナットをねじ込む前に、グランドナットウォッシャーにマリングルーを追加することをお勧めします。より良いシールを作成します。
<図>リモートセンサーエンクロージャーを屋外に設置し、光学赤外線水センサーと光センサーを障害物なしで空に向けて、家の東側に持ち上げて取り付けます。
<図>大きなエンクロージャーの上部中央下部に1/4 "の穴を開け、ボタンを取り付けます。ボタンが収まるまで、ドレメルツールを使用して穴を少し拡大します。
<図>システムをテストし、すべてが正しく動作していることを確認します。リレーとセンサーをテストするには、ArduinoをIO Expanderから切断し、コンピューターに直接接続して手動で制御します。すべてが動作していることを確認したら、両面テープとパッキングフォームを使用してすべての部品をエンクロージャに組み立て、ボードを固定し、スマート灌漑コントローラーの利点と節約を享受します。
動作中のビデオ
2019年9月12日更新
システムが数日間電源を失った場合の起動の問題を修正したv1.1をリリースしました。
2019年10月2日更新
1-WireをI2C、DS3231、次にSSD1306 OLED画面に接続すると、下の丸で囲んだ画像に示すように、SDAラインとSCLラインに合計3つの異なるプルアップがあります。これにより、効果的に4.7k / 3 =1.56kのプルアップが発生し、強すぎて画面がランダムに破損する可能性があります。
<図>DS3231は他のラインで使用されている抵抗パックを使用しているため、他のプルアップ抵抗を取り外します。
- 1-I2CR3およびR4に配線します。
- SSD1306 OLEDR6およびR7。
コード
- スマート灌漑コントローラー
スマート灌漑コントローラー C / C ++
Arduinoを使用して、庭や庭にインテリジェントに水をまきます。/ * IOエキスパンダースケッチの最適化** Irrigation System v1.1 * * /#include#include //ファイルの場所\ Programファイル(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" i6s8f "#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_TIME_BEFORE_SU定義DO_NOT_WATER_TEMP4.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_DAY * SEC_IN_HOUR)#define DAYS_IN_WEEK TUE 0x04#define WED 0x08#define THR 0x10#define FRI 0x20#define SAT 0x40#define EVERYDAY(SUN | MON |火|水曜日| THR | FRI | 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"、 "TUE"、 "WED"、 "THU"、 "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リレー;} ZONE; typedef struct {uint8_tゾーン; uint8_t日; int8_t時間; 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 rain [MAX_ZONES]; uint8_t状態; uint8_t crc;} NVRAM; enum {ZONE1、ZONE2、ZONE3、ZONE4}; enum {RELAY1 =1、RELAY2、RELAY3、RELAY4}; ZONE zone [] ={{"Front Right"、RELAY1}、{"Front Left" 、RELAY2}、{"ブッシュ"、RELAY3}、{"左側"、RELAY4}、};スケジュールスケジュール[] ={{ゾーン1、サンライズ| 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 length){uint8_t crc =0; while(length-){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(エラー)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; for(i =0; i SATURDAY)wday =SUNDAY; if(wday ==clk.tm_wday)break; // 1週間だけチェックします} if(clk_time 0){if(nvram.rain [i]> nvram.water_duration)nvram.water_duration =0;それ以外の場合、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 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; 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 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;長い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()はstruct tm rtc_time =mktime(&clk);を変更できますlocaltime_r(&rtc_time、&rtc); // 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!"); // 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; //日の出時刻を確認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--;それ以外の場合、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);壊す;ケースMENU_WATER:StartScheduleTime(water_time、water_schedule); WaterScheduleTime();壊す;ケースMENU_CLOCK_MIN_PLUS:clk_time + =SEC_IN_MIN;壊す;ケースMENU_CLOCK_MIN_MINUS:clk_time- =SEC_IN_MIN;壊す;ケースMENU_CLOCK_HOUR_PLUS:clk_time + =SEC_IN_HOUR;壊す;ケースMENU_CLOCK_HOUR_MINUS:clk_time- =SEC_IN_HOUR;壊す;ケースMENU_ON_OFF:nvram.state ^ =STATE_ON_OFF; update_nvram =true;壊す; } 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){//サンライズclk_time =nvram.sunrise_time; localtime_r(&clk_time、&clk);} else clk =rtc; Serial.print(clk.tm_hour-((clk.tm_hour> 12)?12:0));シリアル。 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();}
回路図
Intelligently water your yard or garden 製造プロセス