見出し画像

M5Stack を使ってみた #05

環境モニターの作成 (2)

メインプログラム

画面をクリア

最初に画面をクリアします。プログラムが起動すると、あらかじめ配置したラベルが表示されるのが少々目障りだったからです。クリアすると画面が真っ黒になります。

Watch Dog Timer を設定


WDT 初期化

プログラムが途中で止まってしまうことがあります。Watch Dog Timer (WDT) は、一定時間、信号が無いと、処理が停まっているとみなして、リセット(再起動)が実行されます。M5Stack は、再起動後、それまで実行していたプログラムを再実行します。見掛け上は、プログラムは動き続けているように見えます。
どんなコンピュータでもハングする事はありますが、このM5Stackでも発生しますので、環境モニターの様にずっと動いていて欲しい時には、WDTの設定は必須です。
ここでは、WDTを1000秒(約17分)に設定しました。この時間内にWDTが信号を検知しないとリセットされます。進行に相当するのが、メインプログラムの一番下にあるWDT Feed です。10秒に一度、WDTのタイマーがリセットされます。

WDT feed

プログラム名 + バージョン

プログラム名の設定と表示

M5Stackのディスプレー上面に、ProgramTitle (プログラム名 + バージョン)を表示します。シリアル接続時は、COM Monitor にも表示します。

COM Monitor の画面

試行錯誤をしていると、今動いているのはどのバージョンだっけ、と分からなくなる時が多かったので、バージョンも表示する様にしました。歳をとるとちょっと前の事が思い出せなくなるので、面倒ですが、こうすると迷わなくて良いです。

Wifiへの接続

UIFlowから、直接プログラムをRUN(実行)させる分には、このブロックは無くても良いのですが、M5Stackのメモリにプログラムをダウンロードしておいて、M5Stack単体で同じプログラムを実行する時、このブロックが無いとWIFIにアクセスできません。

画面の明るさ

画面の明るさを暗くしています。普段は良いのですが、夜中に他の灯りが無いときに目立つので暗くしました。

現在の日時を取得

ntpの初期化

M5Stack自体に時計が内蔵されていないので、Webから現在の日時を取得します。ntpサーバにアクセスするのですが、いくつか試してみて。ntpサーバは、NTPサーバ一覧 を参考にしました。「ntp.jst.mfeed.ad.jp」が一番応答が早かったので、ここにしています。

初期設定 InitialSetting

初期設定をする関数
def InitialSetting():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  label0.setColor(0xffffff)
  ntp = ntptime.client(host='ntp.jst.mfeed.ad.jp', timezone=9)
  YEAR = ntp.year()
  MONTH = ntp.month()
  DAY = ntp.day()
  TIME = ntp.formatTime(':')
  label1.setText('Now Starting .........')
  ShowEnvMonitor()
  indx = 0

初期設定をするサブプログラムになります。UIFlowでは関数と呼ばれていますが、前に言った通り変数はすべてグローバルなので、関数というと違和感があります。

ntpサーバにアクセスし、現在の年、月、日、時間を取得します。その結果を ShowEnvMonitor でディスプレイ表示します。

ディスプレイ表示

ディスプレイ表示するブロック

# この関数の説明…
def ChangeColor():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  label0.setColor(0xcccccc)
  label1.setColor(0xcccccc)
  label2.setColor(0xcccccc)
  label3.setColor(0xcccccc)
  label4.setColor(0xcccccc)
  label5.setColor(0xcccccc)
  label6.setColor(0xffcc00)
  label7.setColor(0xffcc33)
  label12.setColor(0xffcc33)
  label8.setColor(0xffff00)
  label9.setColor(0xffff00)
  label10.setColor(0xffff00)
  label11.setColor(0xcccccc)
  label13.setColor(0xcccccc)
  label14.setColor(0xcccccc)
  label15.setColor(0xcccccc)
  label16.setColor(0xffff00)
  label17.setColor(0xcccccc)
  label18.setColor(0xffff00)

# この関数の説明…
def ShowEnvMonitor():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  ChangeColor()
  label0.setText(str(ProgramTitle))
  label1.setText('Date:')
  label2.setText('Time:')
  label3.setText('Temp:')
  label4.setText('Baro:')
  label5.setText('Humi:')
  label6.setText(str(ntp.formatDate('-')))
  label7.setText(str(ntp.formatTime(':')))
  label12.setText(str((str('(') + str(((str((ntp.weekday())) + str(')')))))))
  label8.setText(str(TEMP))
  label9.setText(str(BARO))
  label10.setText(str(HUMI))
  label16.setText(str(WBGT))
  label18.setText(str(AbsHUMI))
  label13.setText(str(indx))

ラベルにそれぞれ色と値を設定します。普通にコードを書く時は配列化などして、コードの量を減らそうとしますが、ビジュアルプログラミングでは、これが結構面倒でした。

5分タイマーをセット・開始

タイマーの開始
タイマーが呼び出された時
@timerSch.event('FiveMinuteTimer')
def tFiveMinuteTimer():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  GetEnv()
  Save2Wev_01()
  pass

5分間ごとに計測させるためにタイマーを使いました。タイマーが呼ばれると、GetEnv と Save2Wev_01 の二つの処理を行います。

計測を行い、結果をWebにアップロードする

主に、タイマーで呼ばれる処理ですが、初期化が終わったときにも、GetEnv と Save2Wev_01  を実行します。プログラム起動後、最初のデータになります。

GetEnv 環境センサーから計測、データ化

GetEnvのブロック
def GetEnv():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  indx = (indx if isinstance(indx, Number) else 0) + 1
  result = False
  while not result == True:
    try :
      ntp = ntptime.client(host='ntp.jst.mfeed.ad.jp', timezone=9)
      result = True
      pass
    except:
      result = False
      print('Error !:  Exception at ntptime ')
      wait(10)
  BARO = "%.1f"%(((env3_0.pressure) / 100))
  TEMP = "%.1f"%((env3_0.temperature))
  HUMI = "%.1f"%((env3_0.humidity))
  GetWBGT()
  GetAbsHumi()
  WBGT = "%.1f"%float(WBGT)
  AbsHUMI = "%.1f"%(AbsHUMI)
  Last2Data = Last1Data
  Last1Data = Current
  Current = {'Index':indx,'Date':(ntp.formatDate('/')),'Time':(ntp.formatTime(':')),'Temp':TEMP,'Baro':BARO,'Humi':HUMI,'WBGT':WBGT,'AbsHumi':AbsHUMI}

環境センサーから、温度・気圧・湿度を計測する。その温度と湿度から、暑さ指数(WBGT)と絶対湿度を簡易計算で算出する。それをマップ化する。

さらにひとつ前、そのひとつ前のデータとしてデータを保存しておく。最初は前回、前々回のデータとの差が分かるようにしたかったので用意した。が、あまり意味が無かったので、実際には無くても構わない。またいつか利用するかもしれないのでコードだけ残している。

Webに送るのは、現在のデータだけ。時系列の傾向はWeb上で確認する方がずっと便利。

Save2Wev_01 Webにデータをアップロード


計測および計算したデータを、Ambient というサービスに設定したチャネルにデータアップロードする。

Ambient の仕組 

このブロックはM5Stackに用意されていないので、別途Webから、カスタムブロックをダウンロードする。

Webへのアップロード、グラフ化の方法は、参考書 M5Stack入門&実践ガイド に詳しいので、そちらを参照してください。

WDT の更新


初期化と最初のデータのアップロードが終わったら、10秒ごとにWDTを更新します。
try except は無くても良いはずですが、もしも10秒タイマーでエラーが起きたら、すぐにリセットする様にしています。おまじないみたいなものです。

割り込みボタンで、現在の状態を表示する

最初の頃は、10秒ごとに計測を行い、表示をする処理にしていたのですが、画面を見ていない時間の方が圧倒的に多いので、右ボタンが押された時だけ表示する様にしました。

ボタンCが押された時
def buttonC_wasPressed():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  GetEnv()
  ShowEnvMonitor()
  label14.setText('Show 10 sec')
  wait(10)
  lcd.clear()
  pass
btnC.wasPressed(buttonC_wasPressed)

ボタンが押されたら、計測と表示を行い、10秒後に画面をクリアします。

暑さ指数と絶対湿度

暑さ指数と絶対湿度は、それぞれ以下のサイトを参考にしました。

湿度計算の計算式集

https://www.vaisala.com/sites/default/files/documents/Humidity_Conversion_Formulas_B210973JA-F.pdf

def GetWBGT():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  WBGT = 0.725 * (env3_0.temperature)
  WBGT = WBGT + 0.0368 * (env3_0.humidity)
  WBGT = WBGT + (0.00364 * (env3_0.temperature)) * (env3_0.humidity)
  WBGT = WBGT - 3.246

# 絶対湿度の計算
def GetAbsHumi():
  global indx, WBGT, Pws, result, ProgramTitle, YEAR, Current, BARO, MONTH, TEMP, DAY, HUMI, TIME, AbsHUMI, Last2Data, Last1Data, wdt
  Pws = 7.5 * (env3_0.temperature)
  Pws = Pws / (273.15 + (env3_0.temperature))
  Pws = 10 ** Pws
  Pws = 6.11 * Pws
  Pws = ((env3_0.humidity) * Pws) / 100
  AbsHUMI = 2.16679 * Pws
  AbsHUMI = AbsHUMI * (273.15 + (env3_0.temperature))
  AbsHUMI = AbsHUMI / 1000


役に立った!という記事にはぜひサポートお願いします。サポート頂けると大変に励みになります。