スマートメータの計測値がいつでも見られるように、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として書き込むことで、再起動後自動的に実行される。