🔲

ESP32 - MicroPythonで家電を制御しよう-その4(イベント管理)

2021/08/08に公開

ESP32を使って、IFTTTサービスにリクエストを送り、家電を制御します。その仕組みとコードの部分について説明します。
全体像は、その1(コンセプト、スイッチ)を参照してください。
本記事は、イベント管理スレッドについての説明です。

関連記事

イベント管理スレッド

概要

イベント管理スレッドは、名前の通りイベントの交通整理/ロジック管理するためのスレッドです。
本スレッドは、直接ハードウェアの制御は行いません。
現状、アクターからの入力はスイッチのみですが、ロータリーエンコーダなどに変更された場合、
本スレッドがないと他のスレッドのインターフェースに大きく影響を与えてしまいます。

開発環境の構築

開発環境の構築は、下記の記事を参考にしてください。

https://zenn.dev/kotaproj/articles/d969fb39100da443f41f
https://qiita.com/kotaproj/items/b53006aef9d04053a5ee

コード(イベント管理スレッド)

プログラム全体となるため、全ファイルが必要となります。
下記のレポジトリにまとめています。

https://github.com/kotaproj/supportWebhooksBd/tree/master/esp_zenn

presenter.py
import _thread
import time

from util import *

class PreProc():
    
    def __init__(self, lock=None, snd_ques=None, rcv_ques=None):

        self._lock = lock
        self._snd_ques = snd_ques
        self._rcv_ques = rcv_ques
        return


    def _command_sw(self, msg):
        print("pre_command_sw:run")
        d = conv_msg2dict(msg)
        print(d)
        send_que(self._lock, self._snd_ques["httpc"], ("dst:httpc,src:pre,cmd:sw,type:"+d["type"]+",how:"+d["how"]))
        return

    def _command_dsp(self, msg):
        print("pre_command_dsp:run")
        msg = msg.replace("dst:pre,src:httpc,", "dst:dsp,src:pre,")
        send_que(self._lock, self._snd_ques["dsp"], msg)
        print("pre_command_dsp:over")
        return

    def _command_led(self, msg):
        print("pre_command_led:run")
        msg = msg.replace("dst:pre,src:httpc,", "dst:led,src:pre,")
        send_que(self._lock, self._snd_ques["led"], msg)
        print("pre_command_led:over")
        return


    def _proc_pre(self):
        while True:
            # recvive_que
            for key, rcv_q in self._rcv_ques.items():
                msg = recv_que(self._lock, rcv_q)
                if msg is None:
                    # print("IndexError")
                    continue
                print("proc_presenter:msg - ", msg)
                command = conv_msg2dict(msg)['cmd']
                if "sw" == command:
                    self._command_sw(msg)
                elif "dsp" == command:
                    self._command_dsp(msg)
                elif "led" == command:
                    self._command_led(msg)
                else:
                    print("proc_presenter:error - ", msg)
            time.sleep_ms(10)
        return


    def run(self):
        _thread.start_new_thread(self._proc_pre, ())


def main():

    lock = _thread.allocate_lock()

    from sw import SwProc
    que_sw2pre = []
    sw_proc = SwProc(lock, snd_que=que_sw2pre)
    sw_proc.run()

    from led import LedProc
    que_pre2led = []
    led_proc = LedProc(lock, rcv_que=que_pre2led)
    led_proc.run()

    from httpc import HttpcProc
    que_httpc2pre = []
    que_pre2httpc = []
    httpc_proc = HttpcProc(lock, snd_que=que_httpc2pre, rcv_que=que_pre2httpc)
    httpc_proc.run()

    from dsp import DspProc
    que_pre2dsp = []
    dsp_proc = DspProc(lock, rcv_que=que_pre2dsp)
    dsp_proc.run()

    que_snds = {
        "led" : que_pre2led,
        "httpc" : que_pre2httpc,
        "dsp" : que_pre2dsp,
    }
    que_rcvs = {
        "sw" : que_sw2pre,
        "httpc" : que_httpc2pre,
    }

    pre_proc = PreProc(lock, que_snds, que_rcvs)
    pre_proc.run()

    time.sleep(10_000)
    return

if __name__ == "__main__":
    main()

実行方法と結果

croPython v1.16 on 2021-06-23; ESP32 module with ESP32
Type "help()" for more information.
>>> import presenter
>>> presenter.main()
led:init
LedCtl - init
dsp:__init__ - run
OledCtl - init
Warning: I2C(-1, ...) is deprecated, use SoftI2C(...) instead
dsp:_proc_dsp - run
_proc_poll - run
_proc_poll - run
connecting to network...
.
network config: ('192.168.XX.x', '255.255.255.0', '192.168.XX.1', '192.168.XX.1')
proc_presenter:msg -  dst:pre,src:httpc,cmd:dsp,type:clear
pre_command_dsp:run
pre_command_dsp:over
dsp:stop_timer - run
proc_dsp:msg -  dst:dsp,src:pre,cmd:dsp,type:clearproc_presenter:msg -  
dsp:act_dsp - run
dst:pre,src:httpc,cmd:led,type:off_alldsp:act_dsp - over

pre_command_led:run
pre_command_led:over
proc_led:msg -  dst:led,src:pre,cmd:led,type:off_all
act_led_led:run
{'cmd': 'led', 'type': 'off_all', 'dst': 'led', 'src': 'pre'}
led:_act_cmd - over
proc_presenter:msg -  dst:pre,src:httpc,cmd:led,type:blink,name:green
pre_command_led:run
pre_command_led:over
proc_led:msg -  dst:led,src:pre,cmd:led,type:blink,name:green
act_led_led:run
{'name': 'green', 'src': 'pre', 'dst': 'led', 'cmd': 'led', 'type': 'blink'}
led:_act_cmd - over
dst:pre,src:sw,cmd:sw,type:no1,how:pressed
proc_presenter:msg - dst:pre,src:sw,cmd:sw,type:no1,how:released
 dst:pre,src:sw,cmd:sw,type:no1,how:pressed
pre_command_sw:run
{'src': 'sw', 'dst': 'pre', 'cmd': 'sw', 'how': 'pressed', 'type': 'no1'}
proc_httpc:msg -  dst:httpc,src:pre,cmd:sw,type:no1,how:pressed
act_httpc:run
{'src': 'pre', 'dst': 'httpc', 'cmd': 'sw', 'how': 'pressed', 'type': 'no1'}
None
proc_presenter:msg -  dst:pre,src:sw,cmd:sw,type:no1,how:released
pre_command_sw:run
{'src': 'sw', 'dst': 'pre', 'cmd': 'sw', 'how': 'released', 'type': 'no1'}
proc_httpc:msg -  dst:httpc,src:pre,cmd:sw,type:no1,how:released
act_httpc:run
{'src': 'pre', 'dst': 'httpc', 'cmd': 'sw', 'how': 'released', 'type': 'no1'}
sw1
proc_presenter:msg -  dst:pre,src:httpc,cmd:dsp,type:ifttt,how:sw1,sts:sending...,tmr:3000
pre_command_dsp:run
pre_command_dsp:over
dsp:stop_timer - run
proc_dsp:msg -  dst:dsp,src:pre,cmd:dsp,type:ifttt,how:sw1,sts:sending...,tmr:3000
dsp:act_dsp - run
dsp:dsp_ifttt - run
dsp:start_timer - run 3000
dsp:act_dsp - over
proc_presenter:msg -  dst:pre,src:httpc,cmd:led,type:blink,name:blue
pre_command_led:run
pre_command_led:over
proc_led:msg -  dst:led,src:pre,cmd:led,type:blink,name:blue
act_led_led:run
{'name': 'blue', 'src': 'pre', 'dst': 'led', 'cmd': 'led', 'type': 'blink'}
led:_act_cmd - over
proc_presenter:msg -  dst:pre,src:httpc,cmd:dsp,type:ifttt,how:sw1,sts:sended.,tmr:3000
pre_command_dsp:run
pre_command_dsp:over
dsp:stop_timer - run
proc_dsp:msg -  dst:dsp,src:pre,cmd:dsp,type:ifttt,how:sw1,sts:sended.,tmr:3000
dsp:act_dsp - run
dsp:dsp_ifttt - run
dsp:start_timer - run 3000
dsp:act_dsp - over
dsp:_set_event_clear - run

ポイント

キューの管理

  • イベント管理スレッドには、すべてのキューを渡します。
    • que_snds : イベント管理スレッドから送信するキューを辞書で渡す
    • que_rcvs : イベント管理スレッドで受信するキューを辞書で渡す
  • que_rcvsを定期的に監視し、必要なイベントをque_sndsを経由して通知する

基本的なシーケンス

以下が基本動作となります。

さいごに

その1-4までで、約2年ほど前につくった電子工作を紹介しました。
説明のために、以下の機能を割愛しました。

  • サーバモード
    • アクセスポイント情報、トークン情報の登録画面
  • 設定ファイル
    • テキストファイルとして設定情報を保持
  • ロータリーエンコーダ
    • ロータリーエンコーダも搭載している
  • 電池駆動
    • 電池で動くようになっている

フル機能のソースコードは、下記のレポジトリに配置してあります。

https://github.com/kotaproj/supportWebhooksBd

テレビのオンオフ、エアコンの制御、扇風機の制御と活躍しています。

GitHubで編集を提案

Discussion