前回まで/次回以降の取り組みはこちらから。
Raspberry Pi側のアプリを作りこんでいきます。
今回の完成図
こんな感じ。
全画面表示にして、LED照明のコントロール用のGUIを配置して、時刻としきい値による制御を実装しました。
LED制御GUIの役割
こんな風に役割と使い方を考えました。
照明は一晩点けておく予定です。
プログラムでの処理を簡単にするために、日付変更前後で分けて設定するようにして設定時刻を2セット設けます。
上の図の場合だと時刻設定1が「0:00~6:00」、時刻設定2が「18:00~23:59」になります。
Raspberry PiからArduinoに時刻に応じた指令とLEDを点灯させる照度のしきい値を送り、Arduinoはその指示・しきい値と照度センサの明るさをもとにLEDのON/OFFをコントロールします。
まだArduinoとの通信部分を作っている途中なので、画面上の「LED制御中」の部分の色が時刻に合わせて変わるだけです。
ちなみにこの部分、このまま流用して水やり制御プログラムも作る予定です。
Arduinoスケッチ
しきい値を送信するためのテストスケッチが含まれています。
コメントは「ライトの制御に対応」ですが、まだ対応してません…。
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 | // あさがお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ガーデンライトの制御に対応 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; 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); //水分量取得 water = analogRead(sensor_water); //水やり判断 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=='d'){ l = !l; digitalWrite(LED_pin,l); serial_send(temp,humid,pres_0,bright,water,tank); Serial.println(th_lebel); } } } |
前回、センサデータの先頭に「d」という1文字を送ることで、Arduinoがデータの先頭を判断できるようにしました。
照明や水やりの指示を送る時はこの部分を別の文字に変えて、続けてしきい値を送る心づもりです。
pythonプログラム
バージョン番号が飛んでますが、Arduinoのスケッチと合わせることにしました。
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 | from PyQt5.QtWidgets import QApplication from ui.mainwindow_0_0_7 import MainWindow from PyQt5.QtCore import * import time import datetime import serial serialport = "/dev/ttyACM0" 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'6') self.sc.write(b'6') 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() LED_TH = 999 #時刻制御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 = 999 ui.labelLight.setText(str(LED_TH)) else: ui.progressBarLight.setValue(0) def refresh_sensor(): myserial.start_com() #温度更新 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 __name__=="__main__": import sys app = QApplication(sys.argv) ui = MainWindow() ui.showFullScreen() myserial = SerialCom(serialport) timer1 = QTimer() timer1.timeout.connect(refresh_time) timer1.start(100) timer2 = QTimer() timer2.timeout.connect(refresh_sensor) timer2.start(1000) ui.show() sys.exit(app.exec_()) |
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 | # -*- coding: utf-8 -*- """ Module implementing MainWindow. """ from PyQt5.QtCore import pyqtSlot from PyQt5.QtWidgets import QMainWindow from .Ui_mainwindow_0_0_7 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) @pyqtSlot() def on_pushButtonLed_clicked(self): """ Slot documentation goes here. """ # TODO: not implemented yet raise NotImplementedError |
チェックボックスやスピンボックスの状態を読んだり、プログレスバーを操作したり、だいぶGUIアプリケーションっぽいこと増えてきました。
PyQt5の使い方を都度ググって作っていっているんですが、なかなか思ったような情報に行きつけずに難儀しております。
まだまだ続きます。
コメント