プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

エアコンをSlackでスマートリモコン化の効果を温湿度センサで測定する【2020年版】

3年目となるラズパイによるスマートリモコンの改良です。
s51517765.hatenadiary.jp
s51517765.hatenadiary.jp
s51517765.hatenadiary.jp

昨年のスマートリモコンに温湿度・気圧センサーを連携します。
f:id:s51517765:20200522124824p:plain

これまでの、エアコンをSlackで操る機能はそのままに、温湿度・気圧センサーもslackで取得できるようにしました。
f:id:s51517765:20200522123412j:plain
「温度」「湿度」といったキーワードに反応して温湿度・気圧センサーにアクセスします。

#plugins.py

@listen_to(u'(温|tem|湿|環)+')
@respond_to(u'(温|tem|湿|環)+')
def temp(message, something):
    try:
        env_result = bme280.main()  #センサーにアクセス
        message.reply(env_result)  #センサーからの応答をslackに返す
    except NameError as e:
        print(e)
        message.reply("NameError. airconSet.py")
    except Exception as e:
        print(e)
        message.reply("指示を解釈できませんでした。")

センサーのスクリプトでは、温度、気温、気圧を文字列にして返します。
また、呼ばれるごとに、日付時刻と温度、気温、気圧をcsv形式で書き出しておきます。
これで、データを収集してExcelで解析しやすくなります。

#bme280.py

def main():
    print("BME280 Start!")
    tdatetime = dt.datetime.now()
    try:
        sensor = Bme280()
        Pres = "{:.1f}".format(sensor.getPressure())
        Temp = "{:.1f}".format(sensor.getTemperature())
        Hum = "{:.1f}".format(sensor.getHumidity())
        env_result = str(Pres)+"hPa / "+str(Temp)+"deg / "+str(Hum) + "%"
        print(env_result)
        file = open('env_result.txt', 'a', encoding='utf')  # 追記モードでオープン
        file.write(str(tdatetime)+", "+Pres + ", "+Temp+", "+Hum+"\n")
        return env_result
    except Exception as e:
        print(tdatetime)
        print("Error in BME280")
        print(e)

Slackからの応答の様子。
f:id:s51517765:20200521212535j:plain

また、bme280.pyをslackBotと並行で起動しておくことで、1時間ごとに温度、気温、気圧を取得します。
これでエアコンの設定が変わったときの様子が見れるはずです。

#bme280.py

def get_env_loop(inerval=3600):
    while (True):
        main()
        time.sleep(inerval)

if __name__ == '__main__':
    get_env_loop()

Pythonによる並列化

これを実現するためにSlackBot.main()bme280.get_env_loop()を並列化します。
ラズパイでターミナルを2つ起動してPyhtonを2つ起動するという形でも実現可能ですが、せっかくなのでPythonの並列化threadingを利用します。

並列処理、並行処理、マルチプロセス、マルチスレッド…など似たような言葉が多くありますが、これらの違いについては↓がわかりやすかったです。
qiita.com
今回はその中から並列化threadingがやりたいことになります。

Qiitaのサンプルがわかりやすかったのでそのまま使いました。

#main.py

# -*- coding: utf-8 -*-
import slackBot
import bme280
import datetime as dt
import threading

def worker1():
    slackBot.main()

def worker2():
    bme280.get_env_loop()

if __name__ == "__main__":
    print("Main Start!")
    t1 = threading.Thread(target=worker1)
    t2 = threading.Thread(target=worker2)
    t1.start()
    t2.start()

ここではDebug用に30秒ごとに環境を取得していますが、SlackBot.main()の応答とbme280.get_env_loop()が両方動いていることが確認できました。
f:id:s51517765:20200523225228j:plain

トラブったこと

コーディングはリビングで実施していて、ほぼ完成したところで寝室にラズパイを設置しました。
このとき、電源のUSBケーブルを長いものに変更したら温湿度センサがErrorになるということが起きました。
Pythonは正常に動いているのに、i2cでのセンサだけ不能という現象が発生。

ソースコード・回路図等の全貌

github.com