いっぺーちゃんの いろいろやってみよ~

ESP32でmicropython

天邪鬼ないっぺーちゃんはpythonを避けてEspruinoでごちょごちょやってきましたが、やはりpythonも試しておこうということで、micropythonを試してみることにします。

 

micropythonのビルドは、Windowsで色々ハマるより、Ubuntu仮想マシンで実行するのがオススメです。
私の環境はこんな感じです。
環境:Windows10 Home(64bit) + VirtualBox + Ubuntu(64bit) 16.04 LTS

インストールについては、このあたりでどうぞ。
(バージョンちょっと違うけど、手順は似たようなもんです)

 特に、sambaの設定をしておくと、WindowsからネットワークドライブとしてUbubtuのディスクが見えるので使い慣れたエディタが使えて便利です。

 

以下、ツールのインストールからビルド、書き込みまでの手順です。

使用するツール類をインストールします。

sudo apt-get install -y git wget make libncurses-dev flex bison gperf python python-serial

シリアルターミナルにgtktermを使いたい場合はインストールします

sudo apt-get install -y gtkterm

使わないっぽいけど入れておいてもいいかな?(たぶんesp-idfのサンプルをmakeするときに必要?)

sudo apt-get install -y autoconf  libtool

シリアルポートを使用するための設定をします。これをやらないとシリアルポートを使おうとしたときに「ぱーみっしょんでないど~」と怒られます。

sudo gpasswd -a <<ユーザ名>> dialout 

これを有効にするには一旦ログアウトして再ログインが必要ですが、後でやるのとまとめてもOKです。

 

作業ディレクトリを作成します。以降、この作業ディレクトリとして書いてありますので、自分の環境に合わせて読み替えてください。

mkdir -p /work2/esp
cd /work2/esp

コンパイラをインストールします。下記は64bit版です。32bitOSでは動きません。

wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz
tar xzvf xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz

esp-idf(ESP32のドライバ)を取得します。--recursiveの指定を忘れると悲しいことになるので注意してください。

git clone https://github.com/espressif/esp-idf.git --recursive

micropythonのソースを取得します。こっちも--recursive忘れないように。

git clone https://github.com/micropython/micropython-esp32.git --recursive

micropythonのソースは Sun Jul 30 19:44:58 2017 -0400 にcommitされたもの( ハッシュ値は 79feb95670311eee5ffb61f1dfd8183901d5e441 ) で確認しています。

~/.profile に以下の設定を追加します。

# for ESP32
export PATH=$PATH:/work2/esp/xtensa-esp32-elf/bin
export IDF_PATH=/work2/esp/esp-idf

# for Micropython
export ESPIDF=/work2/esp/esp-idf

.profileの設定を有効にするため、一旦ログアウトして再度ログインしてください。

 

再ログインしたら、micropythonのbuildにかかりましょう。

まず、micropythonクロスコンパイラを生成します。

cd /work2/esp/micropython-esp32/mpy-cross
make

必要なesp-idfのバージョン(HASH値)を確認します。バージョンが異なっているとmakeに失敗したり、うまく動作しなかったりすることがあります。

cd /work2/esp/micropython-esp32/esp32
make idf-version
== 結果 ==
ESP IDF supported hash: 4ec2abbf23084ac060679e4136fa222a2d0ab0e8

このHASHを使ってesp-idfをチェックアウトします。念のため、branch作っておきます。

cd /work2/esp/esp-idf
git checkout 4ec2abbf23084ac060679e4136fa222a2d0ab0e8 -b micropythn

submoduleもupdate します。これ重要!! やらないとsubmoduleと本体のバージョンが合わなくなることがあります。

git submodule update

 

ESP32用 micropython をbuildします。

cd /work2/esp/micropython-esp32/esp32
make

buildが完了したらプログラムを書き込むためESP32を接続します。

ESP32は/dev/ttyUSB0につながっているものとします。それ以外につながっているときは、PORT=/dev/ttyほにゃらら で指定してください。

現在書き込まれているプログラムを消去します。Flash全体を消去しますので、すべてのデータが消去されます。

make erase

buildしたプログラムを書き込みます。

make deploy

Flashの書き込みで失敗する場合は、
VirtualBoxでは 一旦仮想マシンをシャットダウンし、VirtualBoxマネージャで 設定→USB の「USB 3.0(xHCI)コントローラ」を選択してから再起動してみてください。

 

ターミナルソフトを起動します。

gtkterm&

Configuration → Port でポートの設定をします

Port /dev/ttyUSB0
BaudRate 115200
Parity none
Bits 8
Stopbits 1
Flow control Xon/Xoff

 

を選択してOK

Configuration → Save configuration で設定を保存します
Configuration name にdefaultを指定し、OK
overwrite?と聞かれるのでOK

defaultに保存しておけば、次回からは設定不要です。

ターミナルソフトを起動してからESP32をリセットしないと、通信がうまくいかないようです。
ターミナルソフトを起動した後、ESP32のリセットボタンを押してください。

 

gitで最新版のファイルに差し替えるには、git pull するのが普通だけど、
今あるディレクトリを~.oldとかにリネームしておいて、再度新しくgit clone した方が間違いが少ないと思われます。(submodule関連がとくにややこしい)
開発に参加しているわけではないので、それで事足ります。
自分が修正した部分は、あらかじめgit diff を保存しておいて、新しいディレクトリでpatchをあてるのが簡単かな。

 

 

 

Espruino on ESP32 で Twitter にも日本語を

LINEでは日本語の送信をできるようにしたので、Twitterでも日本語の送信ができるようにということで、Espruino on ESP32 で Twitter(その2) - いっぺーちゃんの いろいろやってみよ~ で紹介したtiny_twitterモジュールのtweet処理のメッセージを日本語対応にしてみました。

 

チョイ変だけで済むと思ったら、そうでもなかった。。。
ついでにパーセントエンコード処理がダブっていた部分を整理したり、ちょこちょこと変更しました。

 

以下が日本語対応版 tiny_twitter モジュールです。

tiny_twitter_20170803.zip

zipファイルを解凍してオンボードストレージの /node_modules ディレクトリに格納してください。
日本語対応しているのは送信のみで、受信は対応していません。
受信を日本語対応するには、Espruino本体のString関連処理を大幅に修正する必要がありそうなので、あきらめました。

 

日本語をtweetするには、LINEのときと同様に送信文字列をあらかじめパーセントエンコードしたものを指定し、第3パラメータにエンコード済みを示すtrueを指定します。

var message = "%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86";                 // おはよう
var param   = {"trim_user":true,"include_entities":false};
tw.tweet(message, param, true);                    // パーセントエンコード済み文字列のときは第3パラメータをtrueに

 

これを使って、Espruino on ESP32 で Twitter(その3) - いっぺーちゃんの いろいろやってみよ~ のTweetボタンを日本語化したものが以下です。

 

consumer_key    = '取得した Consumer key';
consumer_secret = '取得した Consumer secret';
access_token    = '取得した Access Token';
access_secret   = '取得した Access Token Secret';

var messages = [
    "%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86",                 // おはよう
    "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF",        // こんにちは
    "%E3%81%93%E3%82%93%E3%81%B0%E3%82%93%E3%81%AF",        // こんばんは
    "%E3%81%8A%E3%82%84%E3%81%99%E3%81%BF",                 // おやすみ
];

if (typeof(ESP32) ==='function') {
    // platform is espruino on ESP32
    // Wi-Fi アクセスポイントへの接続
    var wifi = require('MyWifi');
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);

    // Initialize for switch
    var sw1  = Pin(21);
    sw1.mode("input" );
} else {
    throw "not ESP32";
}

// モジュール読み込み
var tiny_twitter = require("tiny_twitter");

// 初期化
var tw = new tiny_twitter(consumer_key, consumer_secret, access_token, access_secret, true);

tw.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});
tw.on("response_header", function(data, code, msg) {
    if (code != 200) {
        console.log("%%%% RESPONSE ERROR!!!   " + code.toString() + " : " + msg);
    }
    console.log("%%%% RESPONSE_HEADER %%%%\n" + data + "\n%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("data", function(data) {
    console.log("%%%% DATA %%%%");
    console.log(JSON.stringify(data,  null, '\t'));
    // エラー時はdata.errors.code data.errors.message に情報が入る
    console.log("%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("end", function() {
    console.log("%%%% END %%%%");
});

function button_down(e) {
    var msg;
    var date = new Date();
    h = date.getHours();
    if (h >=4 && h < 12) {
        msg = messages[0];      // おはよう
    } else if (h >=12 && h < 17){
        msg = messages[1];      // こんにちは
    } else if (h >=17 && h < 21){
        msg = messages[2];      // こんばんは
    } else {
        msg = messages[3];      // おやすみ
    }
    tw.tweet(msg, {"trim_user":true,"include_entities":false}, true);
}

setWatch(button_down, sw1, {repeat:true, edge:"falling", debounce:100});

 

 これで日本語をtweetすることができるようになりました(ひと手間余分に必要ですが)。
ちょっと使い道が広がったかな??

 

Espruino on ESP32 で LINE(その2)

Espruino on ESP32 で Twitter(その3) - いっぺーちゃんの いろいろやってみよ~ のLINE版も作っておきます。

 ボタンを押したらLINEにメッセージが飛ぶ、LINEボタンです。

 こんな感じです。

var access_token    = '取得したアクセストークン';

var messages = [
    "%E3%81%8A%E3%81%AF%E3%82%88%E3%81%86",                 // おはよう
    "%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF",        // こんにちは
    "%E3%81%93%E3%82%93%E3%81%B0%E3%82%93%E3%81%AF",        // こんばんは
    "%E3%81%8A%E3%82%84%E3%81%99%E3%81%BF",                 // おやすみ
];

if (typeof(ESP32) ==='function') {
    // platform is espruino on ESP32
    // Wi-Fi アクセスポイントへの接続
    var wifi = require('MyWifi');
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);

    // Initialize for switch
    var sw1  = Pin(21);
    sw1.mode("input" );
} else {
    throw "not ESP32";
}

// モジュール読み込み
var tiny_line   = require("tiny_line");

// 初期化
var tl = new tiny_line(access_token, true);

tl.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});
tl.on("response", function(code, msg, data) {
    if (code == 200) {
        console.log("%%%% RESPONSE : " + code.toString() + " : " + msg + " %%%%");
    } else {
        console.log("%%%% RESPONSE ERROR!!! : " + code.toString() + " : " + msg + " %%%%");
        console.log("#### RESPONSE ####");
        console.log(data);
        console.log("############");
    }
});
tl.on("end", function() {
    console.log("%%%% END %%%%");
});

function button_down(e) {
    var msg;
    var date = new Date();
    h = date.getHours();
    if (h >=4 && h < 12) {
        msg = messages[0];      // おはよう
    } else if (h >=12 && h < 17){
        msg = messages[1];      // こんにちは
    } else if (h >=17 && h < 21){
        msg = messages[2];      // こんばんは
    } else {
        msg = messages[3];      // おやすみ
    }
    tl.notify(msg, true);
}

setWatch(button_down, sw1, {repeat:true, edge:"falling", debounce:100});

 

 

 解説を、と思ったけど解説するまでもありませんね。
Twitter用の処理(モジュール読み込みとか初期化とか送信処理など)をLINE用に置き換えただけです。
日本語が使えるようになったので、送信文字列は日本語にしておきました。

 

 

Espruino on ESP32 で 今更だけど時刻変更

テスト用に時刻変更しようと思ったら、時刻設定方法ってどうだっけ?とすぐに出てこなかったので、メモ。

以下のように実行すればOK

setTime(Date("2017-07-30T21:00:00").ms/1000)

Date.msで得られる値はミリ秒で、setTime()に設定する値は秒なので、1000で割る。

Dateは年月日区切りは「-」で、時分秒区切りは「:」。その間に「T」を入れる。

 

 

Espruino on ESP32 で LINE(その1)

Twitterへのアクセスにも飽きてきたので、今回はLINEにメッセージを投げてみます。
LINEにはWebサービスから簡単にメッセージを送信できる、LINE Notifyというサービスがあります。これを使用すると簡単にLINEにメッセージを送信できます。

 

LINE Notifyでメッセージを送信するには、アクセストークンを取得する必要があります。
例によって、先人の知恵を拝借してアクセストークンを取得しましょう。

[超簡単]LINE notify を使ってみる - Qiita

自分にだけメッセージを送信したい場合は、トークルームではなく
「1:1でLINE Notifyから通知を受け取る」
を選択します。
通知先は変更できません。変更するにはアクセストークンを再発行してください。
アクセストークンを他人に知られると、勝手にメッセージが送られることがあるので、注意しましょう。

アクセストークンを無効にするには、LINEのマイページにある、「連携中のサービス」から対象のサービスの解除ボタンをクリックしてください。

 

それでは、LINE Notifyにメッセージを送信するモジュールです。

以下をtiny_line.jsというファイル名でオンボードストレージの /node_modules ディレクトリに格納してください。

var tls      = require("tls");

if (typeof(E) ==='function') {
    // platform is espruino
     var platform = 'espruino';
}
else {
    // platform is node.js
    var platform = 'node';
    var events = require('events');
    var util = require('util');
}

// ######## percent encording ################################
var RFC3986_encode = function(str) {
    // var ret = encodeURIComponent(str);
    // change according to RFC3986
    /* ********** RegEx are not supported in Espruino
    var ret = encodeURIComponent(str).replace(/[!*'()]/g, 
            function(p) {
                return "%" + p.charCodeAt(0).toString(16);
            });
     ********** */
    var tmp = encodeURIComponent(str);
    var ret = "";
    for (var i = 0; i < tmp.length; i++) {
        var c = tmp[i];
        if ((c==="!") || (c==="*") || (c==="'") || (c==="(") || (c===")")) {
            ret += '%'+c.charCodeAt(0).toString(16);
        } else {
            ret += c;
        }
    }
    return ret;
}


// ######## tiny_line class ################################
var tiny_line = function(access_token, _DEBUG_)
{
    this.access_token    = access_token;
    this._DEBUG_         = _DEBUG_;

    if (platform == 'node') {
        // for EventEmitter
        events.EventEmitter.call(this);
    }
}

if (platform == 'node') {
    // for EventEmitter
    util.inherits(tiny_line, events.EventEmitter);
}

// ######## debug print ################################
tiny_line.prototype.debug_print = function(str) {
    if (this._DEBUG_) {
        //console.log(Date().toString());
        console.log(str);
    }
}


// ######## make request message ################################
tiny_line.prototype.makeRequestMessage = function(method, server, endpoint, message){
    method = method.toUpperCase();          // to upper

    // make message body
    var body = 'message=' + message;

    // make request
    var request = method + ' ' + endpoint + ' HTTP/1.1\n';

    // make message header
    var header  = 'Host: ' + server + '\n'
                + 'User-Agent: espruino line Bot v0.1\n'
                + 'Accept: */*\n'
                + 'Connection: close\n'         // これがないとレスポンス受信後も接続状態が保持されてしまう
                + 'Authorization: Bearer ' + this.access_token +'\n'
                + 'Content-Type: application/x-www-form-urlencoded\n'
                + 'Content-Length: ' + body.length.toString() + '\n';

    // request message
    var ret = request + header + '\n' + body + '\n';

    return ret;
}

// ######## Send message ################################
tiny_line.prototype.sendmessage = function(host, msg) {
    var _self = this;
    var client = tls.connect(host, function() {
        client.on('data', function(data) {
            var rcv_header = data.toString();       // 文字列に変換
            var p0 = rcv_header.indexOf('\n');      // 最初の改行の位置
            var line = rcv_header.slice(0, p0);     // 最初の1行取り出し

            var p1 = line.indexOf(' ') + 1;         // 最初のスペースの次(エラーコードの位置)
            var p2 = line.indexOf(' ', p1) + 1;     // 二個目のスペースの次(エラーメッセージの位置)
            var err_code = parseInt(line.slice(p1, p2));
            var err_msg = line.slice(p2);
            _self.emit("response", err_code, err_msg, rcv_header);
        });
        client.on('end', function() {
            _self.emit("end");
        });
        _self.emit("connect");
        client.write(msg);
    });
}

// ######## notify API ################################
tiny_line.prototype.notify = function(msg, encoded) {
    if (!msg) {
        throw new Error("message is required."); 
    }
    var server = 'notify-api.line.me';
    var host = { host: server, port: 443};

    // メッセージがエンコードされていなければエンコードする
    if (!encoded) {
        msg = RFC3986_encode(msg);
    }

    var reqMessage = this.makeRequestMessage('POST', server, '/api/notify', msg);

    this.debug_print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");
    this.debug_print(reqMessage);
    this.debug_print("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%");

    this.sendmessage(host, reqMessage);
}

module.exports = tiny_line;
module.exports.RFC3986_encode = RFC3986_encode;

準備ができたら、以下のプログラムを実行してみましょう。

var access_token    = '取得したアクセストークン';

if (typeof(ESP32) ==='function') {
    // platform is espruino on ESP32
    // Wi-Fi アクセスポイントへの接続
    var wifi = require('MyWifi');
}
if (typeof(E) ==='function') {
    // platform is espruino
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);
}

// モジュール読み込み
var tiny_line   = require("tiny_line");

// 初期化
var tl = new tiny_line(access_token, true);

tl.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});
tl.on("response", function(code, msg, data) {
    if (code == 200) {
        console.log("%%%% RESPONSE : " + code.toString() + " : " + msg + " %%%%");
    } else {
        console.log("%%%% RESPONSE ERROR!!! : " + code.toString() + " : " + msg + " %%%%");
        console.log("#### RESPONSE ####");
        console.log(data);
        console.log("############");
    }
});
tl.on("end", function() {
    console.log("%%%% END %%%%");
});

// メッセージ送信
tl.notify("good morning! (or afternoon)", false);

 

 プログラムを実行すると、LINEに以下のようなメッセージが送信されます。

「[トークン名] good morning! (or afternoon)」

 

 

 以下、プログラムの説明です。

 

 Twitterのときにも使った、ESP32専用設定、Espruino専用設定の部分です。

if (typeof(ESP32) ==='function') {
    // platform is espruino on ESP32
    // Wi-Fi アクセスポイントへの接続
    var wifi = require('MyWifi');
}
if (typeof(E) ==='function') {
    // platform is espruino
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);
}

 

 モジュールを読み込みます。

// モジュール読み込み
var tiny_line   = require("tiny_line");

 

 tiny_lineのインスタンスを生成します。
第1パラメータは↑で取得したアクセストークンです。
第2パラメータはモジュール内部のdebug_print (今回はtypo直しました)を表示するか否かを指定しています。
色々表示されてうっとうしい場合はfalseにしてください。

// 初期化
var tl = new tiny_line(access_token, true);

 

 接続処理時のイベントハンドラです。イベントは"open"、"response"、"end"があります。
"response"イベントのパラメータは
    code    エラーコード
    msg     エラーメッセージ
    data    受信データ全体
です。

tl.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});
tl.on("response", function(code, msg, data) {
    if (code == 200) {
        console.log("%%%% RESPONSE : " + code.toString() + " : " + msg + " %%%%");
    } else {
        console.log("%%%% RESPONSE ERROR!!! : " + code.toString() + " : " + msg + " %%%%");
        console.log("#### RESPONSE ####");
        console.log(data);
        console.log("############");
    }
});
tl.on("end", function() {
    console.log("%%%% END %%%%");
});

 

 メッセージの送信処理です。
第1パラメータが送信する文字列、
第2パラメータが文字列がパーセントエンコード済みか否かを示すフラグです。これがfalse または省略されていると、送信文字列をnotify関数内部でエンコードします。

// メッセージ送信
tl.notify("good morning! (or afternoon)", false);

 

 メッセージ送信部分を以下のように変更すると、
「[トークン名] 現在の時刻は Sat Jul 29 2017 11:15:37 GMT+0900 です」
のような日本語を含んだメッセージを送信することもできます。

var date = new Date();
date_str = tiny_line.RFC3986_encode(date.toString());
var str1 = "%E7%8F%BE%E5%9C%A8%E3%81%AE%E6%99%82%E5%88%BB%E3%81%AF%20"; // 現在の時刻は 
var str2 = "%20%E3%81%A7%E3%81%99";                                     //  です
tl.notify(str1 + date_str + str2, true);

 

 notify関数の第1パラメータにパーセントエンコード済みの送信文字列を、第2パラメータにtrueを指定します。
パーセントエンコードはRFC2396でも大丈夫なようですが、念のためRFC3986にしてあります。

全角文字を含む静的な文字列のパーセントエンコードは、以下のサイトなどで行えます。
http://www.tagindex.com/tool/url.html
(文字コードで「UTF-8」を選択してから「エンコードする」ボタンをクリックしてください)
動的に変更したい半角文字列はtiny_line の RFC3986_encode 関数がエクスポートされているので、それを使えばOK。

 

 

 

 

 

 

 

Espruino on ESP32 で Twitter(その5)

前回Espruino on ESP32 でLチカ - いっぺーちゃんの いろいろやってみよ~ を組み合わせて、TwitterからLEDを制御してみましょう。

 

以下にそのプログラムを示します。

consumer_key    = '取得した Consumer key';
consumer_secret = '取得した Consumer secret';
access_token    = '取得した Access Token';
access_secret   = '取得した Access Token Secret';

if (typeof(ESP32) ==='function') {
    // platform is espruino on ESP32
    // Wi-Fi アクセスポイントへの接続
    var wifi = require('MyWifi');

    // Initialize for LED1
    var led1 = Pin(23); 
    led1.mode("output");
    led1.reset();

    var led_on = function() {
        led1.set();
    };
    var led_off = function() {
        led1.reset();
    };
} else {
    var led_on = function() {
        console.log("LED ON");
    };
    var led_off = function() {
        console.log("LED OFF");
    };
}
if (typeof(E) ==='function') {
    // platform is espruino
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);
}

// モジュール読み込み
var tiny_twitter = require("tiny_twitter");

// 初期化
var tw = new tiny_twitter(consumer_key, consumer_secret, access_token, access_secret, true);

tw.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});
tw.on("response_header", function(data, code, msg) {
    if (code != 200) {
        console.log("%%%% RESPONSE ERROR!!!   " + code.toString() + " : " + msg);
    }
    console.log("%%%% RESPONSE_HEADER %%%%\n" + data + "\n%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("data", function(data) {
    console.log("%%%% DATA %%%%");
    // console.log(JSON.stringify(data,  null, '\t'));
    if (data.text) {
        console.log(data.text);
        if (data.text.indexOf('LED') >= 0) {
            if (data.text.indexOf('ON') >= 0) {
                led_on();
            }
            else if (data.text.indexOf('OFF') >= 0) {
                led_off();
            }
        }
    } else {
        console.log("** NO TEXT **");
    }
    console.log("%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("end", function() {
    console.log("%%%% END %%%%");
});

// オプション指定
param = {"with":"user"};

// twitterに接続
tw.userstream(param);

 

前回との差分です。

 

ESP32のときは、LED用の端子の初期化とそれをON/OFFする関数を定義しています。

    // Initialize for LED1
    var led1 = Pin(23); 
    led1.mode("output");
    led1.reset();

    var led_on = function() {
        led1.set();
    };
    var led_off = function() {
        led1.reset();
    };

 

それ以外の場合は、LED制御ができないので、コンソールにON/OFFを表示する関数を代替処理として定義しています。

    var led_on = function() {
        console.log("LED ON");
    };
    var led_off = function() {
        console.log("LED OFF");
    };

 

また、データ受信時のイベントハンドラ内で、メッセージ本体内に「LED」と「ON」が含まれていたらLEDをONする関数をコール、
「LED」と「OFF」が含まれていたらLEDをOFFする関数をコールする処理を追加しています。
「LED ON OFF」や「LED not ON」 のような意地悪なメッセージは考慮していません(この実装ではどちらもONとして扱われる)。

        if (data.text.indexOf('LED') >= 0) {
            if (data.text.indexOf('ON') >= 0) {
                led_on();
            }
            else if (data.text.indexOf('OFF') >= 0) {
                led_off();
            }
        }

 

プログラムを実行したら、ここで使用しているアカウントで、ブラウザやスマホから「LED ON 1」とtweetしてみましょう。
LEDが点灯したと思います。

 

大文字、小文字は区別されますので、すべて大文字にしてください。
しつこいようですが、全角文字ではダメです。
最後の「1」は連続してtweetするときに同じ文にならないように追加しているだけなので、何でもかまいません。
連続してtweetするときはこの部分を変更してtweetしてください。
「LEDON」のように空白を挟まない場合や「ON LED」と順序を逆にした場合でもOKです。

 

 

次に「LED OFF 1」とtweetするとLEDが消灯します。

 

 

オプションを以下のようにすると、
ハッシュタグ「#ESP32_LED_CONTROL」が付いた自分以外からのtweetでもLEDをコントロールすることができます。
(文字列を見ているだけなので、ハッシュタグである必要はないですが)

 

param = {"with":"user", "track":"#ESP32_LED_CONTROL"};

 

ESP32 に赤外線LEDつけて、リモコン処理を代替できるようにすると、TwitterからエアコンのON/OFFができる、なんて夢が広がりますね(←勝手にエアコンONされて、電気代がぁぁぁ、って心配が。。。)

 

 twitterに関する記事はこれでおしまい。

Espruino on ESP32 で Twitter(その4)

前々回前回とtweetする方のプログラムだったので、今回はtweet内容を受信するプログラムを試してみます。

最初に注意事項です。あまりたくさんのtweetを一度に受信してしまうと、メモリ不足で落ちてしまいます。

 

ここでは、Streaming API の User streams を使用します。
User streams というのは、大雑把に言うと自分のタイムラインに流れてくるメッセージを監視するものです。
取得対象はその時点で流れてくるメッセージなので、過去にtweetされたメッセージは取得できません。

APIの詳細は User streams — Twitter Developers を参照してください。

 

それでは、以下のプログラムを実行してみましょう。

 

consumer_key    = '取得した Consumer key';
consumer_secret = '取得した Consumer secret';
access_token    = '取得した Access Token';
access_secret   = '取得した Access Token Secret';

if (typeof(ESP32) ==='function') {
    // platform is espruino on ESP32
    // Wi-Fi アクセスポイントへの接続
    var wifi = require('MyWifi');
}
if (typeof(E) ==='function') {
    // platform is espruino
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);
}

// モジュール読み込み
var tiny_twitter = require("tiny_twitter");

// 初期化
var tw = new tiny_twitter(consumer_key, consumer_secret, access_token, access_secret, true);

tw.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});
tw.on("response_header", function(data, code, msg) {
    if (code != 200) {
        console.log("%%%% RESPONSE ERROR!!!   " + code.toString() + " : " + msg);
    }
    console.log("%%%% RESPONSE_HEADER %%%%\n" + data + "\n%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("data", function(data) {
    console.log("%%%% DATA %%%%");
    // console.log(JSON.stringify(data,  null, '\t'));
    if (data.text) {
        console.log(data.text);
    } else {
        console.log("** NO TEXT **");
    }
    console.log("%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("end", function() {
    console.log("%%%% END %%%%");
});

// オプション指定
param = {"with":"user"};

// twitterに接続
tw.userstream(param);

 

初期化までと、接続時、ヘッダ受信時、切断時のイベントハンドラは前回と同じです。
データ受信時のイベントハンドラでは受信したメッセージ本体だけを表示するように変更してあります。
受信したデータ全部を表示したいときは、以下の部分を有効化してください。

 console.log(JSON.stringify(data,  null, '\t'));

 

あとは、オプションを指定してuserstreamを実行しています。
このプログラムは接続すると、サーバ側から切断されるか、リセットするまで接続を保持します。
このモジュールは簡易的な実装なので、能動的な接続の切断や再接続については考慮されていません。

 

プログラムを実行すると、以下のように表示されるでしょう。

%%%% CONNECTED %%%%
%%%% RESPONSE_HEADER %%%%
HTTP/1.1 200 OK
~中略~
%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% DATA %%%%
** NO TEXT **
%%%%%%%%%%%%%%%%%%%%%%%%%

最初に「** NO TEXT **」と表示されるのは、friends list というのが送られてくるからです。フォローしている人の一覧のようです。

この状態で、ここで使用しているアカウントで、ブラウザやスマホからtweetしてみましょう。

%%%% DATA %%%%
hogehoge1
%%%%%%%%%%%%%%%%%%%%%%%%%

こんな表示が出ると思います。

え?こんな表示が出た?

%%%% DATA %%%%
dDc_・
%%%%%%%%%%%%%%%%%%%%%%%%%

それは、日本語をtweetしたからでしょう。
Espruinoは日本語に対応していないので、半角文字しか認識できません。
ちなみに、↑が出たときは「ついったー」とtweetしました。

 

オプション指定を以下のようにすると、自分のtweetとフォローしている人のtweetが取得できます。
(タイムラインの表示とほぼ同じ)

param = {"with":"followings"};

 

また、以下の指定では、自分のtweetすべてとキーワード"hogehoge"を含むtweet(フォローしている人以外も)が取得できます。

param = {"with":"user", "track":"hogehoge"};

trackに指定するキーワードは空白区切り、またはカンマ区切りで複数指定することができます。

空白区切り "track":"hogehoge fugafuga" hogehoge と fugafuga の両方を含む
カンマ区切り "track":"hogehoge,fugafuga" hogehoge か fugafuga のどちらか一方を含む

 

"track"に"test"のような一般的なキーワードを指定すると、たくさんのtweetが取得できてしまい、メモリ不足で落ちますので、注意してください。
複数のアカウントからのメッセージを取得したいような場合、ユニークなキーワードを含めてtweetするような運用にするのが良いでしょう。
また、キーワードには "#hoge" のように、ハッシュタグを指定することもできます。
しつこいようですが、Espeuinoは日本語に対応していないので、日本語のキーワードは指定できません。

 

「自分のtweet かつ、キーワード○○を含む」というような指定はできないようです。このような条件を実現するには、一旦自分のtweetをすべて取得して、
その中でメッセージに○○を含むかどうか確認するしか方法はないようです。



 

 

次回 に続く。。。