2021年6月24日木曜日

ESP32-DevkitCとDHT11とCDSで、温度・湿度・明るさのデータをPostgreSQLに保存するデータロガーを作成する

ESP32-DevkitCとDHT11とCDSで、温度・湿度・明るさのデータをPostgreSQLに保存するデータロガーを作成するには、以下の手順を実行します。
構成としてはESP32-DevkitCに接続したDHT11で温度・湿度を取得し、CDSで明るさを取得します。ESP32-DevkitCからWiFi経由でPC側のFlaskのRESTサービスにアクセスしデータを受け渡し、PostgreSQLにデータを保存します。

〇ESP32-DevkitCとDHT11とCDSを接続した写真

データロガーの開発手順

1. PC側:PostgreSQLのデータベースにテーブルを作成する
以下のSQLコマンドを実行して、温度・湿度・明るさを保持するテーブルを作成します。
create table iot_sensor_data
(
  device_name varchar(30) not null,
  data_ts timestamp not null,
  temperature integer,
  humidity integer,
  lightness integer,
  constraint pk_iot_sensor_data primary key (device_name, data_ts)
);

※PostgreSQLをインストールしていない場合は、以下の記事を参照してください。
・Ubuntu20.04にインストールしたい場合は、以下の記事のPostgreSQLのインストール部分を参照してください。
Ubuntu 20.04にNextcloud20とPostgreSQL13をインストールする

・Raspberry Piにインストールしたい場合は、以下を参照してください。
Raspberry Pi(Raspbian Buster)にPostgreSQL11をインストールしてtestデータベースとtestユーザを作成する

2. PC側:ユーザの追加
Flaskを実行するユーザpyを作成するには、以下のコマンドを実行します。
sudo addgroup py

sudo adduser --quiet --gecos "" --ingroup py py

3. PC側:pipenvのインストール
sudo apt-get -y install python3-pip python3-distutils python3-dev python3-testresources

sudo pip3 install --upgrade setuptools

sudo pip3 install pipenv

echo "export PIPENV_VENV_IN_PROJECT=true" >> ~/.bashrc

source ~/.bashrc

4. PC側:flaskとpsycopg2のインストール
以下のコマンドで、flaskとpsycopg2をインストールした仮想環境を作成します。
sudo apt-get -y install libpq-dev

sudo mkdir -p /opt/iot_logger

sudo chown py:py /opt/iot_logger
※ここから作成したpyユーザで以下のコマンドを実行します。
cd /opt/iot_logger

pipenv --python 3

pipenv install flask psycopg2-binary

pipenv shell

5. PC側:REST APIでデータを受け取り、PostgreSQLに保存するFlaskアプリケーションの構築
以下のコードを/opt/iot_loggerのapp.pyに保存します。

app.py
from flask import Flask, jsonify, request
import time
import os
import psycopg2
import psycopg2.extras

def dbconnect():
    conn = psycopg2.connect(host=os.environ['PG_HOST'], port=os.environ["PG_PORT"], database=os.environ['PG_DB'], user=os.environ['PG_USER'], password=os.environ['PG_PASS'])
    return conn

sql = """insert into iot_sensor_data values ('ESP32-DevkitC', current_timestamp, %s, %s, %s)"""

@app.route('/iot_logger', methods=["POST"])
def iot_logger():
    print(request.get_data())
    temp = int(request.json['temp'])
    humidity = int(request.json['humidity'])
    lightness = int(request.json['lightness'])

    conn = dbconnect()
    #with conn.cursor(cursor_factory=psycopg2.extras.DictCursor) as cur:
    with conn.cursor() as cur:
        cur.execute(sql , (temp, humidity, lightness))
    conn.commit()
    return {"status":"ok"}

app = Flask(__name__)
app.run(debug=True, host='0.0.0.0', port=5001, threaded=True)

4. PC側:テスト実行
Flaskを実行するには、以下のコマンドを実行します。
export PG_HOST=(PostgreSQLのホスト名またはIPアドレス)
export PG_PORT=(PostgreSQLのポート:デフォルトは5432)
export PG_DB=(PostgreSQLのデータベース名)
export PG_USER=(ユーザ名)
export PG_PASS=(パスワード)

export FLASK_APP=app.py

flask run -h 0.0.0.0 -p 5001
※Ctrl+Cで停止します

5. PC側:サービス化
以下のコマンドでFlaskアプリケーションをサービス化して実行します。
cat << EOF | sudo tee /etc/systemd/system/iot_logger.service
[Unit]
Description=IoT logger
[Service]
Type=simple
Environment=export PG_HOST=(PostgreSQLのホスト名またはIPアドレス)
Environment=export PG_PORT=(PostgreSQLのポート:デフォルトは5432)
Environment=export PG_DB=(PostgreSQLのデータベース名)
Environment=export PG_USER=(ユーザ名)
Environment=export PG_PASS=(パスワード)
Environment=export FLASK_APP=app.py
ExecStart=/opt/iot_logger/.venv/bin/python3 app.py
User=py
Group=py
WorkingDirectory=/opt/iot_logger
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable iot_logger

sudo systemctl start iot_logger

6. ESP32-DevkitC側:ESP32-DevkitCとDHT11/CDSの配線
ESP32-DevkitCとDHT11センサーモジュール/CDSを配線します
DHT11のDigitalピンへ(付属ケーブルの緑) -> ESP32-DevKitCのIO27ピン
DHT11のGNDへ(付属ケーブルの黒) -> ESP32-DevKitCのGNDピン
DHT11のVへ(付属ケーブルの赤) -> ESP32-DevKitCの3V3ピン

※ESP32とDHT11の接続は以下の記事を参照してください。
ESP32-DevkitCとDHT11で計測した温度・湿度をWiFi経由のREST APIで通知する

CDS,10KΩ抵抗を以下の様に接続します。
※CDSの接続は以下の記事を参照してください。
ESP32-DevkitCとCDSで明るさを計測する

4つのエネループをセットした電池ボックスのプラスは5V端子、マイナスはGNDに接続します。
※電池と基板の接続は以下の部品を使用しました。
XHコネクタ ベース付ポスト トップ型 2P B2B-XH-A(LF)(SN)
https://akizukidenshi.com/catalog/g/gC-12247/

電池ボックス 単3×4本 スイッチ付 XHコネクタ付
https://akizukidenshi.com/catalog/g/gP-12242/

7. ESP32-DevkitC側:プログラミング
以下のプログラムをmain.pyとして、ESP32-DevkitCに保存します。dhtのライブラリ導入は、上記のDHT11の記事を参照してください。
import machine 
import time
import dht
import urequests
import ujson
import network

# WiFiのssid
ssid = "WiFiのssid"
# WiFiのパスワード
password = "Wifiのパスワード"
# REST APIの接続先
url = "http://(ホスト名またはIP):(ポート番号)/iot_logger"
header = {'Content-Type':'application/json'}

def connect_wifi():
    sta_if = network.WLAN(network.STA_IF)
    if not sta_if.isconnected():
        print("connecting to network...")
        sta_if.active(True)
        sta_if.connect(ssid, password)
        while not sta_if.isconnected():
            pass
    print("network config:", sta_if.ifconfig())

# ADC初期化
pin35 = machine.Pin(35, machine.Pin.IN)
cds = machine.ADC(pin35)
cds.atten(machine.ADC.ATTN_11DB) # 11dBの減衰率、約3.6v が最大入力電圧

# DHT11初期化
dht11 = dht.DHT11(machine.Pin(27))
time.sleep(1)
while True:
    # WiFi接続
    connect_wifi()

    # 測定
    dht11.measure()
    temp = dht11.temperature()
    humidity = dht11.humidity()
    lightness = cds.read()

    # REST APIに通知
    data = ujson.dumps({"temp":str(temp), "humidity":str(humidity), "lightness":str(lightness)})
    try:
        resp = urequests.post(url, data=data.encode("utf-8"), headers = header)
        print(resp.json())
        resp.close()
    except OSError as err:
        print(err)
        print("----")
    
    # deepsleep
    #time.sleep(2)
    machine.deepsleep(60*60*1000) # 3600sec=1時間

8. ESP32-DevkitC側:データ確認
以下のSQLを実行して、センサーデータが保存されていることを確認します。
select * from iot_sensor_data

0 件のコメント:

コメントを投稿