HSP3でM5GOからのMQTTパブリッシュを受信

## 概要

HSP3 で M5GO からのMQTT パブリッシュを受信してみました。

事前に Wi-Fiルータに HSP3 が動作する Windows PC と M5GO がぶらさがっている環境ができていることを前提としています。

公式ページはこちら。
[M5stack UIFlow 公式ページ](https://m5stack.github.io/UIFlow_doc/ja/)

注: ユーザー認証などしていませんのでセキュリティなどはご自身で留意してください。
またHSP3側のMQTT実装もM5GOからのパブリッシュを受信するのに必要な機能のみの実装となっています。

## HSP3側
下記コードを実行します。

```hs
#include "hspsock.as"

#enum T_CONNECT = 1
#enum T_CONNACK
#enum T_PUBLISH
#enum T_PUBACK
#enum T_PUBREC
#enum T_PUBREL
#enum T_PUBCOMP
#enum T_SUBSCRIBE
#enum T_SUBACK
#enum T_UNSUBSCRIBE
#enum T_UNSUBACK
#enum T_PINGREQ
#enum T_PINGRESP
#enum T_DISCONNECT

	sdim head,64
	sdim wbuf,256
	pid = 1
	pingnum = 0
	
*main
	port = 19499
	ipget
	mes "このPCのアドレスとポート " + refstr + ":" + port
	sockmake 0, port
	if stat {
		dialog "Socket error"
		goto *errbye
	}
	a = 0
	repeat
		sockwait 0
		title "TCP接続待ち " + a
		if stat > 1 {
			dialog "Socket error"
			goto *errbye
		}
		if stat == 0 {
			break
		}
		a ++
		wait 10
	loop

	mes "クライアントが接続しました"

*main01
// ヘッダの受信
	offset = 0
	reqb = 2

*main03
	sockcheck
	result = stat
	if result >= 2 {
		mes "error, " + result
		goto *bye
	}

	c ++
	title "head sockgetb calling - " + c
	wait 1

	if result == 1 {
		goto *main03
	}

	sockgetb head,offset,reqb
	result = stat

	offset += result
	reqb -= result

	if offset < 2 {
		goto *main03
	}

*main05
	title "sockgetb done - " + result
	wait 1

	h0 = peek(head, 0)
	h1 = peek(head, 1)
	retain = h0 & 1
	qos = (h0 >> 1) & 3
	dupf = h0 & 0x08
	mt = h0 >> 4

	len = h1
	if len > 127 {
		mes "可変長には非対応"
		wait 1
		repeat
			reqb = 1
			sockgetb head,offset,reqb

			result = stat
			cur = peek(head, offset)

			offset += result
			reqb -= result

			if cur <= 127 {
				break
			}
			if offset >= 5 {
				break
			}
		loop
		len = 0
		repeat offset - 1
			len = (len << 7) | (peek(head, offset - 1 - cnt) & 0x7f)
		loop
		mes "len, " + len
	}

	if mt != T_PINGREQ {
		mes "" + retain + ", q:" + qos + ", " + dupf + ", " + mt + ", " + len
	}

	if len == 0 { // 0バイトならskip
		goto *main11
	}

	sdim buf,len
	offset = 0
	reqb = len

*main09
	sockgetb buf, offset, reqb
	rb = stat
	offset += rb
	mes "read, " + rb + " / " + reqb + " / " + len
	wait 1

	if offset < len {
		reqb = len - offset
		goto *main09
	}

	s = ""
	repeat len
		s += strf(",%02x", peek(buf, cnt))
	loop
	mes s

*main11

	if mt == T_CONNECT {
		mes " C->S 接続"

		sdim sbuf,64
		poke sbuf,0, (T_CONNACK << 4)
		poke sbuf,1,2
		
		poke sbuf,2,0x00
		poke sbuf,3,0x00 // 接続許可 0x00

		sockputb sbuf, 0, 4

		mes " S->C 接続ACK, " + stat

		goto *main01
	}
	if mt == T_PUBLISH {
		mes "C->S 発行"

		roffset = 0
		tlen = (peek(buf, 0) << 8) | peek(buf, 1)
		roffset += 2
		sdim tstr, tlen+1
		memcpy tstr,buf, tlen, 0,roffset
		roffset += tlen

		// アプリケーション定義
		alen = len - roffset
		sdim astr, alen + 1
		memcpy astr,buf, alen, 0,roffset

		x = ginfo(22)
		y = ginfo(23)

		color 255,255,255
		boxf 320,360, 640,480
		color 0,0,0
		pos 320,360
		mes "" + tstr + " " + astr

		if y > 3000 {
			x = 0
			y = 0
			color 255,255,255
			boxf 0,0, 640,480
			color 0,0,0
		}
		pos x,y

		goto *main01
	}
	if mt == T_SUBSCRIBE {
		mes " C->S 購読"

		mid = (peek(buf, 0) << 8) | peek(buf, 1)

		sdim sbuf,64
		poke sbuf, 0, (T_SUBACK << 4)
		poke sbuf, 1, 3
		poke sbuf, 2, (mid >> 8) & 0xff
		poke sbuf, 3, (mid & 0xff)

		repeat 1
			poke sbuf, 4 + cnt, 0x00 // Suc QoS 0
		loop

		sockputb sbuf, 0, 5
		mes " S->C 購読ACK, " + stat

		goto *main01
	}
	if mt == T_PINGREQ {
		pingnum ++
		x = ginfo(22)
		y = ginfo(23)
		color 255,255,255
		boxf 320,240, 640,360
		color 0,0,0
		pos 320,240
		mes " C->S PING 要求, " + pingnum + "回目"

		sdim sbuf,64
		poke sbuf, 0, (T_PINGRESP << 4)
		poke sbuf, 1, 0
		sockputb sbuf, 0, 2
		mes " S->C PING 応答, " + stat

		pos x,y
		
		goto *main01
	}
	goto *main01


*bye
	sockclose
	goto *main


*errbye
	sockclose
	mes "終了"
	stop
```

|HSP3 実行結果1|
|:---:|
|![pubserv2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/ed9dbd39-92bb-8bd8-0852-d8188e449a1c.png)|
|接続待ちを開始|

自分のIPアドレスとポート番号はM5GOで使用します。

## M5GO側

M5GO側は M5Flow で以下のようなブロックを組みます。

|M5Flow uiFLOW ブロック構成|
|:---:|
|![pub2flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/7ada62ec-d975-624e-3e43-a87f78701ebd.png)|
|server,portにはHSP3側のIPアドレスを指定する|

M5GO で mqtt を使用するには RUN ではなく Download ダウンロード で転送する必要があります。
M5GO に Download ダウンロード を指定すると再起動がかかります。
M5GO がうまく起動するとHSP3ソフト側に接続します。

|HSP3 実行結果2|
|:---:|
|![pubopen2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/a29692b6-202a-cbc0-6847-94d88e8c8a83.png)|
|![pubclose2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/bca36588-0b85-b110-1925-06e223c6f996.png)|


M5GO の左ボタンを押すと HSP3 側で open と表示されます(図上)。
M5GO の中ボタンを押すと HSP3 側で close と表示されます(図下)。

## 参考

* [MQTT Version 3.1.1 Plus Errata 01](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html)

## オマケ

2019年10月12日 に日本のどこかで M5GO に同梱されている環境センサーで気圧測定してみました。ところどころ抜けているのは受信側のエラーを放置していて取りこぼしたところです。

|気圧測定|
|:---:|
|![pre20191012_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/213145/f308b4bf-1cdc-7296-f478-7fc6b2add68f.png)|

グラフの元データは、本記事の方法をベースに、M5GO 側は環境センサーの気圧値の定期送信とHSP3 側は受信内容のファイル出力を追加して収集しました。