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

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をすべて取得して、
その中でメッセージに○○を含むかどうか確認するしか方法はないようです。



 

 

次回 に続く。。。

 

 

Espruino on ESP32 で Twitter(その3)

Espruino on ESP32 でぽちっとな - いっぺーちゃんの いろいろやってみよ~Espruino on ESP32 で Twitter(その2) - いっぺーちゃんの いろいろやってみよ~ を組み合わせてTweetボタンを作ってみましょう。

大雑把に言うと Espruino on ESP32 でぽちっとな - いっぺーちゃんの いろいろやってみよ~ でスイッチのステータスを表示していた部分をtweet処理に変えるだけです。

 

 以下、そのソースです。

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');
    // 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 = 'Good morning, everyone!!';
    } else if (h >=12 && h < 17){
        msg = 'Good afternoon, everyone!!';
    } else if (h >=17 && h < 21){
        msg = 'Good evening, everyone!!';
    } else {
        msg = 'Good night, everyone!!';
    }
    tw.tweet(msg, {"trim_user":true,"include_entities":false});
}

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

 

 このプログラムを実行すると、Pin21に接続されたスイッチを押すたびにその時刻に応じた挨拶がtweetされます。

スイッチを押してからtweet完了まで4~5秒程度かかります。

tweet完了前に再度スイッチを押したときの動作は未確認です(メモリ不足で落ちそうな気がするけど)。

tweet開始~endイベントまで次のtweet要求をブロックすれば良いのかな?
ま、ぽんぽん押さなければ良いだけなので、そのままにしておこう。

 

 以下処理の説明です。

ESP32の場合はWi-Fiに接続してタイムゾーンを設定し、スイッチ用の端子を初期化します。
それ以外の環境ではスイッチが使えないのでエラー終了します。

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";
}

 

モジュール読み込み~イベントハンドラは前回と同じです。

 

スイッチが押されたときのハンドラです。
現在時刻を取得し、時刻に応じた挨拶をtweetしています。
時刻の区切りには異論もあるでしょうけど。。。
日本語が使えれば、もうちょっと気の利いたtweetができるんですが。。。。

function button_down(e) {
    var msg;
    var date = new Date();
    h = date.getHours();
    if (h >=4 && h < 12) {
        msg = 'Good morning, everyone!!';
    } else if (h >=12 && h < 17){
        msg = 'Good afternoon, everyone!!';
    } else if (h >=17 && h < 21){
        msg = 'Good evening, everyone!!';
    } else {
        msg = 'Good night, everyone!!';
    }
    tw.tweet(msg, {"trim_user":true,"include_entities":false});
}

 

スイッチにハンドラを割り当てます。
今回はスイッチが押されたときだけ処理したいので、「edge:"falling"」としています。

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

 

 これで、わざわざESP32からtweetする価値が出てきたかな?

温度センサの値を読んで、定期的(10分に1回とか)にtweetする、なんて使い方もできそうですね。

 


 

次回に続く。。。

 

Espruino on ESP32 で Twitter(その2)

以下がtwitterにアクセスするためのモジュールです。
さらっと書いてますが、血と汗と涙の結晶です。

====2017/08/03追記 ここから====

 Espruino on ESP32 で Twitter にも日本語を - いっぺーちゃんの いろいろやってみよ~で新しいバージョンを公開しました

====2017/08/03追記 ここまで====

 

====2017/08/03削除 ここから====

tiny_twitter.zip

zipファイルを解凍してオンボードストレージの /node_modules ディレクトリに格納してください。

 

====2017/07/30追記 ここから====

 Node.jsで実行するとエラーになりました。
Espruino用HMACSHA1モジュールの仕様を変更したのを忘れてました(^^ゞ
以下の修正で使用できるようになります。

--- tiny_twitter.js.old2	2017-07-30 11:37:47.540869675 +0900
+++ tiny_twitter.js	2017-07-30 11:40:36.641894478 +0900
@@ -113,7 +113,11 @@
     // make signature
     var signing_key = RFC3986_encode(this.consumer_secret) + '&' + RFC3986_encode(this.access_secret);
     // console.log("key:" + signing_key);
-    var sig = hmacsha1.b64(signing_key, sigbase_str);
+    if (platform == 'node') {
+        var sig = hmacsha1(signing_key, sigbase_str);
+    } else {
+        var sig = hmacsha1.b64(signing_key, sigbase_str);
+    }
     this.degug_print('sig: ' + sig);
 
     var oauth_head  = '        OAuth oauth_consumer_key="'    + RFC3986_encode(this.consumer_key) + '",\n' 

====2017/07/30追記 ここまで====

====2017/08/03削除 ここまで====

 

また、twitterにアクセスするにはアカウントのほか、4つのキーを取得する必要があります。
(Consumer key、Consumer secret、Access Token、Access Token Secret)
自分で手順書くのが面倒なので、先人の成果をパクり、、いやいや参照させて頂くことにします。
ここの手順に従ってキーを取得してください。

TwitterのAPIを使用するために必要なキーを取得する手順 - Hello API

これらのキー(特にsecretと付く方)はパスワードみたいなものなので、取り扱いには十分注意しましょう。
普段使っているアカウントでいきなり変なtweetをすると、フォロワーがびっくりするので、別のアカウントを用意するのが良いかもしれません。

 

 

まずはtweetしてみます。
以下のプログラムを実行してみましょう。

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'));
    // エラー時はdata.errors.code data.errors.message に情報が入る
    console.log("%%%%%%%%%%%%%%%%%%%%%%%%%");
});
tw.on("end", function() {
    console.log("%%%% END %%%%");
});

// tweetする
var message = "test tweet";
var param   = {"trim_user":true,"include_entities":false};
tw.tweet(message, param);

 

成功すれば、「test tweet《改行》(Thu Jul 24 2017 12:29:46 GMT+0900)」のようにtweetされるはずです。

もちろん、ESP32がインターネットにアクセスできるWi-Fiルータにつながってなければ、失敗します。
もし、時刻があってないと(そんなに厳密でなくてもかまいません。何時間とか何日レベルでずれている場合)は、エラーになりますので、時刻合わせを行っておいてください。
tweetするメッセージに時刻を追加するようにしてあります。これは同じメッセージを短い時間内にtweetすると「それ、さっき呟いたやんけ~」とエラーになるため、それを回避するためにtweet処理の中で時刻を付加しています。

調子に乗って何回もtweetしてると、アカウントをロックされることがありますので、注意してください。

 

以下処理の説明です。

ESP32の場合はWi-Fiに接続します。
接続状態を維持しているならここはなくても構いません。前に書いたMyWifi.jsを使用しています。
ESP32上のEspruinoだと、「ESP32」というbuilt-in moduleが存在するので、それで判断しています。

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

 

 Espruinoの場合はタイムゾーンを設定します。
Espruinoだと、「E」というbuilt-in moduleが存在するので、それで判断しています。
ここはLinux版Espruinoの場合も実行されます。
Espruinoでしか使わないならいきなりタイムゾーン設定でも構いません。

if (typeof(E) ==='function') {
    // platform is espruino
    // set time zone  fixed to 'JST'
    E.setTimeZone(9);
}

 なぜ、こんなコードを入れているのか?
いい質問ですねぇ~。
このプログラム、実はnode.jsでも動くんです。
デバッグしやすいので、最初node.jsでデバッグしてた名残です。
せっかくなので、残しておきました。
node.js⇔Linux版Espruinoを行き来しながらデバッグして、最後にESP32で動作確認、な感じでデバッグしてました

 

 モジュールを読み込みます。
これをしないと始まりません。

var tiny_twitter = require("tiny_twitter");

 

 tiny_twitterインスタンスを生成します。
パラメータの最初の4つは↑で取得したキーです。最後のパラメータはモジュール内部のdegug_print (あ、typoだ。めんどいからそのままで)を表示するか否かを指定しています。
色々表示されてうっとうしい場合はfalseにしてください。

var tw = new tiny_twitter(consumer_key, consumer_secret, access_token, access_secret, true);

 

 サーバに接続されたときのイベントハンドラです。
特に処理はないので、接続した旨表示しているだけです。

tw.on("connect", function() {
    console.log("%%%% CONNECTED %%%%");
});

 

 受信データのうち、ヘッダ部分を受信したときのイベントハンドラです。
codeが200以外のときは、接続エラーなので、エラーと表示しています。
また、デバッグ用にヘッダ全体を表示しています。

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%%%%%%%%%%%%%%%%%%%%%%%%%");
});

 

 受信データのうち、データの中身を受け取ったときのイベントハンドラです。
データはJSON形式で送られてくるので、JSON.stringifyで文字列化して表示しています。

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 %%%%");
});

 

 実際にtweetする部分です。
paramは APIリファレンス を参照してください。指定しても動くかどうかわかりませんが。。。
この設定だと、受信するデータがちょっと小さくなります。

var message = "test tweet";
var param   = {"trim_user":true,"include_entities":false};
tw.tweet(message, param);

 

 今回はここまで。

 

次回に続く。。。