お片付け応援システムを作る


はじめに

ものの配置が決まっている場合、使ったら戻すというルールになっていることが多いです。
しかし、ついつい戻すのを忘れたり、面倒だったりするわけです。
そこで、誰かに背中を押してもらえたら、片付けへの意欲がわくんじゃないかという発想で考えてみました。
基本的には子供のお片付けを想定しています。

作りたいもの

特定の時間に定位置にものがないと判断された場合、「片付けよう」と応援してくれるシステム

用意するもの

-距離センサGP2Y0E03
-ESP-WROOM32(ESP32-DevKitC)
-RaspberryPi
-スピーカー

やり方

⒈ESP-WROOM-32に距離センサを接続し、特定の時間に片付け場所から物体までの距離を測定する。
⒉距離が閾値を超えている場合、片付けられていないと判断し、RaspberryPiにHTTP POSTする。
⒊RaspberryPiはHTTP POSTを受けて、「片付けよう」としゃべる。

完成イメージ

作る

ESP-WROOM-32の処理

ソースコード全体はgithubに置いてあります。
ビルドにはESP-IDFが必要になります。

センサから距離を取得する

ソースコードはsensor.cです。
距離センサをESP-WROOM-32に接続して、距離の測定を行います。
以前に書いた距離センサで防犯システムをDIYと同じ接続です。

RaspberryPiに通知する

ソースコードはhttp_request.cです。
距離センサで片付けられていない状態を検出した場合、ESP-WROOM-32からRaspebrryPiに対してHTTP POSTを行います。

片付け状態を確認する

片付け状態は毎日20時に確認を開始します。距離センサから30cm以内に物体がない場合を片付けられていない状態とします。
片付けが行われない場合、1分毎に片付け応援メッセージが流れます。

#include "http_request.h"
#include "sensor.h"
#include "nvs_flash.h"
#include <time.h>
#include <sys/time.h>
#include "esp_log.h"
#include "esp_sleep.h"
#include "esp_wifi.h"
#include "ntptime.h"

#define EMPTY_DISTANCE  30
#define CHECK_HOUR      20

static const char *TAG = "main";

esp_err_t monitor(bool *need_check)
{
    esp_err_t ret;

    ret = reset_sensor();
    if(ret != ESP_OK){
        ESP_LOGI(TAG, "Sensor reset failed!");
        return ret;
    }

    int distance;
    ret = read_distance(&distance);
    if (ret != ESP_OK) {
        ESP_LOGI(TAG, "data_l:No ack, sensor not connected...skip...");
        return ret;
    }

    if(distance >  EMPTY_DISTANCE){
        ESP_LOGI(TAG, "not declutter...");
        http_post_task();
    }else{
        ESP_LOGI(TAG, "decluttered");
        *need_check = false;
    }

    return ESP_OK;
}

void app_main()
{
    ESP_ERROR_CHECK( nvs_flash_init() );
    init_sensor();
    initialise_wifi();

    time_t now;
    struct tm timeinfo;
    char strftime_buf[64];

    ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
    obtain_time();
    // update 'now' variable with current time
    time(&now);

    time_t t = now + (3600 * 9);
    localtime_r(&t, &timeinfo);
    strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
    ESP_LOGI(TAG, "The current date/time in JST-2 is: %s", strftime_buf);

    bool need_check = false;
    int check_start_hour = CHECK_HOUR;
    int check_start_day = timeinfo.tm_mday;

    while(true){
         //get time
        time(&now);
        t = now + (3600 * 9);
        localtime_r(&t, &timeinfo);
        strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
        ESP_LOGI(TAG, "The current date/time in JST-2 is: %s", strftime_buf);

        if(timeinfo.tm_mday == check_start_day && timeinfo.tm_hour >= check_start_hour){ 
            need_check = true;
            check_start_day++;
        }

        if(need_check==true){
            esp_err_t ret = monitor(&need_check);
            if(ret != ESP_OK){
                ESP_LOGI(TAG, "Device error occured!!");
                return;
            }
        }

        //sleep 1 minute
        esp_sleep_enable_timer_wakeup(1000000LL * 60);
        esp_light_sleep_start();
    }
}

ソースコードはmain.cにもあります。
monitor関数で片付け状態を検出し、片付けられていない場合、RaspberryPiに通知を行います。
main関数ではPowerOn直後にNTPから時刻を取得し、日本時間で毎日20時に片付け状態確認を行います。
省電力のため、デバイスをsleepさせながら、1分ごとに時刻を更新しています。
省電力を考えるなら、ここは毎日20時に起きるようにタイマーを仕掛けたほうがいいと後から思いました。
NTP時刻の取得処理はntptime.cです。

RaspberryPiの処理

通知を受け取り、喋る処理を実行する

ソースコードはindex.phpです。
PHPでHTTP POSTメッセージを処理し、喋る処理を実行します。
上記は関係ない処理が入っているため、ここでの処理を抜き出すと以下のようになります。

index.php
<?php
function func_cheer(){
    exec('/home/pi/work/jtalk.sh "そろそろ片付けの時間だよ。頑張って片付けよう。"');
    return;
}

if($_POST['text'] == "decluttering"):
    func_cheer();
endif;
?>

RaspberryPiに喋らせる

音声出力はOpen JTalkを使用します。
JERRY WAREを参考に、インストールと設定を行いました。
スクリプトを実行することでRaspberryPiが喋るようにしておきます。

jtalk.sh
#!/bin/bash                                                                                                                         
tempfile=`tempfile`                                                                                                                 
option="-m /usr/share/hts-voice/mei/mei_normal.htsvoice -x /var/lib/mecab/dic/open-jtalk/naist-jdic -ow $tempfile"                  

echo "$1" | open_jtalk $option                                                                                                      
aplay -q $tempfile                                                                                                                  
rm $tempfile  

上記の参考サイトと同じです。
デフォルトの男性の声だと体育会系になってしまったので、女性の声に変えました。

注意点

実験でPHPから実行してみましたが、音が鳴りませんでした。
調べたところ、/dev/snd/のパーミッションが許可されていないようなので、
Apache2をAudioグループに入れておきます。(セキュリティ面はあまり考えていません)

sudo vi /etc/group
group
...
audio:x:29:pi,pulse,www-data
...

のようにします。私の環境ではApache2のユーザー名はwww-dataでした。
これでPHPで音声が出力されるようになりました。

テスト

ESP-WROOM-32 + 距離センサです。

RaspberryPi + スピーカーです。

まず、片付けられていない状態で確認開始時間を迎えます。(時間はテスト用に変えています)

するとRaspberryPiが応援してくれました。

よし、片付けだ。人形を元の場所に片付そう。

何も言わなくなった。

ちょっと寂しいので、褒めメッセージを仕込んだ方がいいと思いました。
時間があれば追加します。

おわりに

何かものを置いておけば、黙ってしまうのが欠点です。