M5Stackの SIM7080G-CAT-M-NB-IOT-UNITでEmail送信（１）

M5Stackから発売されている IOT-BASE-WITH-CAT-M-MODULE-SIM7080GやSIM7080G-CAT-M-NB-IOT-UNITをUI FLOWを使用してEmailを送信するプログラムを作ってみました。最近発売されたM5STAMP-CAT-M-MODULE-SIM7080Gも同じチップを使っているのでちょっと修正すれば使えると思います。
なお、SIM7080Gそのものは技適取得済ですが、アンテナが認証取得していないのではないかとの話があるので自己責任でお願いします。

公式HPにあるサンプルプログラムにはMQTT用しかありません。そこでHPにあるチップSIM7080Gのマニュアルからサンプルを作ります。

Arduino　IDEでのMQTT用サンプルはGitHubにあります。
https://github.com/m5stack/M5_SIM7080G

SIM7080GのEmail用コマンドとその他のATコマンドはこちら
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/unit/sim7080g/en/SIM7070_SIM7080_SIM7090%20Series_Email_Application%20Note_V1.02.pdf
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/unit/sim7080g/en/SIM7070_SIM7080_SIM7090%20Series_AT%20Command%20Manual_V1.04.pdf

IOT-BASE-WITH-CAT-M-MODULE-SIM7080G
https://docs.m5stack.com/en/base/iot_base_catm

SIM7080G-CAT-M-NB-IOT-UNIT
https://docs.m5stack.com/en/unit/cat_m

M5STAMP-CAT-M-MODULE-SIM7080G
https://docs.m5stack.com/en/stamp/stamp_catm

IOT-BASE-WITH-CAT-M-MODULE-SIM7080GはM-BUSで接続されます。
RX:G0、TX:G35でUART baud 115200 8N1
SIM7080G-CAT-M-NB-IOT-UNITの場合はGroveコネクタを使用しますのでStickC/StickCPlusなら
RX:G33、TX:G32とします。

今回はSIM7080G-CAT-M-NB-IOT-UNITとM5StickCを使用します。

メールサーバーですが、ここではNiftyの物を使用します。本来ならGmailとかがよいのですが、安全性の低いアプリと Google アカウントについて「アカウントを安全に保つため、2022 年 5 月 30 日より、Google は、ユーザー名とパスワードのみで Google アカウントにログインするサードパーティ製のアプリとデバイスについてサポートを終了いたします。」となってしまったので、IoT機器から簡単にメールが送れなくなってしまったためです。

ここではNiftyのメールアドレスをabc123456@nifty.com、送信先のメールアドレスをsendto@gmail.comとしておきます。SIMはSORACOMのIoT SIM Plan-D Docomo 330円／月の物を使用しています。
SORACOM　SIMのAPNは以下の通りです。
APN : soracom.io
ユーザー名 : sora
パスワード : sora
PDP Type : IP
認証タイプ : CHAP or PAP

先にUIFLOWのBLOCKで作成し、Pythonに変換したコードを紹介します。
使用したコントローラはM5StickCです。
UARTでモデムにATコマンドを送信、Label0に応答を表示します。
モデムがネットワークに接続されるとLabel2に「OK」と表示されるので
ボタンＡを押すことでテストメールが送信できます。

~~~UNIT_CATM_EMAIL.py
from m5stack import *
from m5ui import *
from uiflow import *
lcd.setRotation(3)
import time

setScreenColor(0x111111)

readstr = None

label0 = M5TextBox(0, 0, "Text", lcd.FONT_DefaultSmall, 0xFFFFFF, rotate=0)
label1 = M5TextBox(0, 55, "Text", lcd.FONT_DefaultSmall, 0xFFFFFF, rotate=0)

def buttonB_wasPressed():
  global readstr, uart1
  uart1.write('AT+CNACT?'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  uart1.write('AT+CGNAPN'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  uart1.write('AT+CGATT?'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  pass
btnB.wasPressed(buttonB_wasPressed)

def buttonA_wasPressed():
  global readstr, uart1
  uart1.write('AT+EMAILCID=0'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPSRV="smtp.nifty.com",587'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPAUTH=1,"abc123456@nifty.com","Password"'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPFROM="abc123456@nifty.com","senusername"'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPRCPT=0,0,"sendto@gmail.com","sendusername"'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPRCPT=1,0,"abc123456@nifty.com","sendusername"'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPSUB="Test"'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPBODY=19'+"\r\n")
  wait(1)
  uart1.write('This is a new Email'+"\r\n")
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+SMTPSEND'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  pass
btnA.wasPressed(buttonA_wasPressed)

uart1 = machine.UART(1, tx=32, rx=33)
uart1.init(115200, bits=8, parity=None, stop=1)
wait(2)
uart1.write('AT+CREBOOT'+"\r\n")
wait(1)
uart1.write('AT+CSQ'+"\r\n")
wait(1)
label0.setText(str(uart1.read()))
uart1.write('AT+COPS=1,2,44010'+"\r\n")
wait(1)
label0.setText(str(uart1.read()))
uart1.write('AT+CMNB=1'+"\r\n")
wait(1)
label0.setText(str(uart1.read()))
uart1.write('AT+CGNAPN'+"\r\n")
wait(5)
label0.setText(str(uart1.read()))
uart1.write('AT+CNACT=0,1'+"\r\n")
wait(1)
label0.setText(str(uart1.read()))
while True:
  uart1.write('AT+SECMAUTH?'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  uart1.write('AT+CNACT=0,1'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  uart1.write('AT+CNTPCID?'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  uart1.write('AT+CNTP="jp.pool.ntp.org",9'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  uart1.write('AT+CNTP'+"\r\n")
  wait(1)
  label0.setText(str(uart1.read()))
  uart1.write('AT+CCLK?'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  uart1.write('AT+CNACT?'+"\r\n")
  wait(1)
  readstr = uart1.read()
  label0.setText(str(str(readstr)))
  if str(readstr).count('0,1,"10') == 1:
    break
label1.setText('OK')
~~~

では順番に説明しましょう。ATコマンドは長いので、全部表示させるためにはじめに画面を90度回転させておきます。そのあとでUART1をTX:32、RX:33、baud rate:115200で設定します。
IOT-BASE-WITH-CAT-M-MODULE-SIM7080Gを使う場合はModuleの中にIoT Base CatMというものがあるのですが、モデムのEmail用のコマンドはないのでほとんど使えません。
![initial.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1108028/41d8c6ac-9579-89e8-93bc-ee3a7e43d369.jpeg)
そのあとはモデムの設定をひたすら行っていきます。
AT+CREBOOT：モデムをリブート
AT+CSQ：信号品質を確認
AT+COPS=1,2,44010：オペレータをDocomo回線にする設定コマンドです。
AT+CMNB=1：CAT-MかNB-IoTを選ぶコマンドです。1がCAT-Mです。
AT+CGNAPN：APNを使用するためのコマンドです。
AT+CNACT=0,1：APPネットワークを設定します。
UARTへテキストを1行書き込むコマンドを使用し、少し待ち時間を設けた後UARTから応答を読み込み、Label0に表示します。
モデムは普通のネットワーク機器と違い応答が遅いので待ち時間を多めに入れています。
ここからネットワークの状態監視を行います。
![loop1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1108028/6afbf360-c650-c915-0954-567ae8ed7c04.jpeg)
AT+SECAUTH?：デバッグ用にAPNでの認証状態を確認するコマンドです。
AT+CNACT=0,1：APPネットワークをアクティブにします。
AT+CNTPCID?：GPRS Bearer Profile’s IDを取得するコマンドです。
AT+CNTP="jp.pool.ntp.org",9：NTPサーバーを設定するコマンドです。
AT+CNTP：NTPサーバに時刻を同期するコマンドです。
AT+CCLK?：時刻を取得するコマンドです。
![loop2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1108028/cb2a869d-c293-0896-8b87-e0b13d176e6d.jpeg)
AT+CNACT?：IPアドレスを取得できます。ネットワークに接続できていない場合はIPアドレスが0.0.0.0となるので、その場合はループし、接続されればループを抜けます。今回は取得できたIPアドレスが10.*.*.*だったため、それを条件にしました。
Label1に「OK」を表示して待機します。

次はEmail送信ですが、少し長くなったので記事を分けます。