前回まで/次回以降の取り組みはこちらから。
Raspberry Pi側のアプリを作りこんでいきます。
今回の完成図
こんな感じ。
水やりに関して、時刻と水分量で自動制御できるようになりました。
「時刻設定1」「時刻設定2」「水分量設定」のロジックは、LED制御と同じです。
Arduinoスケッチ
基本的に前回追加したLED制御部分をコピペして変数やフラグの名前を変えただけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 | // あさがおIoT観察日記 Arduino側プログラム // 2020.05.21 V0.0.1 DHT11による温度・湿度取得(DHT11サンプルスケッチより作成) // V0.0.2 BME280気圧取得(BME280サンプルスケッチより作成) // 2020.05.23 V0.0.3 TEMT6000による照度取得 // 2020.05.24 V0.0.4 KeyStudio製センサで土の水分量取得 // 2020.06.02 V0.0.5 RaspberryPi側通信制御開発のため、一度シリアル送信するのを照度データだけに変更 // 今後の準備としてLED照明、ポンプ、水切れセンサ、ボタンSWに関する制御パートを追加 // 2020.06.06 V0.0.6 センサの数値をすべてシリアル送信するように変更 // データ「d」をシリアルで受信したらセンサデータを送信する // 2020.06.08 V0.0.7 LEDガーデンライトの制御に対応 // 2020.06.11 V0.0.8 水やり制御に対応 boolean l = false; #define LED_pin 13 #define pump_pin 12 #define SW_B_pin 11 #define SW_R_pin 10 #define sensor_tank 2 #define sensor_water 1 #define sensor_bright 0 #include <Adafruit_Sensor.h> #include <DHT.h> #include <DHT_U.h> #define DHTPIN 2 // Digital pin connected to the DHT sensor #define DHTTYPE DHT11 // DHT 11 DHT_Unified dht(DHTPIN, DHTTYPE); #include <Wire.h> #include <SPI.h> #include <Adafruit_BME280.h> #define SEALEVELPRESSURE_HPA (1013.25) Adafruit_BME280 bme; // I2C uint32_t delayMS; int Alt = 120; void serial_send(double temp,double humid,double pres_0,int bright,int water,int tank){ Serial.println(temp); Serial.println(humid); Serial.println(pres_0); Serial.println(bright); Serial.println(water); Serial.println(tank); } void setup() { Serial.begin(9600); pinMode(LED_pin, OUTPUT); pinMode(pump_pin,OUTPUT); pinMode(SW_B_pin,INPUT_PULLUP); pinMode(SW_R_pin,INPUT_PULLUP); dht.begin(); delayMS = 100; bme.begin(0x76); } void loop() { double temp; double temp_0; double humid; double pres; double pres_0; int bright; int water; int tank; static boolean LED_Flag = false; static int LED_Th = 999; static boolean Water_Flag = false; static int Water_Th = 999; static long Water_time; sensors_event_t event; //温度取得 dht.temperature().getEvent(&event); if (!isnan(event.temperature)) { temp = event.temperature; } //湿度取得 dht.humidity().getEvent(&event); if (!isnan(event.relative_humidity)) { humid = event.relative_humidity; } //気圧取得 pres = bme.readPressure() / 100; pres_0 = pres/(pow((1-((0.0065*Alt)/(bme.readTemperature()+0.0065*Alt+273.15))),5.257)); //海面更生 //照度取得 bright = analogRead(sensor_bright); //LED照明制御 if(LED_Flag==true && bright<LED_Th){ digitalWrite(LED_pin,HIGH); }else{ digitalWrite(LED_pin,LOW); } //水分量取得 water = analogRead(sensor_water); //水やり判断 if(Water_Flag==true && water<Water_Th){ digitalWrite(pump_pin,HIGH); Water_Flag = false; Water_time = millis(); } if(millis()>Water_time+30000){ digitalWrite(pump_pin,LOW); } //タンク水切れ判断 tank = analogRead(sensor_tank); //シリアル送信 if(Serial.available()>=4){ //しきい値受信用行列 char th[] = {0,0,0}; char val = Serial.read(); th[0]= int(Serial.read())-48; th[1]= int(Serial.read())-48; th[2]= int(Serial.read())-48; //しきい値計算 int th_lebel = 100*th[0] + 10*th[1] + 1*th[2]; if(val=='L'){ if(th_lebel==999){ LED_Flag = false; }else if(th_lebel==0){ LED_Th = 1024; LED_Flag = true; }else{ LED_Th = th_lebel; LED_Flag = true; } serial_send(temp,humid,pres_0,bright,water,tank); }else if(val=='W'){ if(th_lebel==999){ Water_Flag = false; digitalWrite(LED_pin,LOW); }else if(th_lebel==0){ Water_Th = 1024; Water_Flag = true; }else{ Water_Th = th_lebel; Water_Flag = true; } serial_send(temp,humid,pres_0,bright,water,tank); }else if(val=='d'){ serial_send(temp,humid,pres_0,bright,water,tank); } Serial.println(Water_Th); } } |
LEDの制御と違っているのは、
- 30秒経ったら自動でOFFする
- 一度水やりを実行したら、次に水やりする時間帯になるまで再度動くことはない
ことの2点です。
pythonプログラム
main_0_0_8.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | from PyQt5.QtWidgets import QApplication from ui.mainwindow_0_0_8 import MainWindow from PyQt5.QtCore import * import time import datetime import serial serialport = "/dev/ttyACM0" LED_TH = 999 LED_TH_P = 999 Water_TH = 999 Water_TH_P =999 class SerialCom: def __init__(self, serialport): self.sc = serial.Serial(serialport,9600) time.sleep(3) def data_read(self): rc_data = self.sc.readline() return rc_data def start_com(self): self.sc.write(b'd') self.sc.write(b'0') self.sc.write(b'0') self.sc.write(b'0') def light_set(self, th): self.sc.write(b'L') light1 = th//100+48 light2 = (th%100)//10+48 light3 = (th%100%10)+48 self.sc.write(chr(light1).encode()) self.sc.write(chr(light2).encode()) self.sc.write(chr(light3).encode()) def water_set(self, th): self.sc.write(b'W') water1 = th//100+48 water2 = (th%100)//10+48 water3 = (th%100%10)+48 self.sc.write(chr(water1).encode()) self.sc.write(chr(water2).encode()) self.sc.write(chr(water3).encode()) def close(self): self.sc.close() def refresh_time(): #時刻更新 now = datetime.datetime.now() ct = "現在時刻:" + now.strftime('%Y/%m/%d %H:%M:%S') ui.labeltime.setText(ct) #LED制御 n = now.time() global LED_TH #時刻制御1 cb_t1 = ui.checkBoxLightTime1.checkState() t = ui.timeEditLedStart1.time() LedStartTime1 = datetime.time(t.hour(), t.minute(), 0) t = ui.timeEditLedEnd1.time() LedEndTime1 = datetime.time(t.hour(), t.minute(), 0) #時刻制御2 cb_t2 = ui.checkBoxLightTime2.checkState() t = ui.timeEditLedStart2.time() LedStartTime2 = datetime.time(t.hour(), t.minute(), 0) t = ui.timeEditLedEnd2.time() LedEndTime2 = datetime.time(t.hour(), t.minute(), 0) #時刻制御有効の場合 if((cb_t1>0 and LedStartTime1<=n<LedEndTime1) or (cb_t2>0 and LedStartTime2<=n<LedEndTime2)): ui.progressBarLight.setValue(100) if(ui.checkBoxLightTh.checkState()): LED_TH = ui.spinBoxLed.value() else: LED_TH = 0 else: ui.progressBarLight.setValue(0) LED_TH = 999 #時刻制御無効の場合、センサーレベルだけ見る #すべてのチェックが入っていなければ、常時ON if(cb_t1==0 and cb_t2==0): if(ui.checkBoxLightTh.checkState()): LED_TH = ui.spinBoxLed.value() else: LED_TH = 0 #水やり制御 n = now.time() global Water_TH #時刻制御1 cb_t1 = ui.checkBoxWaterTime1.checkState() t = ui.timeEditWaterStart1.time() WaterStartTime1 = datetime.time(t.hour(), t.minute(), 0) t = ui.timeEditWaterEnd1.time() WaterEndTime1 = datetime.time(t.hour(), t.minute(), 0) #時刻制御2 cb_t2 = ui.checkBoxWaterTime2.checkState() t = ui.timeEditWaterStart2.time() WaterStartTime2 = datetime.time(t.hour(), t.minute(), 0) t = ui.timeEditWaterEnd2.time() WaterEndTime2 = datetime.time(t.hour(), t.minute(), 0) #時刻制御有効の場合 if((cb_t1>0 and WaterStartTime1<=n<WaterEndTime1) or (cb_t2>0 and WaterStartTime2<=n<WaterEndTime2)): ui.progressBarWater.setValue(100) if(ui.checkBoxWaterTh.checkState()): Water_TH = ui.spinBoxWater.value() else: Water_TH = 0 else: ui.progressBarWater.setValue(0) Water_TH = 999 #時刻制御無効の場合、センサーレベルだけ見る #すべてのチェックが入っていなければ、常時ON if(cb_t1==0 and cb_t2==0): if(ui.checkBoxWaterTh.checkState()): Water_TH = ui.spinBoxLed.value() else: Water_TH = 0 def refresh_sensor(): myserial.start_com() global LED_TH global LED_TH_P global Water_TH global Water_TH_P #温度更新 temp = myserial.data_read() ui.labeltemp.setText("気温:\t" + str("{0:.2f}".format(float(temp))) + " [℃]") #湿度更新 humid = myserial.data_read() ui.labelhumid.setText("湿度:\t" + str("{0:.2f}".format(float(humid)))+ " [%]") #気圧更新 press = myserial.data_read() ui.labelpress.setText("大気圧:" + str("{0:.2f}".format(float(press))) + " [hPa]" ) #照度更新 bright = myserial.data_read() ui.labelbright.setText("照度:\t" + str("{0:4}".format(int(bright))) + "[Lx]") #水分量更新 water= myserial.data_read() ui.labelwater.setText( "水分量:\t" + str("{0:4}".format(int(water)))) #水タンク満水検知 tank= myserial.data_read() ui.labeltank.setText("タンク内水検知:" + str("{0:4}".format(int(tank)))) #LEDライトしきい値送信 light = myserial.data_read() ui.labelLight.setText(str("{000:}".format(int(light)))) if(LED_TH != LED_TH_P): myserial.light_set(LED_TH) LED_TH_P = LED_TH if(Water_TH != Water_TH_P): myserial.water_set(Water_TH) Water_TH_P = Water_TH if __name__=="__main__": import sys app = QApplication(sys.argv) ui = MainWindow() #ui.showFullScreen() myserial = SerialCom(serialport) refresh_sensor() timer1 = QTimer() timer1.timeout.connect(refresh_time) timer1.start(200) timer2 = QTimer() timer2.timeout.connect(refresh_sensor) timer2.start(1000) ui.show() sys.exit(app.exec_()) |
mainwondow_0_0_8.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # -*- coding: utf-8 -*- """ Module implementing MainWindow. """ from PyQt5.QtCore import pyqtSlot from PyQt5.QtWidgets import QMainWindow from .Ui_mainwindow_0_0_8 import Ui_MainWindow class MainWindow(QMainWindow, Ui_MainWindow): """ Class documentation goes here. """ def __init__(self, parent=None): """ Constructor @param parent reference to the parent widget @type QWidget """ super(MainWindow, self).__init__(parent) self.setupUi(self) |
Raspberry PiとArduinoでポンプを連携制御する
前回まで
前回、LED照明を制御するために、Raspberry PiからArduinoへ送信する文字列によってセンサから値を受け取るか、LEDを制御するか決めました。
「d」で始まればセンサデータの送信指示、「L」で始まればLEDの制御指示です。
今回は
前回までのデータの取り決めに、ポンプ制御用のデータセットを追加しました。
- 「d」で始まるデータ:センサデータ送信指示
- 「L」で始まるデータ:LEDの制御指示
- 「W」で始まるデータ:水やりポンプの制御指示 ⇦New!
Raspberry Piから受け取ったデータ文字列によってON/OFFのしきい値とフラグを変えます。
フラグが「true」ならポンプをONしてよい、「false」ならポンプをONしてはならないという指示です。
水分量センサの値がしきい値以下であり、フラグがtrueならポンプをONして、30秒後に自動でOFFします。
今回は水やりポンプの制御が完成しました。
まだまだ続きます。
コメント