M5StickC紹介（温湿度測定とMQTT送信、UIFlow Python）


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/cf08f29a-1af6-4abc-4aa5-6c640cda59d6.png)

画面表示（温度、湿度、気圧、電源電圧、MQTT送信間隔）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/0d1523f4-3c47-8f0b-2256-c1189846c925.png)
全UIFlowグラフィカルプログラム（Pythonコードはリアルタイムで自動生成される）

# はじめに
「M5StickC」と「M5StickC ENV Hat（DHT12/BMP280/BMM150搭載）」で、温度、湿度、気圧を測定し、MQTT送信をしてみました。
開発環境は、UIFlow　V1.4.0-Beta　です。（UIFlow V1.3.2 では、ENV Hat に未対応のようです。）
グラフィカルプログラムから、Pythonコードがリアルタイムで生成され、良い感じです。

#### M5StickC は小さく良いです。
48(W)×24(D)×14(H)mm 18.1 g
３個のスイッチ（１つは電源ボタン）、LED、LCDカラーディスプレイ等で、ユーザインターフェースを作れます。
リアルタイムクロック用のボタン電池も内蔵しています。

#### ENV Hat は、M5StickC本体発熱の影響を受けて、温度が高めにでます。
そのままでは使えない感じです。発熱を抑える工夫が必要です。

#### UIFlow IDEのBlockly画面ではグラフィカルにプログラムでき楽しい。

- UIFlow IDE上部にある「Blockly」と「</>Python」で、グラフィカル画面とPythonコード画面の間を行き来できます。
- グラフィカルプログラムは、Pythonコードに反映されますが、逆はできません。
- グラフィカル画面のメニューは、ハードウェアAPIのマニュアル代わりになり便利です。
- グラフィカル画面内にPythonコードを書きたい時は、「高度なブロック」「実行」ブロックを使用します。

UIFlow　V1.4.0-Beta　では、つぎの不具合がありました。

- 文字列に'%'を入力すると、python側では'\%'になってしまう
- LCDの画面レイアウト作成時に設定したプロパティが、時々反映されない。
 
LCD画面レイアウトとハードウェアアクセスをグラフィカル環境で行い、その後グラフィカル環境を捨てて、Pythonコードのみでの開発もできそうです。


# ハードウェア 
### M5StickC 本体
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/6239549d-734a-521d-d365-1551e40a15ec.png)
https://docs.m5stack.com/#/ja/core/m5stickc より

### M5StickC 電源管理
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/afe834ba-0d9e-4069-2599-54a951caf039.png)


https://lang-ship.com/reference/unofficial/M5StickC/Tips/AXP192/ より

### M5StickC ENV Hat（DHT12/BMP280/BMM150搭載）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/4dfe82cd-9667-f5b4-1f69-5ce5a955f083.png)

https://www.switch-science.com/catalog/5755/ より

# プログラム仕様
### LCD画面表示情報
- 温度、湿度、気圧
- 電源電圧
- MQTT送信間隔

### LED点灯
- ハートビート
- MQTT送信

### MQTT送信データ（PC側でのグラフ作成とデータ表示）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/8ed6f8f7-f26c-8545-c829-3df6ba45ae57.png)



# グラフィカルプログラム（Blockly画面）　

### 初期化（MQTT、画面、タイマー）とメインループ（LEDハートビート、センサー読込ループ、中央値計算、LCD表示）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/05bb9ae4-8a9a-ccf1-228e-b67b8c6758d0.png)

### ボタンAとBの処理

- ボタンA（上面、M5マーク）　 LCDオン／オフ、長押しでMQTT送信
- ボタンB（側面） MQTT送信タイマー選択(1/3/30分)、長押しで背景色変更（青／赤）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/d5e8dd90-96b1-55f0-85b6-f6f148210217.png)

### スクリーンセーバタイマー１
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/01447914-ade1-f1ef-f632-9190d1fe22a5.png)


### MQTT送信タイマー２
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78212/552524e0-d44b-6003-ac0b-03dde875f37b.png)


# Python プログラム（自動生成されたプログラム）
グラフィカルプログラムから自動生成されたプログラムを次に示します。
自動生成後の、コード追加と修正は行っていません。

```python:main.py 
from m5stack import *
from m5ui import *
from uiflow import *
from m5mqtt import M5mqtt
import hat

setScreenColor(0x111111)

hat_env0 = hat.get(hat.ENV)

m5mqtt = M5mqtt('M5StickC', '192.168.11.2', 1883, '', '', 300)

label0 = M5TextBox(74, 5, "Text", lcd.FONT_DejaVu18,0xFFFFFF, rotate=90)
label1 = M5TextBox(50, 5, "Text", lcd.FONT_DejaVu18,0xFFFFFF, rotate=90)
label2 = M5TextBox(25, 5, "Text", lcd.FONT_DejaVu18,0xFFFFFF, rotate=90)
label4 = M5TextBox(50, 97, "Text", lcd.FONT_DejaVu18,0xFFFFFF, rotate=90)
label3 = M5TextBox(74, 97, "Text", lcd.FONT_DejaVu18,0xFFFFFF, rotate=90)

from numbers import Number

x = None
LcdOn = None
mqttIntervalMinIndex = None
blueOn = None
ID = None
LcdOffMin = None
mqttIntervalMin = None
mqttIntervalMinList = None
msg = None
tempList = None
humiList = None
presList = None
battList = None
temp = None
humi = None
pres = None
batt = None

def math_median(myList):
  localList = sorted([e for e in myList if isinstance(e, Number)])
  if not localList: return
  if len(localList) % 2 == 0:
    return (localList[len(localList) // 2 - 1] + localList[len(localList) // 2]) / 2.0
  else:
    return localList[(len(localList) - 1) // 2]

def setLcdTimer():
  global x, LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  LcdOffMin = 3
  timerSch.stop('timer1')
  timerSch.run('timer1', (LcdOffMin * (1000 * 60)), 0x00)

def setMqttTimer(x):
  global LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  timerSch.stop('timer2')
  if x:
    timerSch.run('timer2', (mqttIntervalMin * (1000 * 60)), 0x00)


def buttonA_wasReleased():
  global LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, x, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  LcdOn = not LcdOn
  if LcdOn:
    axp.setLDO2Vol(3)
  else:
    axp.setLDO2Vol(0)
  setLcdTimer()
  pass
btnA.wasReleased(buttonA_wasReleased)

def buttonA_pressFor():
  global LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, x, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  setMqttTimer(False)
  ttimer2()
  wait(3)
  setMqttTimer(True)
  setLcdTimer()
  pass
btnA.pressFor(0.8, buttonA_pressFor)

def buttonB_wasReleased():
  global LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, x, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  mqttIntervalMinIndex = 1 + mqttIntervalMinIndex
  if mqttIntervalMinIndex >= 4:
    mqttIntervalMinIndex = mqttIntervalMinIndex - 3
  mqttIntervalMin = mqttIntervalMinList[int(mqttIntervalMinIndex - 1)]
  label4.setText(str((str(mqttIntervalMin) + 'min')))
  setMqttTimer(True)
  setLcdTimer()
  pass
btnB.wasReleased(buttonB_wasReleased)

def buttonB_pressFor():
  global LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, x, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  blueOn = not blueOn
  if blueOn:
    setScreenColor(0x3366ff)
  else:
    setScreenColor(0xff0000)
  axp.setLDO2Vol(3)
  label0.setText('')
  label1.setText('')
  label2.setText('')
  label3.setText('')
  label4.setText('')
  setLcdTimer()
  pass
btnB.pressFor(0.8, buttonB_pressFor)

@timerSch.event('timer1')
def ttimer1():
  global LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, x, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  axp.setLDO2Vol(0)
  LcdOn = False
  pass

@timerSch.event('timer2')
def ttimer2():
  global LcdOn, mqttIntervalMinIndex, blueOn, ID, LcdOffMin, mqttIntervalMin, x, mqttIntervalMinList, msg, tempList, humiList, presList, battList, temp, humi, pres, batt
  M5Led.on()
  msg = temp  + ' ,' + humi + ',' + pres + ',' + batt
  m5mqtt.publish(str('M5StickC'),str(((ID + ((',' + msg))))))
  wait(0.001)
  M5Led.off()
  pass


ID = 'I5001'
m5mqtt.start()
LcdOn = True
axp.setLDO2Vol(3)
blueOn = True
setScreenColor(0x3366ff)
setLcdTimer()
mqttIntervalMinIndex = 3
mqttIntervalMinList = [1, 3, 30]
mqttIntervalMin = mqttIntervalMinList[int(mqttIntervalMinIndex - 1)]
setMqttTimer(True)
while True:
  M5Led.on()
  wait(0.0007)
  M5Led.off()
  tempList = []
  humiList = []
  presList = []
  battList = []
  for count in range(5):
    tempList.append(int(((hat_env0.temperature) * 100)))
    humiList.append(int(((hat_env0.humidity) * 100)))
    presList.append(int(((hat_env0.pressure) * 100)))
    battList.append(int(((axp.getBatVolt()) * 100)))
    wait(0.2)
  temp = (("%.2f"%((math_median(tempList) / 100))) + 'C')
  humi = (("%.2f"%((math_median(humiList) / 100))) + 'pct')
  pres = (("%.2f"%((math_median(presList) / 100))) + 'hPa')
  batt = (("%.2f"%((math_median(battList) / 100))) + 'V')
  label0.setText(str(temp))
  label1.setText(str(humi))
  label2.setText(str(pres))
  label3.setText(str(batt))
  label4.setText(str((str(mqttIntervalMin) + 'min')))
  wait_ms(2)
```

# 関連情報
M5StickC クイックスタート - UIFlow
https://docs.m5stack.com/#/ja/quick_start/m5stickc/m5stickc_quick_start_with_uiflow

M5StickC (M5Stack Docs)
https://docs.m5stack.com/#/ja/core/m5stickc
https://docs.m5stack.com/#/en/uiflow/hardware

m5stack/M5StickC
https://github.com/m5stack/M5StickC

屋根裏実験室 M5Stackを使ってみる
http://itoi.jp/M5Stack.html

M5StickC非公式日本語リファレンス　AXP192の調査
https://lang-ship.com/reference/unofficial/M5StickC/Tips/AXP192/

M5StickC 0.0.7のAXP192追加関数を調べてみた
https://lang-ship.com/blog/?p=696#_LightSleep

M5Stick C とりあえず分解してみた
https://twitter.com/Ghz2000/status/1125058416014176263

BeetleC が　届いた
http://gijin77.blog.jp/archives/20843205.html

パソコン上のM5Stackの3Dモデルを、M5Stackの動きに合わせて動かす
http://pages.switch-science.com/letsiot/rotateM5Stack/

【これは】世界のメイカーズが注目するM5Stack本社に行ってきた!【勝てない】
https://wirelesswire.jp/2019/08/71960/

Adafruit M5Stick-C Pico Mini IoT Development Board
https://www.adafruit.com/product/4290