PostgreSQLへ接続/ESP32-WROOM-32E/Arduino IDE (Debian11.4.0)

2022/08/05


ESP32からRDBMSへアクセス

ESP32からデータベース(RDBMS)へアクセスしたい。PHPとかCGIとかで中継するものばかりだ。
ESP32をHTTPクライアントとして使い、GETあるいはPOSTメソッドでwebサーバ(PHP等が動いている)へリクエストパラメータを送り、PHP等がデータベースへアクセスしている。
よくできていると思うのがこれ
RANDOM NERD TUTORIALS   
ESP32/ESP8266 Insert Data into MySQL Database using PHP and Arduino IDE
(https://randomnerdtutorials.com/esp32-esp8266-mysql-database-php/)
だ。
たしかにServletを使う、PHPを使う等の方法で実現可能だが、webサーバを経由せずに直接データベースにアクセスしたい。

ESP32からRDBMSへアクセス

Arduino IDEからライブラリマネージャで検索すると。。。
MySQLとsqlite3はある。
「MySQL用ライブラリがあるなら、PHPで中継しなくても行けるだろう?」と先程のサイトに疑問を持ちながら、PostgreSQLを探すが、どうもPostgreSQL用はないらしい。
興味を引くものとしてESP32内EEPROMに簡易データベースをつくるライブラリはあるが、今回の用途とはちょっと違う。
ライブラリマネージャ

PostgreSQLに直接アクセスしたい。TCP通信で実装可能だがちょっと大変そうだし、どうしたものかと思っていたところ、SimplePgSQLを見つけた。
GitHub ethanak/SimplePgSQL (https://github.com/ethanak/SimplePgSQL) によると「Simple PostgreSQL connector for Arduino and ESP8266」らしい。
code buttonをクリックしてソースコードをZip形式(SimplePgSQL-master.zip)でをダウンロードする。
SimplePgSQL

ライブラリへインストール

Arduino IDEのライブラリマネージャでインストールしようとしたが、よくわからなかった。
SimplePgSQL

「ファイルを追加」を選ぶとzipファイルが追加できるらしいが、うまく行かなかった。
面倒になったので、~/Arduino/libraries/SimplePgSQL以下に直接ファイルを展開した。
cd ~/Arduino/libraries/
unzip ~/Download/SimplePgSQL-master.zip
mv SimplePgSQL-master SimplePgSQL
ディレクトリはこんな構造
SimplePgSQL

README.mdには関数の大まかな説明がある。
あとはソースコード(SimplePgSQL.h,SimplePgSQL.cpp,examples/PgConsole/PgConsole.ino)を見ながらライブラリをつかってみよう。

接続状態

SimplePgSQL.hのなかで気になった部分がある。
戻り値というか、接続状態を表すワードらしいが、PgConsole.inoなかではCONNECTION_OK等のワードを記述した部分と整数値(0,1,2,..)を使用している部分がある。動作を理解するにあたりこのワードと整数値の対応を確認した。
SimplePgSQL.hより抜粋接続状態
typedef enum
{
	CONNECTION_OK,
	CONNECTION_BAD,
	CONNECTION_NEEDED,			/* setDbLogin() needed */
	/* Internal states here */
	CONNECTION_AWAITING_RESPONSE,		/* Waiting for a response from the
                                                 * postmaster.        */
	CONNECTION_AUTH_OK			/* Received authentication; waiting for
								 * backend startup. */
} ConnStatusType;
STATUSvaluememo
CONNECTION_OK0正常
CONNECTION_BAD 1接続に失敗
CONNECTION_NEEDED2未接続 setDbLogin()が必要
CONNECTION_AWAITING_RESPONSE 3データベースからの応答待ち
setDbLogin()の後、数ミリ秒の待ち時間が必要
CONNECTION_AUTH_OK4認証待ち

PostgreSQLへ接続:INSERT文

差し当たりPostgreSQLにデータ追加したい。
検索等RDBMSからの返事を扱うのは後にする。INSERT文でも「xx件追加しました」みたいな応答はあるが、受け取らなくてもどうにかなるだろう。
pgSQLClient.ino 端末からデータベースxxxxへ接続
テーブルは先に作ってある。
CREATE TABLE wifilevel2(
  dt   TIMESTAMP DEFAULT NOW() PRIMARY KEY,
  rssi INTEGER DEFAULT 0);

simplepgsql

トラブルが発生します---解決??

[1]データベースの切断はちょっと待て
rssiを記録したときはずっとWiFiに接続していたのでわからなかった。
ADコンバータを使うとき、 (ADコンバータを使用)-(wifiに接続)-(PostgreSQLへ接続)-(PostgreSQLへ挿入)-(ちょっと待って)-(PostgreSQLを切断)-(wifiを切断) を繰り返した。
PostgreSQLへデータを挿入した直後にPostgreSQLを切断すると、INSERT文が処理できたり、処理できなかったりする。
毎回「INSERT文が処理されない」ではなく、ときどき処理できない。
conn.execute(sql);//INSERT文を処理
conn.close();
conn.execute()の後でconn.stat()を表示されたが、conn.stat()は0だった。conn.execute()とconn.close()の間にdelay()関数で遅延を入れてようすを見ている。遅延時間100mSではときどき処理できないが、遅延時間500mSにするとINSERT文は実行できるようだ。 データベースを切断したつもりだったが、実際にはデータベースに接続したままになっている。

[2]セッションが残っている?
conn.close()でデータベースを切断したつもりだったが、違うらしい。
(WiFiに接続)-(PostgreSQLへ接続)のたびに新しいセッションをつくっているらしい。
PostgreSQL側でプロセスを見ると
ps aux|grep postgres
simplepgsql

データベースに現在の接続を訊ねると、ESP32が多数接続している。(ESP32側は切断している)。
#現在の接続を表示
SELECT * FROM pg_stat_activity;
simplepgsql

このまま使い続けると、いずれ新規接続はできなくなる。
3時間程度放置したところ、データベースとの接続に問題が発生した。

[3]データベースへ接続するまで待たされる
WiFiの接続は100mSほとんど待つことはないが、データベースの接続は時々待たされる。
60秒ごとにデータベースへ記録するつもりだったが、時間間隔が不均一になっている。delay関数で60秒を指定したが、待機時間は60秒にはならず60〜70秒になっている。
定時測定(定時記録)をするには工夫が必要だ。

たぶん? 解決?

現在、このようなことで様子をみている。
conn.execute(sql);//INSERT文を処理
delay(500);//固定値500ミリ秒
conn.close();
delay(500);//固定値500ミリ秒
WiFi.disconnect(true);
[1]データベースを切断するタイミング
conn.execute()とconn.close()の間 にdelay(遅延時間500ミリ秒)を入れた。300ミリ秒でもよさそうだが、極まれに次回データベースの接続時に問題がおきた。
RDBMS的には、 「INSERT文を実行しました。○件挿入しました。」みたいな返事をして仕事が完了するのだろうが、早々にconn.close()されてしまった。「仕事が完了しないまま通信が切断されてしまったので、INSERT文は処理できなかった。」ということではないだろうか。

[2]セッションが残る理由
SimplePgSQLのコードを熟読していないので想像であるが、(後にコードを読んで判断したい)
RDBMS的には、conn.close()に対していろいろと確認をするつもりだったが、WiFiそのものを切られてしまった。「なにかのトラブルかもしれないので、セッションをキープして通信の回復を待ちましょう。」ということではないだろうか。
conn.close()とWiFi.disconnect()の間にdelay(遅延時間500ミリ秒)を入れた。この遅延時間を確保したことでセッションを閉じることができた。
conn.close()からWiFi.disconnect()までの遅延時間が短かい設定のときはいくつかのセッションが残った。遅延処理をしないときはほぼすべてのセッションが残っていた。セッションの問題はこれが原因だと思う。

[3]データベースへの接続が待たされる
セッションが残ったままESP32をリセットしてみた。ESP32をリセットした直後、データベースの接続に8秒程度待たされることがあった。毎回ではない。何回かESP32をリセットすると発生する。8秒後にデータベースへの接続ができたが、条件次第ではデータベースの接続待ちが続くかもしれない。
PostgreSQLをリセットした後は発生しない。
セッションが残る件だが、完全に解決したわけではない。15秒ごとにINSERT文を実行したところ、200回に1回程度セッションが残った。 適当なときを見計らってPostgreSQLを再起動しているが、正しい対処とは思っていない。
しばらくの間ESP32を観察した後、対応を検討する。

ESP32についてはかなり詳しい。
RANDOM NERD TUTORIALS   ESP32/ESP8266 Insert Data into MySQL Database using PHP and Arduino IDE (https://randomnerdtutorials.com/esp32-esp8266-mysql-database-php/)

GitHub ethanak/SimplePgSQL (https://github.com/ethanak/SimplePgSQL)