chakokuのブログ(rev4)

日々のごった煮ブログです

ESP32+MicroPython+MQTTでAWS IoTと接続、メッセージ受信して、サーボを動かす

スマートメータの計測値がいつでも見られるように、ESP32 + Servoでメータを作ろうとしています(基本はおもちゃ)。
まだ清書できていませんが、MicroPythonで書いた、AWS IoT接続→Subscribe→サーボ制御のソースは以下

import machine
import json
from umqtt.simple import MQTTClient

ENDPOINT = b'a3bxxxxxxkf7t-ats.iot.ap-northeast-1.amazonaws.com'
ID = 'basicPubSub'
TOPIC = "topic_1"

KEYFILE = '/certs/priv.key'
CERTFILE = "/certs/cert.pem"

SRV_DUTY_MIN = 35
SRV_DUTY_MAX = 118

power_val = 0        # Smart meter readings

servo_pwm = None
SERVO_PWM_PIN = 12
def servo_setup():
    global servo_pwm
    servo_pwm = machine.PWM(machine.Pin(SERVO_PWM_PIN), freq=50, duty=SRV_DUTY_MAX) 

# value:  0t - 1000
def servo(i):
    global servo_pwm
    servo_pwm.duty(int(SRV_DUTY_MAX - (SRV_DUTY_MAX - SRV_DUTY_MIN)*i / 1000))

def _cb(topic, msg):
    global power_val
    print("-------- call back ----------")
    print("topic:{}".format(topic))
    print("msg:{}".format(msg))
    print("-----------------------------")
    val = json.loads(msg.decode())['val']
    power_val = int(val)
    if power_val >= 1000:
       power_val = 999

#
#
#
with open(KEYFILE, 'r') as f:
    key = f.read()

with open(CERTFILE, 'r') as f:
    cert = f.read()

# SSL certificates.
SSL_PARAMS = {'key': key, 'cert': cert, 'server_side': False}
client = MQTTClient(client_id=ID, server=ENDPOINT, port=8883, ssl=True, ssl_params=SSL_PARAMS)

client.set_callback(_cb)
client.connect()
client.subscribe(topic=TOPIC)

servo_setup()

while True:
   print("---loop---------------")
   client.wait_msg()
   print("power val:{}".format(power_val))
   servo(power_val)

長時間動かすと、wait_msgでExceptionが発生する問題があるが、スマートメータで計測した値がPublishされた時に、サーボのアームが動くところまではできた。(瞬時値:0W~1000Wまで連動)
スマートメータの瞬時値と積算値はNature Remo E Liteで取得してNature社のサーバに上がっているので、Nature社のAPIを叩いて、AWS IoTにPublishする。配信されるメッセージの電文

'{"name": "measured_instantaneous", "epc": 231, "val": "240", "updated_at": "2022-04-23T12:26:13Z"}'

今後の取り組み

  1. Nature社のAPIを叩いてPublishするプログラムがRPi上で動作しているので、そのプログラムをAWS Lambdaに移す
  2. 上記Lambdaを定期的に呼び出すCRONを仕込む
  3. FlutterでMQTT試作したが、接続先をAWS IoT Coreに変更する
  4. 24時間CRONが走るのは無駄で、お金がかかってしょうがないので、Client接続がある時だけCRONが走るようにする
  5. 開発終わり

■追記
長時間運用すると、セッションが遮断されるのか、wait_msg()でExceptionが発生する(本当に接続がきれるのか?は未調査)。場当たり的だが、Exceptionが発生したら自分でリセットするように仕込む

while True:
   print("---loop---------------")
   try:
       client.wait_msg()
       print("power val:{}".format(power_val))
       servo(power_val)
   except Exception as e:
       print("Except at wait_msg")
       print(e)
       print("restart")
       machine.reset()       

REPLで貼り付けるだけだと、リセットがかかると全部消えるので、上記プログラムをflash上のファイル main.pyとして書き込むことで、再起動後自動的に実行される。