non vorrei lavorare

2020年度からの小学校プログラミング教育の必修化を親として迎えるブロガーの書く、子供との日常

Arduinoで測った室温をデスクトップマスコットのgopheronに表示させた

背景

arduinoを手に入れて、何かPCと連携してみたくなった。

Arduinoで測った室温をデスクトップマスコットのgopheronに表示

構成

  • node.jsでarduinoの計測結果をシリアルポート経由で受信し、ファイルに出力
  • ファイル出力はリダイレクトで実現

node.jsでarduinoの計測結果をシリアルポート経由で受信

シリアル通信には、以下のモジュールを使用した。

serialport.io

インストールは以下のようにできる。

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()
})

実行結果

youtu.be

今回使用したArduino

関連記事

gopheronつながり

4年前の記事

3年前の記事

2年前の記事