WindowsだけでAmazon DashボタンのMACアドレスを取得できるjsを書いた
こんばんは。先日、保育園から習い事の教室に向かう際、以前、習い事の教室のトイレが故障しており、難儀したことがあり、かなり強く長男に、保育園で事前にトイレに行っておけと言ったのをすっかり忘れてましたが、長男はちゃんとそれを実践しており、感心した@kjunichiです。
背景
LinuxやMacだと、npmモジュールのnode-dash-buttonに付属のfindbuttonで Amazon DashボタンのMACアドレスが簡単に取得できる。
しかし、Windowsだと、このモジュールがWindowsに対応していないようで、 ビルドエラーとなり使えません。
代わりに当ブログでも何度か紹介しているwin-node-dash-button が使えるのですが、MACアドレスの検出のプログラムは付属していません。
MacやLinuxが使えない環境だとこのMACアドレスを取得するところでつまずいて残念なことになる。
http://tanbonomannaka.hatenablog.com/entry/2016/12/18/204217tanbonomannaka.hatenablog.com
なんて記事をたまたま見つけたから、ちょっと記事にしてみた。
つくった
パケットキャプチャー関連の知識がなかったので、勉強になった。 Cだとこの手のプログラムは面倒な印象を持っているが、Node.jsだと思った通り、わかりやすかった。 結局、win-node-dash-buttonのコードを少し手を入れるだけでよかった。
"use strict"; const Cap = require('cap').Cap, decoders = require('cap').decoders, _ = require("lodash"), Server = function() { const self = this, savedMacAddr={}, lastUpdate ="", cap = new Cap(), buffer = new Buffer(65536); this.packetReceived = (nbytes, trunc) => { const ret = decoders.Ethernet(buffer); if (ret.info.type === 2054) { // arp if(! savedMacAddr[ret.info.srcmac]) { console.log(ret.info.srcmac); savedMacAddr[ret.info.srcmac] = true; } } }; this.start = (ip) => { const device = Cap.findDevice(ip), linkType = cap.open(device, "", 10 * 1024 * 1024, buffer); try { cap.setMinBytes(0); } catch (e) { console.log(e); } cap.on("packet", self.packetReceived); process.on("SIGINT", self.stop); }; this.stop = () => { console.log("Shutting down"); cap.removeListener("packet", self.packetReceived); cap.close(); }; }; const srv = new Server(); srv.start('192.168.0.2'); // 192.168.0.2は動かすホストのIPアドレス
CapというnpmモジュールがUnix系だとlibpcapを使い、Windowsだと別途インストールしたwinpcapを同梱しており、利用することで
マルチプラットフォームでパケットキャプチャーを実現している。
自分のPCのIPアドレスもわからない場合
以下のような感じで、コンソールにIPアドレスを出力できたが、どんな環境でも動かくは不明。 osというNode.js標準モジュールで実装することで、環境依存を抑えたつもり。
const os = require('os'); nifs = os.networkInterfaces(); for(let nif in nifs) { if(nif.startsWith("Virtual")|| nif.startsWith("Loopback")) { continue; } //console.log(nif); for(let ad in nifs[nif]) { if(nifs[nif][ad].family == 'IPv4') { //console.log(nifs[nif][ad]); console.log(nifs[nif][ad].address); } } }
まとめ
- Windows環境だとnode-dash-buttonではなく、win-node-dash-buttonを使う。
- MACアドレスの取得は、win-node-dash-button付属のコードをちょっと変更するか、この記事の検出用のコードを利用する。
関連記事
- Heroku logからアクセス元のIPアドレスを抽出してみた
- Amazon dashボタンをWindowsで使うまで 完結編
- Windows 10でMSVCでnghttp2のサンプルを動かす
- Windowsでmruby-http2を動かした
- Windows 10でFirefoxをソースからビルドして動かしてみた
- たぶんGTK2をChocolateyのgtk-runtimeで入れても64ビット環境ではダメな件
- goroutineを使って高速にLAN内の*.localなホスト名の一覧を取得するツールを作った
7年前の記事
Node.jsとAmazon Dashボタンで鬼が来たボタンを作った
おはようございます。去年のこの時期から次男の便秘で小児科通ったりしてましたが、最近では定期的にうんちが出るようになりました。@kjunichiです。
背景
昨年末、自作PCを一新をきっかけにMacよりWindowsに触れる機会が多くなり、sayコマンドのWindows版が ないか調べていたら、Windowsでもいくつかの方法で似たようなものは作れることが分かりました。
Edge.jsでNode.jsからC#のコードを呼び出せることを知っていたので、これとWindows向けに使える win-node-dash-buttonを使ってやってみました。
今回はIOTで子育てを解決してみます(嘘)!
子供が夜なかなか寝ないを解決したい!
子供がよる遊んでなかなか寝ないので、ボタン一つで解決を目指します。
つくるもの
Dashボタンを押すと、「おにがきたぞー」とCortanaと音字声でパソコンに脅かしてもらいます。
Edge.jsからSystem.Speech.dllを参照させる
今回のポイントはここだけです。32ビットの話が多く64ビットだと、\Windows配下で検索して 見つかったdllがいくつか見つかり、この中から当たりを見つけて、.jsと同一のディレクトリに 置きます。
ほんとは、このEdge.jsのdll参照時のパスの設定方法を調べたかったのですが。。。
また、UWPでもやってみましたが、参照設定が必要なのか、使用したい名前空間のクラスが見つかりませんでした。
成果物
const Server = require('win-node-dash-button').Server const DashButton = require('win-node-dash-button').DashButton const edge = require('edge'); const hostIp = '192.168.0.123'; const dashButtonMAC = "88:71:e5:xx:xx:xx"; const say = edge.func(` #r "System.Speech.dll" using System.Speech.Synthesis; async (input) => { SpeechSynthesizer sz = new SpeechSynthesizer(); sz.Volume = 100; sz.Rate = -1; sz.Speak(input.ToString()); return ""; } `); const svr = new Server(), tide = new DashButton(dashButtonMAC, () => { say('おにがきたぞー、はやくねろ!', (error, result)=> { if (error) throw error; console.log(result); }); console.log("Tide pressed"); }); svr.register(tide) .start(hostIp);
まとめ
- IOTを駆使することで、子供たちをボタン一つで寝かしつけに成功した。(嘘です)
- Edge.jsすごいとは思っていたものの、適用箇所が思いつかなかったが、この記事で一例ができた。
参考資料
関連記事
- WindowsだけでAmazon DashボタンのMACアドレスを取得できるjsを書いた
- Amazon dashボタンをWindowsで使うまで 完結編
- Edge.jsで気になって、調べてわかったこと
- #2011aug_baby iPhoneに息子のアイコンを無料で敷き詰める
- #2011aug_baby 息子のきーぼーど練習ソフトをつくる
- #イクメン #2011aug_baby フーリエ記述子を息子のお絵かきソフトに
- 通知センターに子供の写真を表示する #OSX
12年前の記事
mrubyでWebカメラを黒い画面にそのまま表示できるようにした
おはようございます。切り替えの遅かった長男が最近ではすっかり、お気に入りのYoutubeを見ていても、お風呂の号令でさっと、お風呂に来るようになりました。しかし、次男の悪さが今度は目立ってしまってます。まぁ、長男もそうだったから、まぁ、いいかぁ。っとこれだから次男は。。。@kjunichiです。
背景
長編まとめ・Sixel Graphics復活への動き(1) - Togetter
libsixelの使い方
// gcc `pkg-config libsixel --cflags --libs` main.c // ./a.out > test.sixel #include <stdio.h> #include <stdlib.h> #include <sixel.h> static int sixel_write(char *data, int size, void *priv) { return fwrite(data, 1, size, (FILE *)priv); } static SIXELSTATUS output_sixel(unsigned char *pixbuf, int width, int height, int ncolors, int pixelformat) { sixel_output_t *context; sixel_dither_t *dither; SIXELSTATUS status; context = sixel_output_create(sixel_write, stdout); dither = sixel_dither_create(ncolors); status = sixel_dither_initialize(dither, pixbuf, width, height, pixelformat, SIXEL_LARGE_AUTO, SIXEL_REP_AUTO, SIXEL_QUALITY_AUTO); if (SIXEL_FAILED(status)) return status; status = sixel_encode(pixbuf, width, height, pixelformat, dither, context); if (SIXEL_FAILED(status)) return status; sixel_output_unref(context); sixel_dither_unref(dither); return status; } int main(int argc,char **argv) { SIXELSTATUS status; int WIDTH = 128; int HEIGHT = 128; unsigned char *pixbuf; pixbuf = malloc(sizeof(char)*WIDTH*HEIGHT*3); for(int h=0; h < HEIGHT; h++) { for(int w=0; w<WIDTH;w++) { int index = 3*(h*WIDTH+w); int v = (w*h)%255; pixbuf[index] = 0; pixbuf[index+1]=v; pixbuf[index+2]=0; } } status = output_sixel(pixbuf, WIDTH,HEIGHT,256,SIXEL_PIXELFORMAT_RGB888); if (SIXEL_FAILED(status)) { fprintf(stderr, "%s\n%s\n", sixel_helper_format_error(status), sixel_helper_get_additional_message()); return status; } printf("test\n"); }
画像サイズと、RGBの順にunsigned charが並んだ配列を渡せば、良きに計らってくれることが分かった。
mruby-webcamの対応
JPEG出力一択だったところをWebcam#setFmtメソッドを新設して、 "jpg","ppm"等のファイル拡張子による指定を可能として、 libsixelで処理し易い、ppm形式での出力を実装した。
実装と言っても、
imencode(".jpg", mat, buff, param);
と固定だった拡張子の指定を以下の様に可変にしただけ。
imencode(type.c_str(), mat, buff, param);
mruby-webcamでカメラの映像をppm形式で出力する
cam = Webcam.new cam.setFmt "ppm" cam.capture {|img| # img : PPMのP6形式で渡される。 puts img.length } cam.start
mruby-sixelの作成
mrbgemの概要
libsixelにRubyのGemを参考に
encoder = SixelEncoder.new encoder.encode_from_ppm ppm_image_buf
動かす
必要な物
- sixelに対応したターミナルエミュレーター
OSX,Linuxではmltermを用意すれば、試せる。WindowsでもRLoginから試せる。
参考資料
と
- libsixel本体
スペースキーを押すと、端末に画像が表示される。
cam = Webcam.new encoder = SixelEncoder.new cam.setFmt("ppm") cam.capture {|img| puts "\ec" encoder.encode_from_ppm img } cam.start
成果物
macOSでやるには
Undefined symbols for architecture x86_64:
— kjunichi (@kjunichi) 2017年2月25日
"GENERATED_TMP_mrb_mruby_sixel_gem_init
"GENERATED_TMP_mrb_mruby_sixel_gem_final
macOSだとclangが内部的に使われているのと、Linuxだとgccだから?現時点ではさっぱり。
— kjunichi (@kjunichi) 2017年2月25日
まとめ
前々から、sixel表示を手元の環境で試したと思いながら数年経ってしまったが、 2017年にようやく実現でき、mruby-sixelなるmrbgemも作成することが出来た。
関連記事
mrubyつながり
黒い画面つながり
Webカメラつながり
- GoでFaceTime HDカメラやWebカメラを使う
- WindowsでmrubyからGoで作ったライブラリを呼び出して、Webカメラの画像をコマンドプロンプトに表示した
- RustでWebカメラの映像をコマンドプロンプトに出すコマンドを作った