現在(2020年9月4日)、日本の南の海上に台風10号がいます。
台風の正体は発達した低気圧なので、近づくほど気圧が下がります。
なので、気圧を記録していけば台風が最接近したタイミングを知ることができます。
【注】こうした実験をするのもいいですが、テレビ・新聞や気象庁の台風情報を確認したり、対策をしたりといったこともお忘れなく。また、状況を見て避難などしてください。
もくじ
ハード・ソフトの準備
M5Stick + ENV HATの組み合わせで測定します。
過去(ブログを始めるよりも前)に作ったスケッチをほぼそのまま流用しています。スケッチは後で載せます。
動作はこんな感じです。
- 電源投入・リセット時にWifiに接続し、NTPサーバーを利用して内蔵RTCの時刻合わせをする。
(WiFiの名前とパスワードはスケッチ内に記載) - 温度・湿度・大気圧(海面更生済み)を液晶に表示する。
- 1分おき(RTCの情報を利用して毎分0秒)にAmbientにデータを送信する。
チャネルID・ライトキーはスケッチ中に記載、送信中は右上にメールのアイコンを表示 - Bボタンで「温度・湿度・大気圧表示モード」を表示するモード1と、「Wi-Fiアクセスポイント名、AmbientのチャネルID・ライトキー」を表示するモード0を切り替え
- モード0でAボタンを押すとデータ送信はON/OFFを切り替えられる
(時計表示の色で識別→ピンク:データ送信OFF/水色:データ送信ON) - モード1でAボタンを押すと表示のON/OFF切り替え
(画面をOFFすることでバッテリーでの動作時間を少しでも伸ばしたい)
本当はSDカードにローカルでログが取れたらいいんですが、M5STick-Cにはスロットがないので無理ですね。
かといってM5Stack系はRTCがないのでロギングに不向き。
なんだかなぁ…と思っていたらスイッチサイエンスさんでM5STACK Core2が発売されました。
https://www.switch-science.com/catalog/6530/
SDカードスロットもRTCもついているので、IoTサービスとローカルの両方にデータを記録できるデータロガーとして活用できそうです。
停電対策
台風がもろに接近した場合、停電(瞬停含む)する可能性があります。
M5Stick-Cには小容量ながらバッテリーがついているので、AC充電器に刺しっぱなしで運用しておき、停電が長引きそうならモバイルバッテリーに差し替える、という運用で大丈夫でしょう。
停電したとなればWi-Fiやインターネット回線(うちはWiMaxを使用)も落ちます。
今回は機種変して使っていないスマートフォンからテザリングして運用します。
(いわゆる格安simでサブ含めて2回線持っているので1回線をこちらに割り当て。画面がヒビいってますが気にしない気にしない)
こちらもAC充電器に刺しっぱなし運用します。停電してもそもそもスマートフォンなのでバッテリーはそこそこ持つはずです。
データ
こんな感じで、温度・湿度と大気圧とでAmbientのチャートを設定しました。
センサーを室内に置いていて、エアコンを使っている時間が長いので温度・湿度はあまり変わりません。
家が古い木造の建物で、気密性なにそれって感じなので大気圧は多分測定できるかと。
(一瞬チャートを公開しようかとも思ったけど、それ「留守にしてる時間帯」をリアルタイムに知れるデータやん…と気づいたのでやめておきます。IoTが流行ってますがデータセキュリティなどにもお気をつけあそばせ…)
1分間隔でデータを取っているので、ゲリラ雷雨の時の気圧の変動なども記録できそうです。
何か観測できたら追ってエントリ書きます。
…ところで、Ambient。なんかログインできなかったり設定がちゃんと反映されなかったりするんだけど大丈夫?
スケッチ
スケッチ内の以下の情報は使用する環境に合わせて書き換えます。
- 接続するWi-Fiのアクセスポイント名とパスワード
- Ambientのチャネル番号とライトキー
- 測定する地点の高度(海抜高度。スマホアプリなどでも調べられます。)
冒頭の写真で変なところに「NTP」と表示されている点、改善済みです。
また、アクセスポイント名やAmbientのライトキーなどは画面に収まらない部分は表示されません。
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 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 | /* note: need add library Adafruit_BMP280 from library manage Github: https://github.com/adafruit/Adafruit_BMP280_Library */ //海面気圧補正用の海抜高度 #define locate_altitude 120 //M5StickCセットアップ #include <M5StickC.h> //ENV HATセットアップ #include "DHT12.h" #include <Wire.h> #include "Adafruit_Sensor.h" #include <Adafruit_BMP280.h> DHT12 dht12; Adafruit_BMP280 bme; //WiFi接続・RTCセットアップ #include <WiFi.h> const char* ssid = "XXXXXXXX"; // SSID const char* password = "XXXXXXXX"; // パスワード const char* ntpServerUrl = "ntp.nict.jp"; RTC_TimeTypeDef RTC_TimeStruct; RTC_DateTypeDef RTC_DateStruct; //表示切替用 boolean ViewMode = false; boolean ViewEnable = true; //ambientセットアップ WiFiClient client; #include <Ambient.h> unsigned int channelId = XXXXX; //チャネルID const char* writeKey = "XXXXXXXXXXXXXXXX"; //ライトキー Ambient ambient; //ambient送信フラグ boolean AmbientSend = false; void setup(){ // put your setup code here, to run once: M5.begin(); M5.Lcd.setRotation(1); M5.Lcd.setTextWrap(0); //テキストを折り返さない M5.Lcd.fillScreen(TFT_BLACK); M5.Lcd.setCursor(5, 0, 2); M5.Lcd.print("WiFi-AP Connecting"); //WiFi接続 WiFi.begin(ssid, password); int cnt = 0; while (WiFi.status() != WL_CONNECTED) { delay(1000); if(cnt<6) M5.Lcd.print("."); cnt++; if(cnt>10){ M5.Lcd.setCursor(5, 16, 2); M5.Lcd.setTextColor(TFT_RED); M5.Lcd.print("Could not connect valid"); M5.Lcd.setCursor(5, 32, 2); M5.Lcd.print("WiFi-AP!!"); while(1); } } M5.Lcd.fillScreen(TFT_BLACK); M5.Lcd.setCursor(5, 0, 2); M5.Lcd.println("WiFi-AP Connected! "); //NTPデータをもとにRTCの時刻合わせ NTP2RTC(); //BME280起動・ENVHAT接続チェック Wire.begin(0,26); if (!bme.begin(0x76)){ M5.Lcd.setCursor(5, 32, 2); M5.Lcd.setTextColor(TFT_RED); M5.Lcd.print("Could not find a valid"); M5.Lcd.setCursor(5, 48, 2); M5.Lcd.print("ENV HAT!"); while (1); } delay(3000); M5.Lcd.fillScreen(BLACK); pinMode(M5_BUTTON_HOME, INPUT); pinMode(M5_BUTTON_RST , INPUT); Serial.begin(115200); } void loop() { float temp; float humi; float pressure; //海面気圧への校正計算とhPa単位へのけた合わせ pressure = pressure / 100; pressure = pressure * pow((1-((0.0065*locate_altitude)/(temp+0.0065*locate_altitude+273.15))),(-5.257)); //時刻表示 M5.Rtc.GetTime(&RTC_TimeStruct); M5.Rtc.GetData(&RTC_DateStruct); M5.Lcd.setCursor(5, 0, 2); //時刻はambient送信が有効の時白、無効の時赤で表示 if(AmbientSend==true){ M5.Lcd.setTextColor(TFT_CYAN,TFT_BLACK); }else{ M5.Lcd.setTextColor(TFT_PINK,TFT_BLACK); } M5.Lcd.printf("%04d/%02d/%02d %02d:%02d:%02d",RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date,RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds); Serial.printf("%04d/%02d/%02d %02d:%02d:%02d\t",RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date,RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds); //直線表示 M5.Lcd.drawLine(0, 18, 160, 18, WHITE); M5.Lcd.setTextColor(TFT_WHITE,TFT_BLACK); if(ViewMode==1){ //表示モード1の場合:温度、湿度、気圧を表示 //温度表示 temp = dht12.readTemperature(); M5.Lcd.setCursor(30, 20, 2); M5.Lcd.printf("Temp : %2.1f C ",temp); Serial.printf("%2.1f\t",temp); //湿度表示 humi = dht12.readHumidity(); M5.Lcd.setCursor(32, 40, 2); M5.Lcd.printf("Humi : %2.1f %% ",humi); Serial.printf("%2.1f\t",humi); //気圧表示 pressure = bme.readPressure(); Serial.printf("%2.1f\t",pressure); M5.Lcd.setCursor(26, 60, 2); M5.Lcd.printf("Press : %2.1f hPa ",pressure); Serial.printf("%2.1f\t\n",pressure); }else{ //表示モード0の場合:ssid、ambientのチャネルとライトキーを表示 //ssid表示 M5.Lcd.setCursor(5, 20, 2); M5.Lcd.print("WiFi-AP : "); for(int i=0;i<12;i++) M5.Lcd.print(ssid[i]); //ambient M5.Lcd.setCursor(5, 36, 2); M5.Lcd.print("ambient send to"); //ambientチャンネルID M5.Lcd.setCursor(15, 50, 2); M5.Lcd.printf("ChannelID : %d",channelId); //ambientライトキー M5.Lcd.setCursor(15, 63, 2); M5.Lcd.printf("WriteKey : "); M5.Lcd.print(writeKey); } //ambientに送信 int MinuteData; if(RTC_TimeStruct.Seconds==0 && MinuteData!=RTC_TimeStruct.Minutes && AmbientSend==true){ if(ViewMode==1){ //ambientサーバーへのデータ送信をメールマークで表現 M5.Lcd.drawLine(136,20,156,20,CYAN); M5.Lcd.drawLine(156,20,156,36,CYAN); M5.Lcd.drawLine(156,36,136,36,CYAN); M5.Lcd.drawLine(136,36,136,20,CYAN); M5.Lcd.drawLine(136,20,146,28,CYAN); M5.Lcd.drawLine(146,28,156,20,CYAN); } //送信 ambient.begin(channelId, writeKey, &client); ambient.set(1, temp); ambient.set(2, humi); ambient.set(3, pressure); ambient.send(); MinuteData = RTC_TimeStruct.Minutes; } //メールマークを消す if(RTC_TimeStruct.Seconds!=0 || AmbientSend==false){ if(ViewMode==1) M5.Lcd.fillRect(136,20,21,17,TFT_BLACK); } //毎日0:00:05にRTC再設定する if(RTC_TimeStruct.Hours==0 && RTC_TimeStruct.Minutes==0 && RTC_TimeStruct.Seconds==5){ NTP2RTC(); delay(1000); } //温度・湿度モードでAボタンで表示ON/OFF if(digitalRead(M5_BUTTON_HOME)==LOW && ViewMode==true){ ViewEnable = !ViewEnable; if(ViewEnable==true){ for(int i=0;i<13;i++){ M5.Axp.ScreenBreath(i); delay(30); } }else{ for(int i=12;i>=0;i--){ M5.Axp.ScreenBreath(i); delay(30); } } while(digitalRead(M5_BUTTON_HOME) == LOW); } //ssid・ambientモードでAボタンでambientサーバーへの送信ON/OFF if(digitalRead(M5_BUTTON_HOME)==LOW && ViewMode==false){ AmbientSend = !AmbientSend; while(digitalRead(M5_BUTTON_HOME) == LOW); } //Bボタンで表示切替 if(digitalRead(M5_BUTTON_RST) == LOW){ ViewMode = !ViewMode; while(digitalRead(M5_BUTTON_RST) == LOW); M5.lcd.fillScreen(TFT_BLACK); } } void NTP2RTC(){ //NTPの時刻データをRTCに設定する configTime(9 * 3600, 0, ntpServerUrl); //NTPサーバーを使ってRTC時刻合わせ struct tm timeInfo; if (getLocalTime(&timeInfo)) { M5.Lcd.setCursor(5, 16, 2); M5.Lcd.print("NTP : "); M5.Lcd.println(ntpServerUrl); //RTC時刻セット RTC_TimeTypeDef TimeStruct; TimeStruct.Hours = timeInfo.tm_hour; TimeStruct.Minutes = timeInfo.tm_min; TimeStruct.Seconds = timeInfo.tm_sec; M5.Rtc.SetTime(&TimeStruct); RTC_DateTypeDef DateStruct; DateStruct.WeekDay = timeInfo.tm_wday; DateStruct.Month = timeInfo.tm_mon + 1; DateStruct.Date = timeInfo.tm_mday; DateStruct.Year = timeInfo.tm_year + 1900; M5.Rtc.SetData(&DateStruct); M5.Lcd.fillScreen(TFT_BLACK); } } |
スケッチ修正について(2020.09.05 0:00ごろ追記)
当初アップしていたスケッチにミスがありました。上記スケッチは修正済みです。
修正点は3 2点。
Ambientデータアップロード条件変更
新スケッチ159行目のif文を
159 | <del>if(RTC_TimeStruct.Seconds==0 && MinuteData!=RTC_TimeStruct.Minutes && AmbientSend==true){</del> |
から
159 | <del>if(MinuteData!=RTC_TimeStruct.Minutes && AmbientSend==true){</del> |
に変更しました。
「RTCの秒の数値が0」かつ
「RTCの分の数値が前回データアップ時の数値と違っている」かつ
「Ambientへのデータアップロード有効」
の3条件のANDから
「RTCの秒の数値が0」かつ ←無し
「RTCの分の数値が前回データアップ時の数値と違っている」かつ
「Ambientへのデータアップロード有効」
の2条件のANDになります。
「1分に1回」という条件を満たすだけなら、「RTCの秒の数値が0」がなくても成立します。
(というより、ボタン処理などで処理が停止している間にRTCの秒が59→0→1と変化してしまえばデータアップロードを一回し損ねることになります。秒=0という条件がなければ、「分の数値が変わった」ことを条件に動作できるので、多少遅れてでもデータアップロードできるはずです。)
→この条件がないと、「AmbientデータアップロードをOFF→ONにしたとき」にもデータがアップされてしまいますので、やっぱり元に戻します。(2020/9/5 2:30ごろ追記)
変数「MiniteData」のstatic変数化・初期値設定
旧スケッチ161行目
161 | int MinuteData; |
を
161 | static int MinuteData = -1; |
に修正しました。(新スケッチ158行目)
「RTCの分の数値が前回データアップ時の数値と違っている」かつ
「Ambientへのデータアップロード有効」
の2条件のANDでAmbientへのデータアップロード処理を走らせています。
データアップロード処理を1分に1回だけにするために、赤文字部分の条件を入れてあります。
当初の目論見は、この「前回データアップした際の分の数値」を保存しておくメモリとしてMinuteDataという変数を利用するというもの。このために、データアップロード処理の最後に現在のRTCの分の数値を代入しています。(新スケッチ175行目)
loop文が一周して帰ってきた時にも数値をキープしておく必要があるので、static化が必要です。
ここが普通のintになっていると、loop文の終わりでMinuteDataという変数が一度破棄されて、次のloop文の161行目で再度新たに宣言されます。このため、一度の送信タイミングで2~3度データが送られてしまいます。
また、変数を呼び出した際に初期化しなかった場合、値が不定になります。「分の数値が絶対に取らない、int型の取れる値」として、「-1」で初期化しておきます。
センサデータ取得タイミングの変更
もう一点、loop文の最初でtemp、humi、pressureの各変数(温度・湿度・大気圧を入れる変数)を宣言だけして、後から(新スケッチ116 119行目~のif文の中で)実際のセンサ値を代入していましたが、こちらは宣言と同時に代入を行うようにしました。
というのも、このロジックだと「モード1画面にいないと」データが更新されないからです。
スケッチ修正その2(2020.09.05 2:30ごろ追記)
もう一つバグを見つけました。。。
大気圧データ変換タイミングの変更
大気圧センサで読み取った気圧を海面更生する2行(コメント含めて新スケッチの98~100行目)を「センサデータ取得タイミングの変更」と同じ理由で同じ場所に移設しました。
データアップロードをOFF→ONに変更して、そのままモード0(アクセスポイント名などの表示画面)にとどまった場合に、Pa単位の大気圧(100,000Paとか)でアップされてしまうことがわかりました。
ちなみにこれでも時々データを取りこぼしていることがあり、調査中です。
コメント