背景
arduinoを手に入れて、何かPCと連携してみたくなった。
Arduinoで測った室温をデスクトップマスコットのgopheronに表示
構成
- node.jsでarduinoの計測結果をシリアルポート経由で受信し、ファイルに出力
- ファイル出力はリダイレクトで実現
node.jsでarduinoの計測結果をシリアルポート経由で受信
シリアル通信には、以下のモジュールを使用した。
インストールは以下のようにできる。
npm i -S serialport
このserialportモジュールはパーサーをいくつか選べるようで、今回はreadLineパーサーを使って、 arduino側で"\n"を入れることで、このパーサーと連携した。
node.jsの受信部
const SerialPort = require("serialport") const Readline = SerialPort.parsers.Readline const sp = new SerialPort("/dev/cu.usbmodem14201", { baudRate: 9600 }) const parser = new Readline() sp.pipe(parser) parser.on('data', (line) => { console.log(`line : ${line}`) }) sp.on("open", () => { console.log('open') })
arduino側のコード
arduino側はサンプルのコードの結果をシリアルポートに書き込むように処理を追加した程度。
//www.elegoo.com //2016.12.9 #include <LiquidCrystal.h> int tempPin = 0; // BS E D4 D5 D6 D7 LiquidCrystal lcd(7, 8, 9, 10, 11, 12); void setup() { lcd.begin(16, 2); Serial.begin(9600); } void loop() { int tempReading = analogRead(tempPin); // This is OK double tempK = log(10000.0 * ((1024.0 / tempReading - 1))); tempK = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * tempK * tempK )) * tempK ); // Temp Kelvin float tempC = tempK - 273.15; // Convert Kelvin to Celcius float tempF = (tempC * 9.0)/ 5.0 + 32.0; // Convert Celcius to Fahrenheit /* replaced float tempVolts = tempReading * 5.0 / 1024.0; float tempC = (tempVolts - 0.5) * 10.0; float tempF = tempC * 9.0 / 5.0 + 32.0; */ // Display Temperature in C lcd.setCursor(0, 0); lcd.print("Temp C "); // Display Temperature in F //lcd.print("Temp F "); lcd.setCursor(6, 0); // Display Temperature in C lcd.print(tempC); Serial.print(tempC); Serial.print("\n"); // Display Temperature in F //lcd.print(tempF); delay(500); }
デスクトップマスコットへの通信コマンド
デスクトップマスコットはWebSocketを受け付けているので、 先ほどの計測した室温のファイルをtailコマンド風に追加された行を読み込んで、これを WebSocketに書き込む。
アイコンは例によって、PNGを同期APIのfs#readFileSyncで読み込んで、base64でHTMLに埋めむ実装
node.jsでtailコマンド風の処理をする
以下のモジュールでnode.jsでtailコマンド風にファイルに追加された行を取得できる。
npm i -S node-tail
tail風の処理は以下のようになる。
const Tail = require('tail').Tail const filename = "/path/to/roomTemp.dat" const tail = new Tail(filename); tail.on('line', (line) => { const temp = line.split(':')[1] console.log(`temp : ${temp}`) } tail.on('close', () => { console.log('watching stopped'); }) tail.watch() setTimeout(()=>{ tail.unwatch() },5000)
const socket = require('socket.io-client')('http://localhost:5050') const Tail = require('tail').Tail const fs = require('fs') const filename = "/Users/kjunichi/work/nodejs/arduino/serial/roomTemp.dat" const logo = fs.readFileSync("./ArduinoCommunityLogo.png") socket.on('connect', () => { const tail = new Tail(filename); let count; socket.on('gopher recv', (msg) => { console.log(`recv: ${msg}`) count-- if (count <= 0) { process.exit(0) } }) const displayTemp = (temp) => { count=2; socket.emit('gopher front', '1000') const html = `<img width="192" src="data:image/png;base64,${logo.toString('base64')}"><span style=\"font-size:larger;font-family: 'Segoe UI Emoji';\"><div style=\"font-size: 48px;wrap\">🌡 ${temp}℃</div></span>` socket.emit('gopher sendHtml', html) tail.unwatch() } tail.on('line', (line) => { const temp = line.split(':')[1] console.log(`temp : ${temp}`) displayTemp(temp) }) tail.on('close', () => { console.log('watching stopped'); }) tail.watch() })
実行結果
今回使用したArduino
関連記事
gopheronつながり
- Goオールスターズ2に行くので、gopheronをGo言語で動かせるようにした #websocket
- Raspberry Piの温度をgRPCを使ってElectronで作ったデスクトップマスコットに表示させた
- macOSのCPU温度をgRPCを使ってElectronで作ったデスクトップマスコットに表示させた