15
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

リモートワークを快適にする換気システムを作ってみた

Last updated at Posted at 2022-04-15

はじめに

リモートワーク中、頭がぼーっとするときはありませんか?
そんなときはもしかすると、部屋の二酸化炭素濃度が高いかもしれません。

この記事では、Raspberry Pi(以降、RPi)、CO2センサ、Nature Remo 3、および Amazon Echo(以降、Echo)を用いて、リモートワークを快適にする換気システムを作る方法について、解説します。

この換気システムを使用すれば、換気が必要なタイミング・換気が完了したタイミングを Echo に教えてもらうことができます

換気システムの全体像

換気システムの全体像

換気システムの機能

  • CO2センサから取得した二酸化炭素濃度の値、Nature Remo 3 から取得した温度・湿度・照度の値(以降、各センサの値)をスプレッドシートに記録
  • スプレッドシートに記録した各センサの値をグラフ化し、Web に公開
  • 現在の各センサの値を Echo に教えてもらう
  • 換気が必要なタイミングを Echo に教えてもらう
  • 換気が完了したタイミングを Echo に教えてもらう

使用機材

  • RPi:Raspberry Pi 3 Model B
  • CO2センサ:MH-Z19B
  • 温度・湿度・照度センサ:Nature Remo 3

温度・湿度・照度が必要なければ、Nature Remo 3 は用意しなくても大丈夫です。

各機能の実装

RPi に接続した CO2センサから二酸化炭素濃度を取得

RPi と CO2センサをジャンパワイヤで接続

シリアル通信を有効化

  • $ sudo raspi-config を実行して下記の順番で画面を操作し、設定を変更
    1. Interfacing Options
    2. Serial Port
    3. Would you like a login shell to be accessible over serial ? → <No>
    4. Would you like the serial port hardware to be enabled ? → <Yes>
    5. The serial login shell is disabled The serial interface is enabled → <Ok>
  • $ sudo reboot を実行し、設定を反映

必要なライブラリをインストール

  • $ pip install mh-z19 を実行
  • 参考:mh-z19

動作確認

  • 下記の get_co2.py を実行
    • /home/pi/.virtualenvs/py3/bin/python は適宜変更(例:$ which python の実行結果など)
    get_co2.py
      import subprocess
      import json
    
    
      def get_co2():
          cmd = ['sudo', '/home/pi/.virtualenvs/py3/bin/python', '-m', 'mh_z19']
          res = subprocess.check_output(cmd).decode()
          co2 = json.loads(res)['co2']
    
          return co2
    
    
      if __name__ == '__main__':
          co2 = get_co2()
          print(co2)
    

CO2センサから取得される二酸化炭素濃度のキャリブレーション

  • 下記を実行し、CO2センサを屋外(400ppm)に20分間放置
      $ python
      >>> import mh_z19
      >>> mh_z19.zero_point_calibration()
    

NatureRemoAPI を叩いて Nature Remo 3 から温度・湿度・照度を取得

必要なライブラリをインストール

NatureRemoAPI を利用するためのアクセストークンを発行

  • Nature にアクセスし、アクセストークンを発行

動作確認

  • 下記の get_natureremo_data.py を実行
    get_natureremo_data.py
      from remo import NatureRemoAPI
      import json
    
    
      def get_natureremo_data():
          api = NatureRemoAPI(json.load(open('./config/setting.json'))['natureremo_token'])
          device = api.get_devices()[0]
          te = device.newest_events['te'].val  # 温度
          hu = device.newest_events['hu'].val  # 湿度
          il = device.newest_events['il'].val  # 照度
    
          return device, te, hu, il
    
      if __name__ == '__main__':
          device, te, hu, il = get_natureremo_data()
          print(device)
          print(te, hu, il)
    
    setting.json
      {
          "natureremo_token": "**********"
      }
    

各センサの値を Google Apps Script を用いてスプレッドシートに記録

各センサの値を記録・グラフ化するためのスプレッドシートを作成

  • 参考:Raspberry PiからGoogleスプレッドシートにCO2濃度データを保存する
  • シートの追加
    • log
      • センサデータの記録用

      • A列:時刻、B列:二酸化炭素濃度、C列:温度、D列:湿度、E列:照度

      • 完成後の表示例:

        A B C D E
        1 2022/04/12 8:51:59 559 26.6 51 137
    • filter
      • log から最新900件(5時間分)の各センサの値を取得

      • A1 に下記を記入

        =query(
          log!A:E,
          "SELECT A, B, C, D, E ORDER BY A DESC LIMIT 900 FORMAT A 'hh:mm'"
        )
        
      • 完成後の表示例:

        A B C D E
        1 08:51 559 26.6 51 137
    • graph
      • filter を用いて各センサの値をグラフ化
      • A1 に下記を記入
        =CONCATENATE(
          TO_TEXT(filter!A:A), ", ",
          TO_TEXT(filter!B:B), "ppm, ",
          TO_TEXT(filter!C:C), "℃, ",
          TO_TEXT(filter!D:D), "%, ",
          TO_TEXT(filter!E:E), "lx "
        )
        
      • A2 にグラフを挿入
        • グラフをクリックして、グラフエディタを編集
          • 設定
            • 以下の画像を参考に各項目を記入
            • データ範囲:filter!A1:A900,filter!B1:B900,filter!C1:C900,filter!D1:D900,filter!E1:E900
              グラフエディタ_設定
          • カスタマイズ
            • 横軸の軸ラベルの順序を逆にするにチェック
            • 好みのデザインにカスタマイズ
      • 完成後の表示例:
        グラフ

各センサの値をスプレッドシートへ記録する方法

  • GAS(Google Apps Script)を利用
    • GAS は、作成したプログラムを Webアプリとして公開可能
  • 記録方法の流れ
    • RPi が GAS にセンサデータを POST
    • GAS が各センサの値をスプレッドシートに記録

RPi から POSTされた各センサの値を受け取り、スプレッドシートへ記録する GAS のプログラムを作成

  • 参考:Raspberry PiからGoogleスプレッドシートにCO2濃度データを保存する
  • GAS のプログラムを書くためのエディタの開き方
    • スプレッドシートを開く
    • 拡張機能、Apps Script の順にクリック
  • GAS のプログラム(sensor_data.gs)を作成
    sensor_data.gs
    function doPost(e) {
        // パラメータの値を取得
        var co2 = e.parameter.co2;  // co2
        var te = e.parameter.te;  // 温度
        var hu = e.parameter.hu;  // 湿度
        var il = e.parameter.il;  // 照度
    
        // 保存先のシートを取得
        var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('log');
    
        // シートに各センサの値を追記
        sheet.appendRow([new Date(), co2, te, hu, il]);
    }
    

GAS のプログラムを Webアプリとして公開

  • デプロイ、新しいデプロイの順にクリック
    • 設定する項目
      • 新しい説明文:任意
      • 次のユーザとして実行:自分
      • アクセスできるユーザ:全員
    • 許可を確認を選択し、自分のアカウントをクリック
  • 「このアプリは確認されていません」の画面における操作
    • 左下の詳細をクリック
    • (安全ではないページ)に移動をクリック
    • 許可をクリック
  • Webアプリの URL をコピー

RPi が GAS にセンサデータを POSTするプログラムの作成

python logging_sensor_data.py
import schedule
import time
from get_co2 import get_co2
from get_natureremo_data import get_natureremo_data
import requests
import json


def logging_sensor_data():
    co2 = get_co2()
    device, te, hu, il = get_natureremo_data()

    response = requests.post(
        url=json.load(open('./config/setting.json'))['apps_script_url'],
        data={
            'co2': f'{co2}',
            'te': f'{te}',
            'hu': f'{hu}',
            'il': f'{il}'
        }
    )


def main():
    schedule.every(1).minutes.do(logging_sensor_data)

    while True:
        schedule.run_pending()
        time.sleep(1)


if __name__ == '__main__':
    main()
setting.json
{
    "apps_script_url": "**********"
}

動作確認

  • 上記の logging_sensor_data.py を実行
  • スプレッドシートが更新されるか確認

スプレッドシートの graph を Web に公開

  • ファイル、Web に公開の順にクリック

Voiceflow で Alexaスキルを作成し、現在の各センサの値を Echo に教えてもらう

プロジェクトを作成

Alexaスキルを作成

  • 以下の画像を参考に、Steps から必要なカードを選択して配置
    Voiceflow_steps

    • Speak カード
      • Speak sensor data
      • Speak err msg
    • Google Sheets カード
      • Get sensor data
  • 現在の各センサの値を取得するためのカード(Get sensor data)を編集

    • Retrieve Data を選択
    • ユーザ、スプレッドシート、シート(filter)を選択
    • 以下の画像を参考に、With Settings と Mapping Output を編集
      With_Settings
      Mapping_Output
  • Start カードをクリックしてテストを実行し、動作を確認

Alexaスキルをデプロイ

  • 右上の Upload to Alexa をクリックし、その後、Connect Amazon をクリック
  • Alexa開発者コンソールにログインし、Alexaシミュレータで Alexaスキルの動作を確認
    • Alexaシミュレータにセンサーと入力

動作確認

  • Echo に「エコー、センサー」と話しかけてみる
    • 応答例:現在の時刻は14時25分、二酸化炭素濃度は583ppm、温度は26℃、湿度は39%、光量は28lxです。

おまけ

  • 私の場合、この機能は定型アクションに組み込んで使っていたりします。
    定型アクション

alexa-remote-control を用い、換気が必要なタイミングを Echo に教えてもらう

換気が必要なタイミング

alexa-remote-control の設定

  • 必要なライブラリをインストール

    • $ sudo apt install jq を実行
  • alexa-remote-control をダウンロード

    • $ wget https://raw.githubusercontent.com/thorsten-gehrig/alexa-remote-control/master/alexa_remote_control.sh を実行
  • alexa_remote_control.sh を編集

    • 編集項目
      SET_EMAIL='**********'
      SET_PASSWORD='**********'
      SET_LANGUAGE='ja-JP'
      SET_TTS_LOCALE='ja-JP'
      SET_AMAZON='amazon.co.jp'
      SET_ALEXA='alexa.amazon.co.jp'
      
  • alexa_remote_control.sh の権限を変更

    • $ sudo chmod 777 alexa_remote_control.sh を実行

おまけ(LINEへ通知するための設定)

  • LINE Notify にアクセス
  • トークンを発行する、1:1でLINE Notifyから通知を受け取るの順にクリック

動作確認

  • 下記の notify.py を実行
    notify.py
    import subprocess
    import json
    import requests
    
    
    def let_echo_speak(msg):
        cmd = ['./sh/alexa_remote_control.sh', '-e', f'speak:{msg}']
        res = subprocess.check_output(cmd).decode()
        send_line_notify(msg=msg)
    
    
    def send_line_notify(msg):
        line_notify_token = json.load(open('./config/setting.json'))['line_notify_token']
        line_notify_api = 'https://notify-api.line.me/api/notify'
        headers = {'Authorization': f'Bearer {line_notify_token}'}
        data = {'message': msg}
        requests.post(line_notify_api, headers=headers, data=data)
    
    
    if __name__ == '__main__':
        let_echo_speak(msg='テスト')
    
    setting.json
    {
        "line_notify_token": "**********"
    }
    

Node-RED を用いて RPi と Echo を連携し、換気が完了したタイミングを Echo に教えてもらう

換気が完了したタイミング

  • Echo に「換気 ON」と伝えてから、初めてCO2センサから取得される二酸化炭素濃度の値が500を下回った場合

Node-RED の起動

  • 参考:Raspberry Piで実行する
  • Node-RED のスクリプトをダウンロード
    • $ bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered) を実行
  • Node-RED のサービスの起動時実行を有効化
    • $ sudo systemctl enable nodered.service を実行
  • Node-RED のサービスを起動
    • $ node-red-start を実行
  • ログに表示される URL(例:http://192.168.10.108:1880/)に PC からアクセス

Node-RED を用いて RPi と Echo を連携

  • Node-RED Alexa Home Skill Bridge の設定
    • Node-RED Alexa Home Skill Bridge にアクセスし、Node-RED Alexa Home Skill Bridge のアカウントを作成
    • Devices、Add Device の順にクリックし、下記の項目を設定
      Name:換気
      Description:換気システム
      Actions:On, Off
      Application Type:SWITCH
      
  • Node-RED に Node-RED Alexa Home Skill Bridge を追加
  • alexa-home ノードの設定
    • alexa-home ノードの設定を配置し、ダブルクリック
    • Acount の右の編集ボタンをクリックし、Node-RED Alexa Home Skill Bredge のサイトのユーザー名とパスワードを入力して add をクリック
  • Node-RED の Alexaスキルを有効化
    • Node-RED にアクセス
    • 端末を検出をクリック

Node-RED のフローを作成

動作確認

  • 下記の server.py を実行
server.py
from flask import Flask, Response
import json
from notify import let_echo_speak
from get_co2 import get_co2
import time

app = Flask(__name__)
ventilation = False


@app.route('/ventilate')
def ventilate():
    global ventilation
    ventilation = True
    check_ventilation_is_complete()
    return Response(response=json.dumps({'message': 'Start Ventilation!'}), status=200)


@app.route('/stop')
def stop():
    global ventilation
    ventilation = False
    return Response(response=json.dumps({'message': 'Stop Ventilation!'}), status=200)


def check_ventilation_is_complete():
    let_echo_speak(msg='換気を開始します。')

    while True:
        co2 = get_co2()
        if int(co2) <= 500:
            let_echo_speak(msg='換気が完了しました。')
            break
        elif not ventilation:
            let_echo_speak(msg='換気を終了します。')
            break
        else:
            time.sleep(60)


def main():
    app.run(host='0.0.0.0', port=50080)


if __name__ == '__main__':
    main()
  • Echo に「換気ON」と話しかけてみて、Echo から「換気を開始します」と応答があるか確認

RPi の低消費電力化(Wi-Fi 以外の不要な機能を停止)

オンボードLED の無効化(RPi Model 3B の場合)

  • /boot/config.txt に下記を追記後、再起動
    • Act LED:データアクセス時に緑色に点滅
    • Pwr LED:起動後常に赤色に点灯
      config.txt
      # Disable the Activity LED
      dtparam=act_led_trigger=none,act_led_activelow=on
      # Disable the PWR LED
      dtparam=pwr_led_trigger=none,pwr_led_activelow=on
      

HDMI の無効化

  • /etc/rc.local に下記を追記後、再起動
    rc.loal
    # Disable HDMI
    tvservice --off
    

Bluetooth の無効化(RPi Model 3B の場合)

  • /boot/config.txt に下記を追記後、再起動
    config.txt
    # Disable Bluetooth
    toverlay=disable-bt
    

USBコントローラの無効化

  • /etc/rc.local に下記を追記後、再起動
    rc.loal
    # Disable USB
    echo '1-1' |sudo tee /sys/bus/usb/drivers/usb/unbind
    

おわりに

この記事では、RPi、CO2センサ、Nature Remo 3、および Echo を用いて、リモートワークを快適にする換気システムを作る方法について解説しました。

皆さんのリモートワークが、少しでも快適になればと思います。

15
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?