M5GO(M5Stack)からMQTTで送信

#概要

- M5GO(M5Stack) から MQTT でデータ送信
- MQTT Broker は Mosquitto を使用
- Mosquitto は Raspberry Pi 上に Docker で動かす

##環境

- M5GO (Firmware 0.15)
- Raspberry Pi 3 Model B (Raspbian Stretch)

## Mosquitto 立ち上げ

以下から Dockerfile、docker-entrypoint.sh を取得
https://github.com/eclipse/mosquitto/tree/master/docker/1.4.14

Dockerfileを修正し、動作確認のために mosquitto-clients もインストール

```Docker:Dockerfile

FROM arm32v6/alpine

LABEL Description="Eclipse Mosquitto MQTT Broker"

RUN apk --no-cache add mosquitto mosquitto-clients && \
    mkdir -p /mosquitto/config /mosquitto/data /mosquitto/log && \
    cp /etc/mosquitto/mosquitto.conf /mosquitto/config && \
    chown -R mosquitto:mosquitto /mosquitto

COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["/usr/sbin/mosquitto", "-c", "/mosquitto/config/mosquitto.conf"]
```

Dockerイメージの作成および起動

```
docker build -t rpi-mosquitto .
docker run -d --name mosquitto -p 1883:1883 rpi-mosquitto
```

## MicroPython MQTT Client

M5GO MicroPython の MQTT Client については以下を参照
https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/wiki/mqtt

M5GOから送信する以下の投稿のプログラムを修正し Ambient ではなく MQTT Broker へ送るようにする。
[M5GO(M5Stack)でDHT12とBMP280の気温値を比較](https://qiita.com/inasawa/items/def3b7755e8e28ed4f53)

M5GO Cloudから下に貼ったMicroPythonプログラムを実行

##動作確認

動作確認のために mosquitto_sub を起動。M5GOから送信した気温、湿度、気圧の値が表示されるのを確認。

```
$ docker exec -it mosquitto  mosquitto_sub -t "M5GO/Env"
2018-07-15 16:02:29,28.7,62.1,28.16,1000.77140625
2018-07-15 16:02:30,28.7,62.1,28.16,1000.70984375
2018-07-15 16:02:31,28.7,62.1,28.15,1000.8093359375
2018-07-15 16:02:32,28.7,62.1,28.16,1000.8172265625
　　　　　：　　　　　：　　　　　：
```

##プログラム

```python:
from m5stack import lcd
import machine
import time
import units
import gc
import network


def conncb(task):
    print('MQTT Server [{}] Connected'.format(task))


def disconncb(task):
    print('MQTT Server [{}] Disconnected'.format(task))


# 日本時間に同期
rtc = machine.RTC()
rtc.ntp_sync('ntp.nict.jp', tz='JST-9')
# M5GOのfirmwareがv0.11ではntp_syncでtzを指定するとエラーになるので以下で対応
# rtc.ntp_sync('ntp.nict.jp')
# sys.tz('JST-9')

# 同期が完了するまで100ms程度かかる
for i in range(100):
    if rtc.synced():
        print('synced.')
        break
    print(i, end=' ')
    time.sleep_ms(10)

lcd.font(lcd.FONT_DejaVu18)
lcd.clear()

lcd.print('DHT12',        10,  50)
lcd.print('humidity:',    30,  80)
lcd.print('temperature:', 30, 110)
lcd.print('BMP280',       10, 140)
lcd.print('temperature:', 30, 170)
lcd.print('pressure:',    30, 200)

env = units.ENV(units.PORTA)

mqtt = network.mqtt('raspi', 'mqtt://MQTTサーバー',
                    autoreconnect=True,
                    connected_cb=conncb, disconnected_cb=disconncb)
mqtt.start()

while True:
    #次の秒までの差分（ミリ秒）を求めてスリープ
    time.sleep_ms(1000 - int(time.time() % 1 * 1000))
    
    localtime = time.localtime()
    localtime_str = time.strftime('%Y-%m-%d %H:%M:%S', localtime)
    try:
        # DHT12 から気温と湿度を取得
        env.dht12.measure()
        d_h = env.dht12.humidity()
        d_t = env.dht12.temperature()
        
        # BMP280 から気温と気圧を取得
        b_t, b_p = env.bmp280.values
        
        lcd.print(localtime_str, 10, 10)
        # 表示桁数が減った時に（気圧が1000から999になった時）
        # 後ろを消すのに空白2個入れる
        lcd.print('{:.2f}%  '.format(d_h),   180,  80) # DHT12の湿度
        lcd.print('{:.2f}C  '.format(d_t),   180, 110) # DHT12の気温
        lcd.print('{:.2f}C  '.format(b_t),   180, 170) # BMP280の気温
        lcd.print('{:.2f}hPa  '.format(b_p), 180, 200) # BMP280の気圧
        
        if mqtt.status()[0] == 2: # (2, 'Connected')
            mqtt.publish('M5GO/Env', '{},{},{},{},{}'.format(
                                localtime_str, d_t, d_h, b_t, b_p))
        else:
            print(localtime_str, ' MQTT Status: ', mqtt.status())
        
    except Exception as e:
        # 時々I2C bus error が起きる。
        # データを取得できなかった時は時刻を赤字で表示
        lcd.print(localtime_str, 10, 10, lcd.RED)
        print(localtime_str, ' Script Name: ', __name__)
        print('Exception: ', e)
    
    gc.collect()
```