Shoeisha Technology Media

CodeZine(コードジン)

特集ページ一覧

Spread.ViewsとRaspberry Pi+ESP32搭載ボードNefry BTでインフルエンザ対策のBIツールを作る

IoT時代の救世主! SpreadJSで作るデータ可視化アプリ 第3回

  • LINEで送る
  • このエントリーをはてなブックマークに追加

目次

MQTTブローカーの実装

 ここまででそれっぽいUIを作ることができました。次にセンサーデバイスとの連携をMQTTを利用して実装します。

 語弊を恐れずにいうと、MQTTはデバイスとデバイスでリアルタイムに情報を送受信できるプロトコルです。

 MQTTは「Nefry BT(ESP32)でMQTTを使ってみよう Subscribe編」で紹介しているように、ブローカー(Broker)と呼ばれるサーバーの役割が必要です。

 MQTTブローカーはNode.jsでも実装できます。

 今回はMoscaというライブラリを利用してMQTTブローカーを立てます。

npm i --save mosca

 server.jsにMQTTブローカーの記述を追記します。

server.js
'use strict';

const express = require("express");
const http = require('http');
const mosca = require('mosca');

const HTTP_PORT = 3000;
const MQTT_PORT = 1883;

const app = express();
const httpServer = http.createServer(app);
const broker = new mosca.Server({port: MQTT_PORT});

broker.on('ready', () => console.log('Server is ready.'));
broker.on('clientConnected', client => console.log('broker.on.connected.', 'client:', client.id));
broker.on('clientDisconnected', client => console.log('broker.on.disconnected.', 'client:', client.id));
broker.on('subscribed', (topic, client) => console.log('broker.on.subscribed.', 'client:', client.id, 'topic:', topic));
broker.on('unsubscribed', (topic, client) => console.log('broker.on.unsubscribed.', 'client:', client.id));
broker.on('published', (packet, client) => {
    if (/\/new\//.test(packet.topic))return;
    if (/\/disconnect\//.test(packet.topic))return;
    console.log('broker.on.published.', 'client:', client.id);
});

app.use(express.static(__dirname + '/public'));
app.get('/',(req,res) => res.sendFile(__dirname + '/index.html'));

broker.attachHttpServer(httpServer);
httpServer.listen(HTTP_PORT);

 実行してみましょう。

$ node server.js
Server is ready.

 エラーが出なければ問題無いです。

 broker.on('published')のコールバック関数の箇所がエッジデバイスからデータが送信されたら反応します。

エージェント(Nefry BT)側の配線

 今回はGroveの温湿度センサーを利用し、温度と湿度を測ります。また、CO2濃度を測るためにMH-Z19センサーを利用します。

 Grove温湿度センサーはNefry BTのGroveコネクタD2に接続し、MH-Z19センサーはGND、Vin、Tx、RxをそれぞれNefry BTのGND、5v、D3、D4に配線しましょう。

エージェント(Nefry BT)側の実装

 Nefry BTでエージェント側の実装をします。Nefry BTでプログラムを書いて利用開始するまでの手順はNefry BTの始め方を参照して下さい。

 今回はセンサリングした値をMQTTで送信するPublisherプログラムです。

 Arduino向けのMQTTライブラリをknolleary/pubsubclientからインストールします。

 以下のコードを書き込めば接続できますが、ブローカーのIPアドレスが必要となるのでRaspberry Pi上でifconfigなどのコマンドを実行し、IPアドレスを調査し、#define URLの箇所に適宜記載して下さい。

publish.ino
#include <Nefry.h>
#include <PubSubClient.h>

WiFiClient httpsClient;
PubSubClient mqttClient(httpsClient);

#define TOPIC "n0bisuke"
#define QOS 0
#define URL "192.168.179.2" //Raspberry PiのIPアドレスを指定
#define PORT 1883

#include "DHT.h"
#define DHTPIN D2     // what digital pin we're connected to
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);

HardwareSerial Serial1(1);
byte cmd_conc[9] = {0xFF,0x01,0x86,0x00,0x00,0x00,0x00,0x00,0x79};
byte cmd_zero[9] = {0xFF,0x01,0x87,0x00,0x00,0x00,0x00,0x00,0x78};
byte res[9];
int  co2 = 0;

void callback(char* topic, byte* payload, unsigned int length);
void errorReport();
bool verify(byte packet[]);

void setup() {
  Nefry.enableSW();
  Nefry.setLed(0, 0, 0);

  mqttClient.setServer(URL, PORT);
  mqttClient.setCallback(callback);

  Serial.begin(115200);
  Serial.println("DHTxx test!");
  dht.begin();

  // Serial1 RX : Nefry D3 (ESP32 IO19) --- CO2 Sensor TX
  // Serial1 TX : Nefry D4 (ESP32 IO18) --- CO2 Sensor RX
  Serial1.begin(9600, SERIAL_8N1, 19, 18);
  delay(10*1000);
}

void loop() {
  delay(2000);

  // Calibration Co2 sensor
  if (Nefry.readSW()) {
    Serial1.write(cmd_zero, 9);
    Serial.println("---Calibration---");
    delay(100);
  }

  /**
   * 温度湿度
   */
  float h = dht.readHumidity(); //湿度
  float t = dht.readTemperature(); //温度
  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  /**
   * co2
   */
  // Send command to get co2 concentration
  Serial1.write(cmd_conc, 9);
  delay(10);
  // Receive packet
  if (Serial1.readBytes(res, 9) == 9) {
    // verify checksum
    if (verify(res)) {
      /*
      * 012345678
      * SCHL----ck
      */
      int resHigh = (int)res[2];
      int resLow  = (int)res[3];
      co2 = (resHigh<<8) + resLow;
    } else {
      // invalid packet
      co2 = -1;
    }
  } else {
    // received strange length of bytes
  }

  /**
   * MQTT
   */
  if(!mqttClient.connected()) {
    if (mqttClient.connect(TOPIC)) {
        Serial.println("MQTT Connected.");
    }
    else {
      errorReport();
    }
  }else{
    char buffer[70];
    sprintf(buffer, "{\"humidity\":%f,\"temperature\":%f,\"co2\":%d}", h, t, co2);
    mqttClient.publish(TOPIC, buffer);
    Serial.println("Published");
  }

  /**
   * 表示
   */
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.print(" %\t");
  Serial.print("Temperature: ");
  Serial.print(t);
  Serial.print(" C\t");
  Serial.print("CO2: ");
  Serial.println(co2);

  mqttClient.loop();
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

void errorReport(){
  Serial.print("Failed. Error state = ");

  switch (mqttClient.state()) {
    case MQTT_CONNECT_UNAUTHORIZED:
      Serial.println("MQTT_CONNECT_UNAUTHORIZED");
      break;
    case MQTT_CONNECT_BAD_CREDENTIALS:
      Serial.println("MQTT_CONNECT_BAD_CREDENTIALS");
      break;
    case MQTT_CONNECT_UNAVAILABLE:
      Serial.println("MQTT_CONNECT_UNAVAILABLE");
      break;
    case MQTT_CONNECT_BAD_CLIENT_ID:
      Serial.println("MQTT_CONNECT_BAD_CLIENT_ID");
      break;
    case MQTT_CONNECT_BAD_PROTOCOL:
      Serial.println("MQTT_CONNECT_BAD_PROTOCOL");
      break;
    case MQTT_CONNECTED:
      Serial.println("MQTT_CONNECTED");
      break;
    case MQTT_DISCONNECTED:
      Serial.println("MQTT_DISCONNECTED");
      break;
    case MQTT_CONNECT_FAILED:
      Serial.println("MQTT_CONNECT_FAILED");
      break;
    case MQTT_CONNECTION_LOST:
      Serial.println("MQTT_CONNECTION_LOST");
      break;
    case MQTT_CONNECTION_TIMEOUT:
      Serial.println("MQTT_CONNECTION_TIMEOUT");
      break;
  }

  delay(5000); // Wait 5 seconds before retrying
}

bool verify(byte packet[]) {
  byte checksum = 0;
  for (int i=1; i<8; i++) {
    checksum += packet[i];
  }
  checksum = 0xFF - checksum;
  checksum += 0x01;
  if (packet[8] == checksum) {
    return true;
  } else {
    return false;
  }
}

 Arduino IDEからNefry BTに書き込めば完成ですが、Nefry BTとRaspberry Piは同じWi-Fiに接続していることを確認しましょう。

 これでデータの確認をしてみましょう。

 問題なければ2秒おきのデータがNode.jsのブローカー側で確認できます。

 ちなみにFailed to read from DHT sensor!と表示されてうまく湿度の値が取れてない箇所がありますが、これは利用しているセンサー(DHT11)の対応範囲が湿度20%~90%となっており、湿度が下回りすぎて上手くデータが取得できていないという衝撃的な事実でした。

 dotstudioオフィスが乾燥しすぎなので加湿器を増やそうと思います。


  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

  • 菅原のびすけ(dotstudio株式会社)(スガワラ ノビスケ)

     日本最大規模のIoTコミュニティ「IoTLT」主催。岩手県立大学大学院ソフトウェア情報学研究科を卒業後、株式会社LIGでWebエンジニアとして入社し、Web開発に携わる。2016年にdotstudio株式会社を立ち上げ、今はIoT領域を中心に活動している。JavaScript Roboticsコミ...

バックナンバー

連載:IoT時代の救世主! SpreadJSで作るデータ可視化アプリ
All contents copyright © 2005-2018 Shoeisha Co., Ltd. All rights reserved. ver.1.5