本記事のポイント

本記事では、Reactをベースに NEQTO と連携するための HTTPベースのウェブAPI NEQTO APIを使用して特定のノードの情報を取得するUIを作成します。NEQTO APIを使う上で参考になれば幸いです。



1. はじめに

IoT組み込みエンジンNEQTOをご契約の方は、NEQTOで提供しているNEQTO APIを使ってノードに関する情報を閲覧・管理するUIを独自で作成できます。例えば、NEQTOに接続しているエアコンをお持ちの場合、管理しているエアコンの一覧を表示したり、機械や機器に対して遠隔操作を行えるDynamic APIを使用して各エアコンの設定温度を操作したりするような、特定のデバイスに特化したダッシュボードを作成できます。

そこで今回は、そういったUIを作る方の参考になるよう、Reactをベースにノードのイベント一覧を表示するUIを作る方法をご紹介します。

2. Reactでプロジェクトを作る

まず、React公式の手順に従い、以下のコマンドを実行してプロジェクトを作成します。

$ npx create-react-app neqto-custom-ui
$ cd neqto-custom-ui</pre>

ファイル構造はこのようになっています。

.
├── README.md
├── node_modules/
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
└── src
    ├── App.css
    ├── App.js
    ├── App.test.js
    ├── index.css
    ├── index.js
    ├── logo.svg
    ├── reportWebVitals.js
    └── setupTests.js</pre>

UIを作成する際に必要のないコードは削除します。

src/App.js

src/App.js
import './App.css';

function App() {
  return (
    <div className='App'>
      {/* something */}
    </div>
  );
}

export default App;

また、useEffectで指定した関数が2回実行される問題を防ぐため、index.jsのReact.StrictModeを外します。本番モードでは機能しないため、外していてもそれほど影響はありません。

src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
// - root.render(
// -  <React.StrictMode>
// -    <App />
// -  </React.StrictMode>
// - );
root.render(
  <App />
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

そして、以下のコマンドを実行して開発モードで起動できます。

$ npm start

3. ログイン部分を作る

NEQTO APIに関する情報はNEQTOの公式ドキュメントの「APIの利用」のページに記載しています。

ログイン情報は同ページの「認証情報取得」の項目を参照すると、以下のパラメーターとボディでリクエストを行うことができます。

パラメーター
URL https://auth.neqto.com/account/api-token-auth
method POST
Content-Type application/json

body

{
  "company_code": "your company code",
  "email": "your login user",
  "password": "your user's login password"
}

これらを踏まえて書いたコードがこちらです。

src/App.js

import { useState } from 'react';
import './App.css';

function login(password) {
  return fetch('https://auth.neqto.com/account/api-token-auth', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      company_code: 'your-company-code',
      email: '■■■■@▲▲▲.com',
      password: password
    })
  }).then(res => res.json());
}

function App() {
  const [accessToken, setAccessToken] = useState();

  const onSubmit = (e) => {
    e.preventDefault();
    const password = e.target.querySelector('input[type="password"]').value;
    login(password)
      .then(data => setAccessToken(data.token));
  }
  return (
    <div className='App'>
      <form onSubmit={onSubmit}>
        <label htmlFor='password-input'>パスワードを入力してください</label>
        <br />
        <input type='password' id='password-input' />
        <button type='submit'>ログイン</button>
      </form>  

      {accessToken &&
        <>
          <p>ログインに成功しました</p>
          {accessToken}
        </>
      }
    </div>
  );
}
export default App;

ログインにはパスワードの他に、company codeとemailが必要ですが、今回は一つのノードにのみ対象にするUIを作成するため、この二つの情報はハードコーディングしています。

開発モードでアプリを起動後、localhost:3000にアクセスすると、以下のようにパスワードを入力するフォームが表示されます。

 
  パスワードを入力するフォーム  

入力を終えボタンをクリックすると、認証APIにリクエストされます。 ログインが成功すると以下のように表示され、アクセストークンを正常に得られたことが確認できます。

 
ログインが成功すると  

4. イベント履歴を取得する

特定のノードのイベントを取得するにはリージョンAPIを使用します。 NEQTOの公式ドキュメントの「APIの利用」のエンドポイントの表にも記載されていますが、リージョンAPIには2種類あるので、対象のデバイスに近いリージョンをお使いください。 APIリファレンスの「groups_nodes_events」のAPIで特定のノードのイベント履歴を取得できます。

また、認証APIで取得したアクセストークンはAuthorizationリクエストヘッダーにjwt <access token>という形でセットすることで使用できます。

次に、実際にコーディングをしますが、App.jsと同じディレクトリにEventTable.jsというファイルを新規作成し、そのファイルにイベント一覧を表示するテーブルをもつコンポーネントを書きます。 グループIDとノードIDを使用するため、定数”GROUP_ID”と”NODE_ID”を適宜書き換えてください。

グループIDとノードIDについては、ブログ「NEQTO リージョンAPIを使って、コマンドラインからスクリプトの操作をする方法」を参照してください。

src/EventTable.js

import { useEffect, useState } from 'react';

const GROUP_ID = 'your-group-id';
const NODE_ID = 'your-node-id';

function listEvents(accessToken) {
  const url = `https://asia-pacific-1.neqto.com/groups/${GROUP_ID}/nodes/${NODE_ID}/events`
              + `?from_time=${Date.now() - 70 * 24 * 60 * 60 * 1000}`
              + `&to_time=${Date.now()}`
              + '&limit=10'

  return fetch(url, {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'jwt ' + accessToken,
    }
  }).then(res => res.json());
}

function formatTime(unixtime) {
  return new Date(unixtime).toISOString()
                           .replace('T',' ')
                           .replace(/\..*/, '')
}

export default function EventTable({ accessToken }) {
  const [events, setEvents] = useState();

  useEffect(() => {
  listEvents(accessToken)
    .then(data => {
    setEvents(data.results);
    });
  }, [accessToken]);

  return (
    <div className='table-wrapper'>
      <table>
        <thead>
            <tr>
            <th>種類</th>
            <th>レベル</th>
            <th>メッセージ</th>
            <th>発生時間(サーバー)</th>
            <th>発生時間(デバイス)</th>
            </tr>
        </thead>
        {events ?
          events.map(event => (
            <tr>
              <td>{event.event_type}</td>
              <td>{event.event_level}</td>
              <td>{event.message}</td>
              <td>{formatTime(event.timestamp)}</td>
              <td>{formatTime(event.occurred_at)}</td>
            </tr>
          ))
          :
          <span>
            loading...
          </span>
        }
        <tbody>
        </tbody>
      </table>
    </div>
  )
}

そして、App.jsからこのコンポーネントを呼び出します。

src/App.js

import { useState } from 'react';

import './App.css';
import EventTable from './EventTable';

function login(password) {
  return fetch('https://auth.neqto.com/account/api-token-auth', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      company_code: 'your-company-code',
      email: '■■■■@▲▲▲.com',
      password: password
    })
  }).then(res => res.json());
}

function App() {
  const [accessToken, setAccessToken] = useState();

  const onSubmit = (e) => {
    e.preventDefault();
    const password = e.target.querySelector('input[type="password"]').value;
    login(password)
        .then(data => setAccessToken(data.token));
  }

  return (
    <div className='App'>
      <form onSubmit={onSubmit}>
        <label htmlFor='password-input'>パスワードを入力してください</label>
        <br />
        <input type='password' id='password-input' />
        <button type='submit'>ログイン</button>
      </form>  

      <h1>イベント一覧</h1>

      {accessToken ?
        <EventTable accessToken={accessToken} />
        :
        'Loading...'
      }
    </div>
  );
}

export default App;   

EventTableコンポーネントでは、リージョンAPIを使ってイベント一覧を取得し、eventsというステートにセットし、テーブルとして表示しています。

以下が実際に作成したUIです。(CSSは別途設定しています。)

 
イベント一覧画面  

5. まとめ

今記事では、NEQTO APIを使用して特定のノードの情報を取得するUIを作成する方法をご紹介しました。

簡単のため、API呼び出しのエラーハンドリングの実装や煩雑な処理の抽象化を省いていますが、NEQTO APIを用いたUIを実装する際の参考になれば幸いです。