mitolab's diary

東南アジアで頑張って生きてる人のブログ

目的と手段についてのマインドセット

久々のポストです。とりあえずoutputしてこって思ったんで、書いてみます。

今、ベトナムの農業プロジェクトが一旦落ち着いたところで、次の動きの仕込みをしてる段階で、いったら節目なんですけど。こういう時によく思うのが、コレ。

「方法にこだわることを辞める」

ということ。別の言い方をすると、「他にどんな方法があるか探してみる」とも言えます。

きっかけ

そう思えるようになったきっかけとしては、新卒で入った職場を辞める時でした。正直辞めたいって思うことは何度かありましたが、その度に会社に受けた恩を返さなくては、と思いなかなか行動に踏み切れませんでした。が、ある時「恩を返すつっても色んな形があるよね」って気づけた事が、辞めることを決心する最後のひと押しとなりました。

実際、会社辞めてフリーランスになって、複数のお客さんとおつきあいさせてもらう中で、経営者にも色んなタイプがいて、ミッションへのアプローチの仕方や、文化、それに集まる社員も違うから当然プロジェクトの進め方も違うし、戦略も違うし、etc…という当たり前のことを身をもって知ることができました。そのおかげで、あーこれは自分にも取り入れられるかもとか、自分ならこういう会社を作りたいとか考えを整理するきっかけになりました。

そういう経験をしたことで、今は、目的が1つあったとしても、そこに至るまでの過程が本当に1つしかないのか、他にあるとすればどういう方法か、それは今の自分に妥当か、と問い直すようになりました。もっというと、その目的は本当に正しいのか?みたいなことも時には考えます。で、実をいうと節目だけではなくて、苦しい時とか、逃げたい時にも良く考えます(笑)。でも、それは間違ってないと自分は思っています。そこで吟味して、自分なりの最善解を出すことが大事なのであって、それ自体は寧ろ良いことじゃないかなと。

初志貫徹、すごい良い言葉だなと思うんですが、見直すことを怠って逆に自分の可能性を狭めてしまったり、苦しい生き方を何年もしてしまうのはもったいないです。

Pros & Cons

こだわることを辞めるメリットは、

  • 1つの事に対して複数の観点をもつことができる
  • 同時並行することでリスク分散できる
  • 比較的短い時間でトライ&エラーできる

ことです。デメリットは、

  • 周りに何してるか理解されにくい(かも)
  • こだわった時の世界線は経験できない

ってことくらいかな?

注意点

注意点としては、自分の中で正しく目的が設定されているか確認し、その精度を上げることが大事なんだと思います。そこがブレなければ、いくらでも方向転換していいと思いますが、そこが何度も変わるようだと、自分でも自分が何してるのかわからなくなって来る可能性がありますし、色々手をつけすぎて、結局1つも達成できなかった、みたいなことになってしまう危険性もあります。

あと、これは生き方の問題で、環境や能力や性格も人それぞれなので、万人に当てはまるものではないと思います。

まとめ

まとめると、成し遂げたい目的を正しく設定し、それに向かって色んな方法を同時並行、または短いスパンで複数試してみるっていうマインドセットもあるよっていうご紹介でした。

ベトナムで農業を初めて約2ヶ月たっての近況と課題感

10月後半から昨日までおよそ2ヶ月にわたる農場整備がようやく終わった...。荒れ地の草刈りから始めて耕耘、土壌分析、客土、施肥、土中発酵、潅水配管設置、小屋建てx2、各種資材調達、育苗、各種データ取り、関連各所との渉外、播種/定植、etc...本当に大変だった。言葉通じない且つ使える資材も限られる、且つ農業1年生ということで、かなりシビアな状況の中、農家の先輩たちからの指導や、行動力のあるリーダーのおかげでなんとかこなせてよかったとホッと一安心。

でも撒いた種が発芽するまで、定植した苗が順調に育つのを見るまでは油断できない。てかこれからも色々な病気や虫、雑草、天候色々な敵が待ち構えているのでそもそも油断はできないんだけど...。とりあえず振り返ってつらつらと書いてみる。

before f:id:mitolab:20161220015025j:plain

after f:id:mitolab:20161220015106j:plain

before f:id:mitolab:20161220015357j:plain

after f:id:mitolab:20161220015430j:plain

新設の小屋(倉庫, 作物調整場, 堆肥場を兼ねる) f:id:mitolab:20161220015606j:plain

新設の堆肥場(エアレーション装置はまた別途作製予定) f:id:mitolab:20161220015609j:plain

堆肥に使う廃菌床 f:id:mitolab:20161220015612j:plain

新設のポンプ小屋と水質浄化タンク f:id:mitolab:20161220015615j:plain

先輩に苦労して作ってもらった配管 f:id:mitolab:20161220015618j:plain

この2ヶ月、日本が如何に恵まれているかを思い知ったなぁと。ほしい肥料も資材も機械も電話一本、メール一本、ボタン1つで手に入るし、ちょっと車を走らせれば大型ショッピングセンターで必要なものは大抵手に入る。しかもどの道具も洗練されてる。

ベトナム社会主義国なためかわからないけど、見事に業種が分けられていて、大型DIYショップみたいなのが無い。ホーチミンはまだいいと思うけど、北部はまだまだ...。特に私が今いるハナム省は、首都であり北部の中心都市であるハノイから車で1時間の地方都市。そこまで田舎ではないけど、便利ではないし、農業が盛んといえるほど資材が充実していない。ビニール系はこの店、工具系はこの店、配管はこの店、っていうふうに1軒1軒まわらないといけないし、在庫もクオリティも店によって違う。少しでもいい店安い店を見つけるのが本当に大変。

クオリティに関してもう少し言うと、ココ(ハナム省)の資材はホント最低限。じょうろなんて、釘で穴空けたの?っていうくらいにドボドボと水が出て来る。これじゃあ植物体に物理攻撃しかけてるようなもんだし、ハンマーなんかも楔(くさび)がついてないので、ヘッドの部分が打っている時にすっぽぬけたりするというマヌケな自体もしばしば。クワとかスコップも同様、且つ柄の部分が適当に切られていて重い。全然洗練されてない。そもそも使う人のことを考えられてない。

播種機を使ったときなんて、ベトナム人は目が点になったように見つめてて、「これいいなぁ俺にも貸してくれ」って顔してたし実際に言われた。ベトナムの農家は手で条蒔きや点播するスタイルなので、メジャーで間隔を確認しながら中腰を維持しなきゃいけない。キレイにまこうとおもうと1時間も2時間もかかってしまう。それが日本の機材を使えば間隔もギアの設定を変えるだけで自由自在だし、普通に立ったまま機材を土の上でころがすだけで10分もかからないという、歴然たる差。

他にも手袋なんかも現地の人は使わないので手は荒れ放題。長靴は流石にあるけど、日本みたく高機能じゃない最低限のもの。

土作りの資材に関しても、できあいの良質な培土なんか無いし、良質な堆肥を販売する肉牛屋や酪農屋もいない(探せていないだけかもしれない)。ミネラル資材なんかも、かなり苦労して探してホーチミンから取り寄せた。が、石灰なんかは良質なものが手に入らなかった。

ということで、ベトナムの、殊に自分らの周辺地域において農業をする上では、道具や資材や機材を充実させることが先決のように感じた。

私も1年前までは四六時中スマフォアプリ開発に携わっていたので、農業xIoTだのスマート農業だのは興味がある。前職で培った技術を活かしたい、早く何か作りたい。そういう気持ちはあるんだけど、上記のような、現場において感じる課題をいくつも見出して、それをどう解決していけばいいのか、どうしたらビジネスにすることができるのか、それぞれのピースを集めてはくっつけてを繰り返して進めていければと、思った。

ちょっと余談。日本でも欧米でもよくagTechとかスマート農業とか言って騒がれるけども、ベトナムを含む東南アジアにおいては、そういう言葉が使われる場面が違うなーと思う。日本なんかはドローンで農場管理とか収穫ロボとか、環境制御ハウス〜とかいってて既に普通に作物が作れる上での省コスト化をどう進めるか、みたいな場面で良く使われる印象。一方で、東南アジアはそもそもどうやったらいい作物を作れるの、とかどうやったら貧しい農家を救えるの、みたいな場面で使われる印象。農機無いのでレンタルしあいましょうっていうサービスとか、農家用のクラウドファンディングサービスとか。

後者は、今この時代だからこそ出来る発想で、とてもおもしろいなーと思う。なんというか、日本を含め先進国が積み重ねてきた苦労を踏み台にして、サクッと飛び越えていくような、超右肩上がりに成長するんじゃないかっていうワクワク感がある。こういうズルいITの使い方こそが、東南アジアの発展を加速させ、世界をより良い方向に導くんだろうなと期待してしまう。UberとかGrab Taxiしかり。日本のいわゆる失われた20年で10代20代を過ごした自分としては、そういうワクワク感を体験してみたいって気持ちがあるんだろうな〜(なぜか80年代の歌謡曲も大好きだし)。だから今自分はベトナムなんぞにいるんだろなーと思ったり。

以上、明日も元気にがむばります。

『畳み込みニューラルネットワークによるテキスト分類を TensorFlow で実装する · けんごのお屋敷』を理解するための前知識

ちょっと機械学習してみよう、って思って勉強してたら自分がいまどこに居るのかわかりかねてきたので(汗)、頭の整理のためにこれまでの学習の軌跡をまとめてみます。実際には掲題の記事を理解するためのリンク集みたくなりましたので予めご了承ください。

目標

自然言語における5W1H(誰が、いつ、どこで、何を、なぜ、どのように)を、機械学習を用いて分類する。

上記はmecab-pythonだけで出来るんや...(しかもオフラインで!スゲェ!)ということで、、マヌケながら実際はこの前段(or後段)で文章のカテゴリ分類をする必要がありそうなので、その部分で機械学習を取り入れることを目標とします。

動機

とあるアプリにそういう機能をつけたく。

筆者の数学的知識

数学は高校2年まで。偏微分や行列などは独学で学び、わからなければ都度調べる形。

機械学習って?

機械学習(きかいがくしゅう、英: machine learning)とは、人工知能における研究課題の一つで、人間が自然に行っている学習能力と同様の機能をコンピュータで実現しようとする技術・手法のことである。

機械学習の目的は、訓練データから学んだ「既知」の特徴に基づく予測である。

via 機械学習 - Wikipedia

目標達成のためのマイルストーン

TensorFlowを使えばなんとかなるんじゃね?という安易な考えからスタート。「TensorFlow 自然言語処理」でググってよさげだなと思ったサイトが以下。まずはこの記事の理解のために学習する方針とした。

畳み込みニューラルネットワークによるテキスト分類を TensorFlow で実装する · けんごのお屋敷

道筋

上記記事中に、対象とする読者としてこう書いてあった:

ので、10年も前になぜか購入していた以下の本を読んでニューラルネットワークについてまずは復習。

学習とニューラルネットワーク (電子情報通信工学シリーズ)

中古価格
¥1,543から
(2016/9/4 13:24時点)

基本的なニューラルネットワークの考え方、勾配法、誤差逆伝播法(バックプロパゲーション法)、シグモイド関数などの理解に役立った。7章の途中くらいからボルツマンマシンの話になり、めんどくさそうだなと思って読んでない。それでも、この本を読んでから上記WEB記事を見ると理解度は前よりは上がった。それでもわからない単語が出てきたので都度調べた(以下)。

畳み込みニューラルネットワーク(CNN)

自然言語処理における畳み込みニューラルネットワークを理解する · けんごのお屋敷

画像認識における例から、それを自然言語処理(NLP)にどう適用するか、の説明がなされていてイメージしやすかった。

word2vec

これについてはなんとなくイメージはつかめる程度。以下で理解しようと試み中。

Word2Vec のニューラルネットワーク学習過程を理解する · けんごのお屋敷

Vector Representations of Words

enakai00.hatenablog.com

qiita.com

qiita.com

MNIST For ML Beginners

neuralnet.hatenablog.jp

MNIST For ML Beginnersで実行していることは何なのか、softmaxはシグモイド関数の多変量版だとかのくだりが非常に理解しやすかった。また、関連する交差エントロピーについても以下の記事で理解が進んだ。

neuralnet.hatenablog.jp

過学習

ここがよさ気だけどまだ読んでない。

tjo.hatenablog.com

活性化関数

活性化関数 - Wikipedia

ということで

今後も理解を深めつついい加減コードを書いていけるようにしないと。

Hugo、github Pages、wovn.io、ムームードメインを使って楽に短時間でプロフィールページを作る!

最近、初対面の方にお会いすることが多くなってきたので、先日webサービスとアプリを使ってオシャレな名刺を作ってみました*1

で、この際プロフィールページフリーランス時代のものだったので、現状に即した内容にアップデートをしてみました。

できたもの

f:id:mitolab:20160812131646p:plain mitolab

  • 1枚だけのプロフィールページ
  • PC/スマフォ両対応
  • google analyticsでトラッキング可能
  • メールフォーム利用可能
  • ブログへの拡張性もある
  • 日本語/英語両対応

短時間でこれだけのものが、ドメイン代だけでまかなえます。

プロフィールページ作成に使うもの

  1. Hugo... 静的サイト生成ツール
  2. Github Pages... 静的サイトを公開できるgithubのサービス
  3. ドメイン... ムームードメインで取得
  4. wovn.io... htmlに一行挿入するだけ簡単ローカライズサービス

作成手順

基本的な手順は、

Hugo + GitHub Pagesでブログを作る

の記事を参照しつつ、ドメイン設定に関しては、

GitHub Pagesで静的なサイトを公開し、独自ドメインを設定する

こちらの記事を参照しながら進めました。

最後に、wovn.ioを使って英語と日本語を切り替えられるようにしました。

Hugoテンプレート適用

Hugoのいいところは、多数のフリーテンプレートを用意していること。しかも結構シンプルでオシャレなものが多い印象です。

f:id:mitolab:20160812133009p:plain http://themes.gohugo.io/

多分、テンプレを探すのに一番時間を費やしました...。最終的に決めたものがこちら。

f:id:mitolab:20160812133119p:plain Hugo Theme: Strata

1枚で完結して、且つスマフォ/PC両対応だったのでこれにしました。あとこれは別に選定基準ではなかったんですが、google analyticsのトラッキングコードを設定出来るようになっていたり、メールフォームもすぐ使えるようにしていたりで、かゆいところに手が届くテンプレで素晴らしいです。背景画像くらいは変えたほうがいいかもしれないけどそのまんま使ってます...。

あと、左下のアイコンを出す出さないとか、右カラムの画像類を出す出さないとかは全てconfig.tomlで設定できて便利です。

注意点として、今回は1枚だけのページを作りたかったので、上記参照した手順記事記事の枠を作ってみるから記事を書いてみるまでは飛ばして、テンプレに付属のexampleSiteに入っている、config.tomlhugo new site <site-name>した際のトップディレクトリに配置(デフォのやつを上書き)して、その中身をいじってあげればOKです。

あと、テンプレに付属のメールフォームは、formspree.ioというプロキシサービスを使っていて、使う場合はサイトをgithubにpushして、ドメインも適用してから、実際にフォームから自分宛にメールを送信して、来たメールでconfirmするだけでフォームが利用可能になります。月に1000通までは無料らしいので余裕で足りると思います。

Github Pages

基本的には、

  • githubリポジトリを作る
  • gh-pagesというブランチを作る
  • 上記ブランチにpushする

という作業だけで、http://[ユーザ名].github.io/[リポジトリ名]というurlにページを公開できます。それか、[ユーザ名].github.ioというリポジトリを作ることでも同様のことが出来るようで、2通りのやり方があるみたいです。今回は前者のやり方でやってみました。

ドメイン設定

ムームードメインでの作業と、Github Pagesでの作業にわかれます。

ムームードメインでは既にドメインを取得済だったので、DNSのAレコードを変更/追加してあげました。加えて、tumblrでCNAMEレコードを使っていたんですが不要なので消しました。

GithubPagesでは、リポジトリのSettingsからCustom Domainを設定してあげると、自動的にリポジトリにCNAMEファイルができます。それで、qiita記事のこちらの手順と同等の手順となります。

f:id:mitolab:20160812134456p:plain

ローカライズ

wovn.ioを使うと簡単にローカライズできました。画面もシンプルなのでいじってみれば使い方は理解できると思います。手順も公式で用意されています。

ただ1つわかりにくかったのが、htmlに挿入する1文が見つけにくいこと。上記手順では、ダッシュボードがブランクの際のページに1文が書いてあるのですが、一度ページを登録してしまうと、その1文がどこかに消えていなくなってしまい、色々ボタンを探してみないとわからないという状態になってしまいました。

最終的には、右上のドロップダウンにフォーカスして、アカウント > コードスニペット を選択すると1文が表示されます。

<script src="//j.wovn.io/1" data-wovnio="key=xxxxx" async></script>

こういうやつです。

まとめ

以上です。簡単に多機能なページが作れてしまうのでオススメです。今回は静的ページ生成サービス探しやテンプレ探しに時間がかかりましたが、既にテンプレも決まっていてドメインも取れている状態であれば、1時間では終わりそうなボリュームかと思います。

では、何かの参考になれば幸いです。

aws serverlessでfacebook messenger botを試してみた

前回のポストから時間がだいぶ空いてしまった...反省。やったことと言えば件名にあることくらいです。まだ中途半端ですが忘れてしまうのでとりあえずメモします。

作ろうと思っているもの

今学んでいるBLOF理論や植物生理、微生物、土の性質、etc...農作物の生産に関するQ&A botができれば便利かなぁと思って着手し始めました。

想定する使い方はいたってシンプルで、

  1. 質問をメッセンジャーに音声で質問する(農作業中テキストを打つとかめんどくさくてしないので)
  2. botがその答えを返してくれる

というもの。


ゆくゆくは個別の圃場情報を予めinputしておいて、例えば「A圃場に必要な肥料は?」とか聞くと、「はい、次の施肥をしてください:① バーク堆肥を250kg、アミノ酸肥料を10kg、鉄肥料を2kg、マンガン肥料を1kg を混ぜて施肥してください ② 酵母菌を30g、砂糖を400g、水を5Lを混ぜて施肥してください、③ 1,2完了後、透明マルチを被せて3日間養生してください」とかそういう答えが返ってくるようなものができれば便利だなぁと思ったりします。つまりは圃場メンテナンスにかけるルーチンプロセスを少しでも省略化することができれば便利だなぁと。


利用サービス

作り方

qiita.com

developers.facebook.com

http://docs.serverless.com/v0.5.0/docsdocs.serverless.com

※ wit.aiについては一端スルー(理由は以下)

現状

頭悪くてwit.aiの使い方/メリットがいまいち理解できず...モチベーションが下がり気味です。"音声認識"がついていること以外、単純にスプレッドシートにキーワードとそのキーワードが含まれていた場合の回答を用意しておくのと何が違うのかイマイチ理解出来ていません...。あと自分がバカなんだとおもいますがwit.ai上の単語の意図するところやインタフェースがわかりにくくてイマイチ手が進まないという。

なので、現状はmessengerでテキストを入力するとオウム返しするbotといういたっておもしろみのないサンプルで止まっています。

f:id:mitolab:20160710154847p:plain

作る上での方針

今回利用するツールはどれも新しい技術らしく、公式ドキュメント、qiita記事などの第三者情報、どちらか一方にしか無い情報があるということがネットサーフィンでわかりました。ので、「ベースの手順は公式ドキュメントを優先し、詰まったところを第三者情報に頼る」という至ってまっとうな形で進めました。

作る上でのメモ

以下は、今後同様のことをするときのために、わかりにくかった点をメモしておきます。

iamロールの設定が必要ですよ

serverlessを導入するにあたって、公式ドキュメントにあるように、"Configuring AWS"から設定しておきましょう。serverlessのプロジェクトを作る前に設定しておかないと、_meta/variables/s-variables-dev-{region名}.jsoniamRoleArnLambdaに適切なキーがアサインされず、handler.jsの実行時にエラーになりますので要注意です。

aws console iamでこんな感じになっていればOK

f:id:mitolab:20160710152220p:plain

iamロールについては、以下が分かりやすかったです。

dev.classmethod.jp

Serverless Optimizer Pluginを入れないと無理

lambdaにUPするコード(ここではhandler.js)にrequireがある場合は、browserifyしてrequire先のコードも1つのファイルにまとめるプラグインが無いと無理でした。

github.com

※ これは前述のqiita記事を読まないとわからなかったです。

API Gatewayからserverlessへのパラメータの受け渡しはどうする?

本来は、s-templates.jsonなるものを作って、任意のendpointに適用していく形のようですが、まどろっこしかったので、qiitaのサンプルのやり方を踏襲してs-function.json内で書けば動いたのでそれでいきました。

{
  "name": "facebook",
  "runtime": "nodejs4.3",
  "description": "Serverless Lambda function for project: FBBot",
  "customName": false,
  "customRole": false,
  "handler": "handler.handler",
  "timeout": 6,
  "memorySize": 1024,
  "authorizer": {},
  "custom": {
    "excludePatterns": [],
    "optimize": {
      "exclude": ["aws-sdk"],
      "transforms": [
        {
          "name": "babelify",
          "opts": {
            "presets": ["es2015"]
          }
        }
      ]
    } 
  },
  "endpoints": [
    {
      "path": "facebook",
      "method": "GET",
      "type": "AWS",
      "authorizationType": "none",
      "authorizerFunction": false,
      "apiKeyRequired": false,
      "requestParameters": {
        "integration.request.querystring.hub.verify_token": "method.request.querystring.hub.verify_token",
    "integration.request.querystring.hub.challenge": "method.request.querystring.hub.challenge",
    "integration.request.querystring.hub.mode": "method.request.querystring.hub.mode"
      },
      "requestTemplates": {
        "application/json": {
          "verify_token": "$input.params('hub.verify_token')",
          "challenge": "$input.params('hub.challenge')",
      "mode": "$input.params('hub.mode')",
          "method": "$context.httpMethod"
        }
      },
      "responses": {
        "400": {
          "statusCode": "400"
        },
        "default": {
          "statusCode": "200",
          "responseParameters": {},
          "responseModels": {
            "application/json;charset=UTF-8": "Empty"
          },
          "responseTemplates": {
        "text/plain": "$input.path('$')"    
          }
        }
      }
    },
    {
      "path": "facebook",
      "method": "POST",
      "type": "AWS",
      "authorizationType": "none",
      "authorizerFunction": false,
      "apiKeyRequired": false,
      "requestParameters": {},
      "requestTemplates": {
        "application/json": {
          "entry": "$input.json('entry')",
          "method": "$context.httpMethod"
        }
      },
      "responses": {
        "400": {
          "statusCode": "400"
        },
        "default": {
          "statusCode": "200",
          "responseParameters": {},
          "responseModels": {
            "application/json;charset=UTF-8": "Empty"
          },
          "responseTemplates": {
            "text/plain": "$input.path('$')"
          }
        }
      }
    }
  ],
  "events": [],
  "environment": {
    "SERVERLESS_PROJECT": "${project}",
    "SERVERLESS_STAGE": "${stage}",
    "SERVERLESS_REGION": "${region}"
  },
  "vpc": {
    "securityGroupIds": [],
    "subnetIds": []
  }
}

参考:

http://docs.serverless.com/docs/templates-variablesdocs.serverless.com

docs.aws.amazon.com

handler.jsはこんな感じ

'use strict';

const request = require('request');

const FB_MESSANGER_TOKEN = 'xxxxxx';

module.exports.handler = function(event, context, cb) {
  switch (event.method.toUpperCase()) {
    case 'GET': {
      if (event.mode === 'subscribe' && event.verify_token === FB_MESSANGER_TOKEN) {
        const validRequest = event.verify_token;
        return cb(null, validRequest ? event.challenge : 'Error, wrong validation token');
      }
    }
    case 'POST': {
      event.entry.forEach(function(pageEntry) {
        pageEntry.messaging.forEach(function(messagingEvent) {
      if (messagingEvent.message) {
        receivedMessage(messagingEvent);
      }
        });
      });
      return cb(null, 'OK');
    }
    default: return cb('Error, Invalid Method');
  } 
};

function receivedMessage(event) {
  var senderID = event.sender.id;
  var recipientID = event.recipient.id;
  var timeOfMessage = event.timestamp;
  var message = event.message; 

  console.log("Received message for user %d and page %d at %d with message:",senderID, recipientID, timeOfMessage);
  console.log(JSON.stringify(message));
  
  var messageId = message.mid;
  
  // You may get a text or attachment but not both
  var messageText = message.text;
  var messageAttachments = message.attachments;

  if (messageText) {
    sendTextMessage(senderID, messageText); 
  } else if (messageAttachments) {
    sendTextMessage(senderID, "Message with attachment received");
  }
}

function sendTextMessage(recipientId, messageText) {
  var messageData = {
    recipient: {
      id: recipientId
    },
    message: {
      text: messageText
    }
  };

  callSendAPI(messageData);
}

function callSendAPI(messageData) {
  request({
    uri: 'https://graph.facebook.com/v2.6/me/messages',
    qs: { access_token: FB_MESSANGER_TOKEN },
    method: 'POST',
    json: messageData

  }, function (error, response, body) {
    if (!error && response.statusCode == 200) {
      var recipientId = body.recipient_id;
      var messageId = body.message_id;

      console.log("Successfully sent generic message with id %s to recipient %s", messageId, recipientId);
    } else {
      console.error("Unable to send message.");
      console.error(response);
      console.error(error);
    }
  });  
}

誰でもbotにアクセスできるわけではない

ここまでの手順で、botサービスを一般公開できるわけではありません。一般公開するには、facebookの審査に通る必要があります。

じゃあどうやって審査に出せばいいの?というと恐らく以下のようになるかと思います。ただし実際に試したわけではないのであくまで推測になります。

  1. facebook developerの当該アプリのダッシュボードにて、左側のサイドバーからmessengerを選択し、スクショの1,2のボタンを押して申請します。

f:id:mitolab:20160710152840p:plain

  1. 左側のサイドバーからアプリレビューを選択し、page_messagingの項目でノートを編集ボタンを押します。

f:id:mitolab:20160710153411p:plain

  1. さらにその先で、プラットフォームポリシーに準拠しているかどうかの確認と、使い方のスクリーンキャストの提出を求められるので、それらを入力します。

f:id:mitolab:20160710153741p:plain

  1. 承認されれば、晴れて一般公開となると思われます。

botを誰かに試して欲しい場合はテスターとして追加する

f:id:mitolab:20160710152447p:plain

画像のように、テスターとして役割に追加してあげれば、botを試してもらうことができます。

感想

今回はとりあえず、serverlessを使ってmessengerでテキストを入力するとオウム返しするbotを作りました。感想としては、おもったよりレスポンスが遅いなー(0.5秒くらいな感覚)と思いました。handler.jsの中身の処理がかさむと恐らくもっと重くなると思われます。

wit.aiは音声認識が付いているので使いたいですが、概念を理解するのに人より多く時間を割かないといけなさそうでだるいなーというところです。

ということで、引き続き触っていきます。

ラズベリーパイ3で土壌湿度センサーを試してみました

今日はこちらの記事を参考に土壌湿度センサーを試してみました。

dev.classmethod.jp

今後はnodeで色々やりたかったので、本記事はドンピシャでした。

実験の目的

最終的には、葉物(特にコマツナ)を作るにあたっての最適な潅水タイミングを見極めたい、ので、とりあえずデータをとってみたい。

結果

結果からいうと記事の通りやったらこんなかんじで何の問題もなくデータがとれました*1

f:id:mitolab:20160529163745j:plain

f:id:mitolab:20160529163800j:plain

基本、参照元の記事の手順まんまでいけるのですが、多少僕の環境との相違点とか、補足があるのでそこだけ書いておきます。

参照記事との相違点

  • ラズベリーパイsudo raspi-configコマンドからAdvanced OptionsにてSPIの機能を有効化しました
  • 前回、nodebrewで最新のnodeを入れたので、"Node.js のインストール"は割愛しました
  • "npm モジュールのインストール"の前にサンプル用ディレクトリを作成ました
  • npm の引数 -S は--saveと同意で、package.jsonのdependenciesに追加されるので、別途package.jsonを作っておく必要があります(作り方はこちらの記事に)
  • nodeコマンドがsudoで実行できなかったので、nodebrewがインストールした場所(which nodeで特定)からシンボリックリンクを貼って対応しました(参考)

参照記事の補足

ピン名対応表

記事中Fritzingで書かれた図面を見れば、配線はできますが、ADコンバータとラズパイ上のピンの対応関係が把握しずらかったのでここで少し補足します。

土壌湿度センサー 結線 MCP3208-CI/P 結線 ラズベリーパイ3
青:
湿度出力(アナログ電圧出力: 0~4.2v(@5v))
- Pin1:
CH0
赤:
電源入力(DC3.3~5v)
- - Pin2:
5v Power
黒:
GND
- Pin14:
AGND*2
- Pin6:
Ground
Pin16:
ADO*3
- Pin1:
3.3v Power
Pin13:
CLK
- Pin23:
SPI0 SCLK
Pin12:
Dout
- Pin21:
SPI0 MISO
Pin11:
Din
- Pin19:
SPI0 MOSI
Pin10:
CS/SHDN
- Pin24:
SPI0 CE0

※ 結線に"-"(ハイフン)が入っているものは結線します。MCP3208-CI/Pを飛ばして結線しているものもあります。

※ MCP3208-CI/PのPin10は、LOWにするとADCがONの状態になります。ADCを使わない場合はHIGHにしてて待機状態にする必要があります。

出力される数値の対応

土壌湿度センサーの開発元wikiページ)をみると、

0 ~300 : dry soil
300~700 : humid soil
700~950

とありました。これはArduinoに繋いだ場合の値で、見たところ上限が10bit(0~1023)ぽいです。今回のADCは12bit仕様なので、分解能は0~4095になります。これを直線的に変換するとすれば、

出力値 状態
0~1292 乾いている
1292~3017 湿っている
3017~4095 湿りすぎ

というふうになるかとおもいます。

通信方式について参考

今回使ったSPI通信、前回のI2C通信に関してはこちらが参考になるかと思います: I2CとSPI

感想

センサー自体が"プリント基板を切り出しました" みたいな作りだったことや、ウルトラ簡単な回路ということもあったりで実用性はどうなんだろう...というところです。色々他も調べてみたほうがいいかもしれません。

また、pFメーター(テンシオメーター)とはちがって、植物の根と土壌間の水分浸透圧を加味することはできないので、その辺の相関関係を調べないと、根が水分を吸収するのに最適な潅水時期を検出することはできないかなぁと思いました。その辺は、東大の難しめな資料が参考になるかもしれません。

あと、良く硝酸態チッソの量を推測するのに使われるEC(電気伝導率)とは仕組みとしてはどう違うのだろうと疑問に思いました。

ということで、かなり簡易的なデバイスですがデータは取るだけとってみて考えようと思います。

*1:ハウツーを参照させていただいたクラスメソッドさんありがとうございます

*2:Pin9:DGND と直結

*3:Pin13:AREF と直結

ラズベリーパイ3にnodejsをインストール

前回のセンサの動作確認pythonでやったんですが、今後はpythonじゃなくてnodejsで色々やりたいので、とりあえず環境を整えます。

既存のnodejsをアンインストール

# apt-getでインストール済のパッケージを確認
dpkg -l | grep node

# nodejs, nodejs(legacy), nodered が入ってたのでそれぞれアンインストール [参照](http://kawatama.net/web/296)
sudo apt-get --purge remove nodejs
sudo apt-get --purge remove nodered

# 一応ちゃんと削除されたか確認
dpkg -l | grep node
sudo find / -name node

# proc/xx/node ってファイルが大量にあったけど問題なさそうなので続行

nodebrewをインストール

# nodebrew(nodeのバージョン管理)をインストール
curl -L git.io/nodebrew | perl - setup

# nodebrewのパスを通す
vim ~/.bashrc
export PATH=$HOME/.nodebrew/current/bin:$PATH
source ~/.bashrc

# nodebrewが有効になったか確認
nodebrew -v

# nodebrewでnodejsのバイナリ安定版をインストール(もし無ければbinaryを外してみる。ちなみにバイナリじゃない場合はソース落としてコンパイルするのでクソ時間かかります要注意)
nodebrew install-binary stable

# lsして出てきたものをuse
nodebrew ls
nodebrew use v6.2.0

# 上記versionが出てきたら成功
node -v

とりあえずここまで。