ESP8266/ESP32でsyslog出力

ESP32でセンサ情報を収集できるようになったのですが、ESP32は電源を落とすとデータが消えてしまいます。そこでログをsyslogで出力してみます。

ぐぐると、GitHubにちょうど Arduino用の Syslog ライブラリがありましたので、これを試してみます。

GitHubからZIPでダウンロードしてきて、ダウンロードしたファイル(Syslog-master.zip)を展開、展開したディレクトリの名前を Syslog-master から Syslog に変更して、 ~/Arduino/librariesの下に移動します。

その後、Arduino IDEを起動すると、「ファイル→スケッチ例」の中に「Syslog」が出てきますので、この中の AdvancedLoggingESP8266 を開いて、冒頭の部分を修正します。

// WIFI credentials
#define WIFI_SSID "**************" ← WiFiのSSIDをセット
#define WIFI_PASS "**************" ← WiFiのパスワードをセット

// Syslog server connection info
#define SYSLOG_SERVER "syslog-server"  ← syslogサーバのIPアドレスを記載
#define SYSLOG_PORT 514

// This device info
#define DEVICE_HOSTNAME "my-device"   ← ESP8266のデバイス名をセット
#define APP_NAME "my-app"           ← 適当に設定
#define ANOTHER_APP_NAME "my-another-app" ← 適当に設定

修正して実行すると、syslogサーバ側に以下のようなログが記録されました。

May 13 00:23:29 esp8266 my-app Begin loop
May 13 00:23:29 esp8266 my-app This is error message no. 2
May 13 00:23:29 esp8266 my-app This is info message no. 2
May 13 00:23:29 esp8266 my-app This is daemon info message no. 2
May 13 00:23:29 esp8266 my-app This is ftp info message no. 2
May 13 00:23:29 esp8266 my-another-app This is error message no. 2 from my-another-app
May 13 00:23:29 esp8266 my-app This is logged.
May 13 00:23:29 esp8266 my-app This is logged.
May 13 00:23:39 esp8266 my-app Begin loop
May 13 00:23:39 esp8266 my-app This is error message no. 3
May 13 00:23:39 esp8266 my-app This is info message no. 3
May 13 00:23:39 esp8266 my-app This is daemon info message no. 3
May 13 00:23:39 esp8266 my-app This is ftp info message no. 3
May 13 00:23:39 esp8266 my-another-app This is error message no. 3 from my-another-app
May 13 00:23:39 esp8266 my-app This is logged.
May 13 00:23:39 esp8266 my-app This is logged.

ドップラーセンサー用のケースを設計

以前作ったESP32のテスト用の基板以前買った秋月のドップラーセンサを適当に組みあわせてFusion360でケースを設計、出力してみました。

組み合わせた基板はこんな感じでいきあたりばったりです。

でも、基板に合わせてこんな感じのケースを設計しました。

こんな感じで基板を載せます。

蓋をしてネジ止めするとそれっぽくなるのが3Dプリンタのいいところです(笑)。

ネジ穴はM3x6のネジのネジ部を実測して、2.8mmの穴を開けて、入れやすいようにC1で面取りしただけで、いい感じにネジ止めできるようになります。何度も開け閉めするものでなければインサートナットを挿入しなくてもいいので楽ちんです。

ESP32でマイクロ波近接センサをロギング

ESP32はしばらく放置している間にすごく使いやすくなっていたので、調子に乗って、以前買ったESP32 DevKitCOLEDモジュールをつけて、ドップラーセンサーモジュールで壁越しに動体検知するのにチャレンジしてみました。

開発はArduino環境で行いました。無線LANの初期化やNTPでの時刻同期、OLEDの表示に関する部分、Webサーバーに関する部分はT-Cameraのソースをベースに不要な部分を削除して用意しました。

今回使用したセンサはUARTで通信します。ESP32にはUARTが3つあり、1つはPC(Arduino IDE)との通信用となっていますので、残り2つが利用可能です。今回はUART1の送信を16ピン、受信を17ピンに割り当てて使用しました。

#define UART1_TX 16
#define UART1_RX 17

Serial1.begin(9600, SERIAL_8O1, UART1_RX, UART1_TX

で初期化しました。

受け取ったセンサ情報は接近時、離別時、停止時の3つのパターンがありますが、それぞれ毎分0秒を境界とした1分毎、毎時0分を境界とした1時間毎に発生数を計数して Chart.js を用いてグラフ化してみました。

 

TTGO T-Cameraの画像をngrok経由で取得

NAT配下のWebサーバ等をインターネットからアクセスできるようにトンネリングをするngrokというサービスがあります。

これを使って、3Dプリンタの監視画像をインターネットから取得できないか試してみました。

テスト環境は以下のとおりです。

   |
 WiFi Router
   | 192.168.10.1
   |
   +---- TTGO T-Camera
   |       192.168.10.2
   |          80/TCP Web, 81/TCP Streaming
   |
   +---- Raspberry Pi(Raspbian Lite)
           192.168.10.3

まず、ngrok公式サイトからサインアップをします。サインアップすると、「Setup & Installation」という画面に移行しますので、これに沿って操作していきます。

まず、ngrokのダウンロードですが、Linux(ARM)のURLをコピーして、wgetでzipファイルを取得します。(下記はURLを書き換えてありますので、必ずURLをコピーしてください)

~$ wget https://bin.equinox.io/c/xxxxxxxxxx/ngrok-stable-linux-arm.zip

ダウンロードしたら、②、③に沿って展開とトークンの取得を行います。トークンの取得は③のところのコマンドラインをコピー&ペーストして実行するだけです。

~ $ unzip ngrok-stable-linux-arm.zip 
Archive: ngrok-stable-linux-arm.zip
inflating: ngrok 
~ $ ./ngrok authtoken xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Authtoken saved to configuration file: /home/pi/.ngrok2/ngrok.yml

トークンを取得したら、 ~/.ngrok2/ngrok.yml にある設定ファイルを作成します。

authtoken: xxxxxxxxxxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxx
tunnels:
  ttgo:
    addr: 192.168.10.2:80
    proto: http
    auth: "user:password"
    bind_tls: true

1行目の内容はトークン取得で作成されている内容です。2行目以降が追加した内容になります。

tunnels:
  ttgo:        <-------- トンネルにつけた名前です
    addr: 192.168.10.2:80    <---- アクセスされた際の転送先です
    proto: http              <---- httpプロトコルを指定します
    auth: "user:password"    <---- アクセスの際の認証を追加します
    bind_tls: true           <---- TLSで暗号化を強制します

作成したら、

~ $ ./ngrok start --all

で起動します。(終了すると tunnel も消滅するので screen と併用するとよいかと思います)

ngrok by @inconshreveable                                           (Ctrl+C to quit)
                                                                                    
Session Status                online                                                
Account                       XXXXXXXXXXXXXXXXX (Plan: Free)                       
Version                       2.3.27                                                
Region                        United States (us)                                    
Web Interface                 http://127.0.0.1:4040                                 
Forwarding                    https://b3d16323.ngrok.io -> http://192.168.10.2:80   
                                                                                    
Connections                   ttl     opn     rt1     rt5     p50     p90           
                              0       0       0.00    0.00    0.00    0.00

という感じで状態が表示されます。この状態でインターネット側から https://b3d16323.ngrok.io にアクセスするとBASIC認証が求められ、設定したユーザー名とパスワードを入力すると、TTGO T-Cameraへアクセスすることができました。アクセスすると上記の状態の下にHTTPリクエストの状態がリストで表示されます。なお、b3d16323の部分は起動する度にランダムに変わります。有料プランにするとこの部分を固定にすることができるようです。

実際にGet Stillをクリックすると、

という感じで実際に画像を取得できました。なお、ストリーミングについては異なるポート(81/TCP)でのアクセスが必要なのですが、ngrokのコンフィグファイルでは複数のポートの設定も記述できるものの、ポートごとに異なるURLが割り付けられます。このため、うまくいきませんでした。有料プランにするとURLを指定できるので、うまく行く方法があるのかもしれません。

PCのファンを修理

ネットアクセス用のAthlon5350マシンがあるのですが、しばらく前にケースFANがビビリ音で煩くなってFANを交換しました。もともとついていたFANは回転数センサなしの電源だけが接続されるタイプだったのですが、使っているASUS製のマザー側にFANの回転数制御機能があるようだったので、できるだけ高速のFANを買ってマザーボード側で速度を落として使うことにしました。

・・・・が、交換後、実はPWM制御しかできないということが判明して、爆音PCになってしまいました。速度制御できないとうるさくてたまりませんが、冬場だったこともありFANのケーブルを抜いて使っていました。しかし、気温が上がってきたせいか、最近CPUファンの音が煩くなってきたので、なんとかせにゃならん、ということで、もともとついていたFANにグリースを差して戻してみました。

もともとついていたFANは以下のようなものです。

シールを剥がすと、軸受が見えます。

ここに、グリースを詰めました。爪楊枝の先にグリースを載せて、穴の中に詰めていきました。

たくさん詰めたら、シールを蓋して、ケースにつけると、以前のようなビビリ音はしなくなりました。

今回使ったグリースは、近所のホームセンターにあった下記のグラファイトグリースです。適切なものなのかわかりませんが、見たところ金属同士の軸受かなーと思ったので、これにしました。まあ、FANがだめになったら、またFANを交換すればいいかな、ということで。
蛇腹タイプで40gも入っていますが、はっきり言って一生分くらいありそうです(笑)。

 

リチウムイオン電池制御IC IP5306について

TTGO T-Cameraに搭載されているリチウムイオン電池制御ICのIP5306について調べてみました。

データシートはこちらの通販サイト?で見ることができます(ダウンロードできなくなった場合のために、コピーを置いておきます)。簡体字中国語で書かれていますが、整然と書かれているのでこの手のチップの英語のデータシートが読める人なら大体わかると思います。細部はディスプレイに拡大表示させて、スマートフォンのGoogle翻訳でカメラから翻訳させれば、かなり精度よく翻訳してくれます。

このデータシートを見ると不思議なのはPDFのタイトルでは「1.2A充電、1A放電」と書かれているのですが、中身では「2.1A充電、2.4A放電」と書かれています。

まあ、細かいことはさておき、大雑把に捉えると、モバイルバッテリー用に特化したICです。面白いところを見てみます。

たとえば、LED表示ですが、端子3つでLED1本〜4本までの仕様に対応できるようになっています。1kΩの抵抗でプルアップすることにより、LEDが何個の仕様で動作するかを読み取っているんじゃないかと思います。

また、リファレンスデザインの項目を見てみると、付加価値として操作用のスイッチと照明用のLEDもつけられるようになっています。

この操作用のスイッチは50ms以上2秒以下の押下によって残量表示LEDと出力がONになり、2秒以上の押下で同じ端子に接続された照明用のLEDが点灯、1秒以内に2回連続して短く押すと出力や残量表示LED、照明用LEDがOFFになるというものです。これらの機能が不要の場合には5ピンは未接続でよいようです。
こんな感じで、とにかく2〜5ピンには機能が盛り沢山に詰め込まれています。単に出力端子として使うだけではなく、時分割で入力端子としても使用することでピン数削減を図り、とことんコストダウンを狙っています。かつての日本の半導体では(あるいは欧米の半導体でも)ここまで徹底的にピン数削減を図ったものはみたことがありません。

中国のローカルベンダーの製品にはこういう面白い半導体もあったりするのは興味深いところですし、彼らの並々ならぬパワーを感じるところです。また、数年前は中国語のデータシートがあっても雰囲気しかわからなかったのですが、データシートの内容自体も洗練されたものが増えていることや、Google翻訳のカメラ翻訳を使うことで中身がかなり読めるようになりました。

また面白いものがあったら取り上げてみたいと思います。

TTGO T-Cameraを3Dプリンタ監視用に

TTGO T-Cameraを3Dプリンタの監視用に使ってみました。

まず支柱を設計して、3Dプリンタで出力しました。

Ender-3の左手前に共締めして取り付けるとこんな感じです。

3D Benchyを出力してみました。

PCからブラウザ上でストリーム表示させるとこんな感じです。

VGAサイズくらいであればスムーズに表示されます。スマホからでも表示可能。

暗いのでノイジーですが、UXGAでのキャプチャもこの通り。魚眼レンズなので近くても全景が入ります。画像は歪んでしまいますが、ちょっと状況を確認するには十分な出来になりました。

TTGO T-Camera 出力画像を180度回転

現在のT-Cameraのソースだと、USBコネクタが上に来る向きで天地が合う形になっているので、結構扱いにくい(一方で、USBケーブルを挿した状態で置きやすいというメリットもある)。

で、カメラモジュールで反転させる機能があるのではないか、と探してみたところ、やはりあった。

これを使えないか探しまくった結果、カメラを初期化している

    //drop down frame size for higher initial frame rate
    sensor_t *s = esp_camera_sensor_get();
    s->set_framesize(s, FRAMESIZE_QVGA);

の後に、

    s->set_hmirror(s, 1); // 
    s->set_vflip(s, 1); //

と入れれば画像が回転できることがわかった。よって、先に入れたOLEDの表示を回転させる

     oled.flipScreenVertically();

は削除できる。
でも、USBコネクタが上のほうが便利な場合もあるので、

#define UPSIDEDOWN

とすることで反転するようにソース修正した。

TTGO T-Camera LiPO電池を接続してみました

リチウムイオン電池のコントローラ(IP5306)が搭載されているTTGO T-Cameraですが、回路図をみるとD4というダイオードが入っていて電池からIP5306に向かってしか電流が流れないので、一見充電できないように見えます。

しかし、よくみるとこれ、「2A FUSE」と書いてあります。つまり、フットプリント流用のためにダイオードのシンボルになっているようです。さらに、その右下を見ると分圧回路があり、電池の電圧がESP32で確認できるようです。そこで、電池の電圧をモニターしつつ、LiPOをつないでみることにしました。つないだのは手持ちのトイドローン用の500mAhのものをコネクタを付け替えたものです。

ソフトウェアは表示画面に3ページ目を追加してモニターするようにしてみました。

void drawFrame3(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
{
    #define AVE 32
    static String Item1, Item2, Item3, Item4;
    static uint64_t lastMs;
    static unsigned int ms;
    static long rd[AVE] , sum;
    static int idx = 0;

    if (millis() - lastMs > 50) {
        lastMs   = millis();
        ms = millis();
        rd[idx++] = (long)analogRead(35);
        if(idx==AVE) idx=0; 
        sum = 0;
        for(int i=0;i<AVE;i++){
          sum += rd[i];
        }
        float volt = (long)sum/AVE * 3300. / 4096. * 2. ;
        Item1    = "TIME: " + String((float)ms/1000.) + "s";
        Item2    = "BATT: " + String(volt/1000.) + "V";
        Item3    = "Item3:" + String(0);
        Item4    = "Item4:" + String(0);
    }
    display->setFont(ArialMT_Plain_10);
    display->setTextAlignment(TEXT_ALIGN_LEFT);
    display->drawString(0 + x,  0 + y, Item1);
    display->drawString(0 + x, 10 + y, Item2);
    display->drawString(0 + x, 20 + y, Item3);
    display->drawString(0 + x, 30 + y, Item4);
}

FrameCallback frames[] = {drawFrame1, drawFrame2, drawFrame3};
#define FRAMES_SIZE (sizeof(frames) / sizeof(frames[0]))

単純にIO35の電圧を読んだだけでは高インピーダンスで外部/内部のノイズの影響を受けているのか、スッチングノイズを拾っているのかわかりませんが、かなりブレがあります。本来ならまずはR43にコンデンサを抱かせたいところですが、面倒なので50ms周期で32回の平均を取っています。(1005のコンデンサなんて手持ちにないし・・・。そもそもESP32のADCの入力インピーダンスってどのくらいなんでしょうね。100kΩでは大きすぎるのかも?)

一方、充電電流を見てみると、PCにつないだ場合には入力側で0.4Aくらいでしたので、電池への充電電流もせいぜい0.5Aくらいで1C程度ということで問題ない範囲(本当はもう少し減らしたい)かと思ったのですが、Ankerのモバイルバッテリーにつないだところ、0.8Aくらい流れていて2C近い電流が流れてしまうようです。IP5306の中国語のデータシート(こちらの通販サイト?にあるもの)を見ると、最大1Aで充電するようですので、ちょっとまずいかもしれません。データシートをみても充電電流を調整する方法はなさそうです。

バッテリーで動作するWiFi IPカメラというのも悪くないですし、どうしたもんでしょうね。

TTGO T-Camera ファームウェア改造

TTGO T-Cameraのファームウェアを改造してみました。

1.ファームウェア開発環境の準備

ファームウェアはArduino環境で開発しますので、まずはLinuxMint19に開発環境を導入します。

まずは、pyserialをインストールしておきます。

$ curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
$ sudo python get-pip.py 
$ sudo pip install pyserial
$ sudo apt install python3-pip 
$ sudo pip3 install pyserial

自分のユーザーアカウントを dialout グループに追加した後、一旦ログアウトしてログインし直します。

Aruduino公式サイトから arduino-1.8.9-linux64.tar.xz をダウンロードしてきて展開します。生成された arduino-1.8.9 というディレクトリをホームディレクトリ直下に移動した後、
シェルを開いて、

$ cd ~/arduino-1.8.9/
$ sudo ./install.sh

で Arduino をインストール完了です。インストールが完了したら、 「Menu → プログラミング → Arduino」でArduino IDEを起動します。次にArduino IDEの「ファイル→環境設定」で「追加のボードマネージャのURL」に

https://github.com/espressif/arduino-esp32/releases/download/1.0.2/package_esp32_dev_index.json

を設定します。引き続き、「ツール→ボード→ボードマネージャ」で「esp32 by Espressif Systems」を探してインストールします。インストールが完了したら、「ツール→ボード→ESP32 Wrover module」を選択すれば、Arduino自体の準備は完了です。

2.ソースコードの導入

ソースコードは https://github.com/lewisxhe/esp32-camera-series からZIPでダウンロードしてきます。ダウンロードした esp32-camera-series-master.zip を展開し、展開したディレクトリ名をesp32-camera-seriesに変更して、~/Arduino の下に移動します。

Arduino IDEの「ファイル→開く」で ~/Arduino/esp32-camera-series/esp32-camera-series.ino を開いておきます。

3.ライブラリの準備

Arduino OneButton Library を https://github.com/mathertel/OneButton からZIPでダウンロードしてきて、OneButton-master.zip を展開します。展開したら、ディレクトリ名をOneButtonに変更して、~/Arduino/liraries の下に移動します。

BME280のライブラリについては TTGO T-Cameraでは正常な値を表示しない(そのため、途中から削除されている)のでソースコード中の

#include <Adafruit_BME280.h>

の行はコメントアウトしておきます。

esp8266-oled-ssd1306 Library を https://github.com/ThingPulse/esp8266-oled-ssd1306 からZIPでダウンロードしてきて、esp8266-oled-ssd1306-master.zipを展開します。ディレクトリ名をesp8266-oled-ssd1306に変更して、~/Arduino/liraries の下に移動します。

ここまででビルドと書き込みはできるはずです。Arduino IDEのチェックマーク(検証)を押してコンパイルしてみます。うまく行ったら、右矢印マークを押して書き込みもテストしておきます。

4.SoftAPモードからSTAモードへ変更

#define SOFTAP_MODE //The comment will be connected to the specified ssid

をコメントアウトして、SoftAPモードを禁止して、

#define WIFI_SSID "your wifi ssid"
#define WIFI_PASSWD "you wifi password"

のところに接続先のSSIDとパスワードを設定します。

5.ESP32のIPアドレスを固定IPに変更する

SSID/PASSWORDの設定の箇所の後に以下の記述を追加

#define FIXED_IP
#ifdef FIXED_IP
IPAddress fixed_ip( 192, 168, 1, 100); // for fixed IP Address
IPAddress gateway( 192, 168, 1, 1);  // Gateway Address
IPAddress subnet(255, 255, 255, 0);  // Subnet Mask
IPAddress DNS( 8, 8, 8, 8);          // DNS server
#endif

WiFi.begin()の直前に以下の記述を追加

    #ifdef FIXED_IP
    WiFi.config(fixed_ip, gateway, subnet, DNS); // Set fixed IP address
    #endif

6.mDNS対応

ローカルネット内からはIPアドレスではなくホスト名でアクセスできると便利なので、mDNS対応させておきます。

先頭の

#include <WiFi.h>

の後に

#include <ESPmDNS.h>

を追加します。続いて、SSID/PASSWORDの設定の箇所の後に以下の記述を追加します。

#define AVAHI
#ifdef AVAHI
#define AVAHI_HOST "esp32" // esp32.local
#endif

引き続き、setup()の最後の箇所の

    Serial.print("Camera Ready! Use 'http://");
    Serial.print(ip);
    Serial.println("' to connect");

#ifdef AVAHI
    // Set up mDNS responder (reference : mDNS_Web_Server.ino)
    if (!MDNS.begin(AVAHI_HOST)) {
        Serial.println("Error setting up MDNS responder!");
        while(1) {
            delay(1000);
        }
    }
    Serial.println("mDNS responder started");

    Serial.print("Camera Ready! Use 'http://");
    Serial.print(AVAHI_HOST);
    Serial.print(".local");
    Serial.println("' to connect");
#else
    Serial.print("Camera Ready! Use 'http://");
    Serial.print(ip);
    Serial.println("' to connect");
#endif

に変更します。更に、void drawFrame1(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) の中の

#ifdef SOFTAP_MODE
    display->setFont(ArialMT_Plain_10);
    display->drawString(64 + x, 25 + y, buff);
#else
    display->setFont(ArialMT_Plain_16);
    display->drawString(64 + x, 35 + y, ip);
#endif

//#ifdef AVAHI
//    display->setFont(ArialMT_Plain_10);
//    display->drawString(64 + x, 25 + y, "http://" AVAHI_HOST ".local");
//#else
    #ifdef SOFTAP_MODE
        display->setFont(ArialMT_Plain_10);
        display->drawString(64 + x, 25 + y, buff);
    #else
        display->setFont(ArialMT_Plain_16);
        display->drawString(64 + x, 35 + y, ip);
    #endif
//#endif

に書き換えます。(いくつかの行がコメントアウトになっているのは、表示にはIPアドレスもほしいためです。すべてURLでいい場合にはコメントを外します)
さらに、void drawFrame2(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)の中の

    display->drawString(64 + x, 25 + y, "http://" + ip );

    #ifdef AVAHI
        display->drawString(64 + x, 25 + y, "http://" AVAHI_HOST ".local");
    #else
        display->drawString(64 + x, 25 + y, "http://" + ip );
    #endif

に書き換えます。

7.カメラの向きとOLEDの表示が上下逆なのを修正

oled.init();

の後あたりに

oled.flipScreenVertically();

を追加します。

これでボードに書き込むと同じサブネットのPCからは http://esp32.local で、異なるPCからは http://IPアドレス でアクセスできます。どちらもOLEDディスプレイにも表示されます。