スマートメータの計測値がいつでも見られるように、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"}'
今後の取り組み
- Nature社のAPIを叩いてPublishするプログラムがRPi上で動作しているので、そのプログラムをAWS Lambdaに移す
- 上記Lambdaを定期的に呼び出すCRONを仕込む
- FlutterでMQTT試作したが、接続先をAWS IoT Coreに変更する
- 24時間CRONが走るのは無駄で、お金がかかってしょうがないので、Client接続がある時だけCRONが走るようにする
- 開発終わり
■追記
長時間運用すると、セッションが遮断されるのか、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として書き込むことで、再起動後自動的に実行される。