テンプレートを用いたテーブルウィジェットのカスタマイズ


投稿日 / 更新日 / 投稿者名

2022.3.15 / 2024.9.9 / アプリチーム

はじめに

本レポートは、Things Cloud の利用例をより知っていただくための実利用レポートとして作成したものです。
Things Cloud は極力後方互換性を持つよう開発されていますが、今後のリリースにより、一部画面やコマンド、手順などが変更となったり、利用できない可能性があることをあらかじめご了承ください。
なお、作成にあたり、以下バージョンを用いています。

  • ver.1018.0.259(Frontend)

難易度 ★★


所要時間(目安)

60分

概要

本レポートでは、Things Cloud でテーブルウィジェットをカスタマイズするための簡単な方法について紹介いたします。

カスタムウィジェット開発には通常であればプログラミング経験や前提知識を要しますが、本レポートでは、カスタムウィジェットのテンプレートを提供しています。Things Cloud 特有の前提知識が必要となる箇所を最小限にしているため、0からカスタムウィジェットを開発するよりも小さなコストで開発でき、IoT データ可視化の探索や試行錯誤に注力いただけます。

テンプレートでは Things Cloud Data Supplier というモジュールを使用しており、Things Cloud からのデータの取得等を行っております。

前提条件

  • 以下を扱えること
    • JavaScript/TypeScript
  • カスタムウィジェット開発に必要な環境を準備していること
    • Node.js (v10.16.3以上推奨)
    • npm (Node.js と一緒にインストールされます)
    • @c8y/cli パッケージ (c8ycli コマンドの使用に必要です)
  • 基本的な Things Cloud のデータモデル(Alarm, Managed Object など)の理解があること

本レポートでは、通常のカスタムウィジェット開発で必要とされる、以下スキルについては極力不要となるように考慮されています。

完成イメージ

下の赤枠が完成したウィジェットです。

このウィジェットは、指定されたデバイス、またはアセット(グループ)内にあるデバイスの最新 Measurement 値、最新 Event テキスト、最新 Alarm テキストを表示することができます。

config 画面

ウィジェットのconfig画面の説明です。

番号 項目 設定内容 設定値例
① タイトル ウィジェット上部に表示されるタイトルを入力します -
② 対象のアセットもしくはデバイス データ取得対象となるデバイスまたはアセット(グループ)を指定します。アセットが階層となっていた場合、子、孫、、すべてのデバイスが対象となります。 -
③ Measurement の FragmentType 表に表示する Measurement の fragment type を指定します c8y_Temperature
④ Measurement の FragmentSeries 表に表示する Measurement の fragment series を指定します T
⑤ Event の type 表に表示する Event の type を指定します c8y_LocationUpdate
⑥ Alarm の type 表に表示する Alarm の type を指定します c8y_UnavailabilityAlarm

ウィジェット本体

ウィジェットの表の各要素を説明します。

番号 項目
① 表示対象のデバイス名が列挙されます
② 各デバイスが報告した Measurement のうち、指定 Fragment type/series の最新値を表示します
③ 各デバイスに関連する Event のうち、指定 type のものの最新 text 値を表示します
④ 各デバイスに関連する Alarm のうち、指定した type で最後に報告されたものの text 値を表示します

※各最新値はウィジェットが表示される時点での最新値です

開発の流れ

以下の流れで作業を進めます。

  1. ダウンロード、ローカルで確認
  2. データの前準備
  3. ウィジェットのカスタマイズ
  4. ローカルで確認
  5. デプロイ

1. ダウンロード、ローカルで確認 

テンプレートzip をダウンロード

以下のファイルをダウンロードします。

zip ファイルを解凍し、適当なディレクトリに保存して下さい。ここがカスタムウィジェットプログラムを作成するディレクトリになります。

ファイル構成

以下の17ファイルが解凍されます。

└─cockpit-table
        app.module.spec.ts
        app.module.ts
        table-template-config.component.html
        table-template-config.component.ts
        table-template.component.css
        table-template.component.html
        table-template.component.ts
        i18n.ts
        index.ts
        jest.config.js
        ng1.ts
        package.json
        polyfills.ts
        preview-table-template.png
        setup-jest.js
        tsconfig.json
        tsconfig.spec.json
        tc-data-supplier/
ファイルについて

本記事では、以下4ファイルを編集します。

# ファイル名 説明
1 table-template.component.ts Angularコンポーネントで、table-template-component ウィジェットを表すプログラムです。
表に表示するデータを編集したい場合はこのファイルを編集します。
2 table-template.component.html table-template-component の html テンプレートファイルです。表の見た目を編集したい場合はこのファイルを編集します。
3 table-template.component.css table-template-component のスタイルシート定義ファイルです。表のスタイルを編集したい場合はこのファイルを編集します。
4 package.json npm で利用されるパッケージ定義ファイルです。

以下ファイルはビルドに必要なものですが、編集不要です。

# ファイル名 説明
1 app.module.spec.ts テスト用のプログラムです。
2 app.module.ts Angularで利用されるコンポーネント構成を定義するプログラムです。
3 table-template-config.component.ts Angularコンポーネントで、ウィジェットの config ダイアログを表すプログラムです。
4 i18n.ts 表示言語の翻訳情報を定義するプログラムです。
5 index.ts Angularで利用されるプログラムです。
6 jest.config.js テスト用の定義ファイルです。
7 ng1.ts Angularで利用されるプログラムです。
8 polyfills.ts Angular で利用されるプログラムです。
9 preview-table-template.png ウィジェットのプレビューイメージです。
10 setup-jest.js テスト用のプログラムです。
11 tsconfig.json TypeScriptのコンパイルオプションを定義します。
12 tsconfig.spec.json テスト用の定義ファイルです。
13 tc-data-supplier/ プログラム動作に必要なファイルが格納されています。ウィジェット開発を容易にするための便利な関数が複数定義されています。

ビルド

ダウンロードしたテンプレート zip にはサンプルのウィジェットが含まれていますので、正常に構築できるか試しましょう。

ビルド、実行には Node.js および c8ycli をインストールする必要があります。

Node.js のインストール

Node.js から Node.js(v16.14以降)をインストールして下さい。

c8ycli

続いて、以下コマンドにより c8ycli コマンドをグローバルインストールして下さい。

$ npm install -g @c8y/cli

npm は Node.js に含まれるパッケージ管理ソフトです。

npm install

解凍ファイルを格納したディレクトリで、以下コマンドを実行します。

$ cd cockpit-table
$ npm install

npm install では、関連パッケージをインターネットから自動的にダウンロードします。

数分~数十分程度時間がかかる場合があります。

  :
(省略)
  :
  :
npm WARN deprecated xterm@3.14.5: This package is now deprecated. Move to @xterm/xterm instead.
npm WARN deprecated angular-i18n@1.6.9: For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward.

> cockpit-table@1018.0.259 postinstall
> ngcc

added 1789 packages, and audited 1790 packages in 1m
  :

上記のようなメッセージが出れば完了です。

package.json の編集

package.json 内 scripts の start の -u以降を削除 することで、npm run start コマンドで、localhostでの動作確認ができます。また、localhostへのリクエストを -u オプションによって指定した URL へプロキシするように指定できます。同じように scripts の build や deploy に c8ycli コマンドをあらかじめ設定することで、c8ycli コマンドを意識せず、npm run ...コマンドにより実行することができます。

{
  "name": "cockpit-table",
  "version": "1018.0.259",
  "description": "",
  "scripts": {
    "start": "c8ycli server",
    "build": "c8ycli build",
    "deploy": "c8ycli deploy",
    "locale-extract": "c8ycli locale-extract",
    "postinstall": "ngcc",
    "test": "jest"
  },
  "keywords": [],
  :
}

npm run start を実行した後、Webブラウザに以下のURL ( http://localhost:9000/apps/cockpit-table/ ) を入力し、アクセスします。アクセス後、テナントID・ユーザ名・パスワードの入力が求められるためこれらを入力し、リクエストをプロキシしているテナントへログインします。ログイン後、アプリケーションの動作確認ができるようになります。

npm run start

次のコマンドを入力します。

$ npm run start

http://localhost:9000/apps/cockpit-table/ 98 % - after emitting - angular-compiler

上記 % 表示が 100 になるまでお待ちください。

完了すると、以下表示となります。数分以上かかる場合があります。

http://localhost:9000/apps/cockpit-table/ done - finished in 123 s - 237.738 ms

ブラウザから閲覧

Chrome, Firefox, Edge などのブラウザのアドレスバーに、http://localhost:9000/apps/cockpit-table/ を入力し、テナントID、ユーザー、パスワードを入力して下さい。

テナントID は、あらかじめテナントにログインし、右上のユーザーボタンで確認しておいて下さい。

詳細は、ユーザーオプションと設定 に記載があります。

ログイン後、コックピットアプリケーションの「ホーム」で右上の「ウィジェットを追加」をクリックして下さい。以下のように、「TableTemplate Widget」が選択できるようになっていれば、build は成功です。

以下のようなエラーが出てウィジェットを追加できない場合は、一度 コックピットアプリケーションをデプロイ してください。

2. データの前準備

ここでは、表へ出力させるためのデータを準備します。今回は説明のために、Things Cloudの機能であるシミュレータを利用します。
また、お手持ちのIoTセンサーやデータがあればそちらもご利用可能です。

シミュレータの準備

以下では、温度シミュレータを例としてシミュレータの作成手順を説明しています。シミュレータをご利用になる方は参考にしてください。

シミュレータ作成の操作をgifアニメーションにしています。クリックすると拡大して表示されます。

  1. Things Cloudのデバイス管理画面を開き、シミュレータ -> シミュレータを追加 をクリック
  2. プリセット 温度計測 を選択し、作成 をクリック
  3. 作成した温度シミュレータを 実行中 へ変更 (データが生成されるまで少し時間がかかります)

以上でシミュレータの準備は完了となります。シミュレータについて、詳しくはこちらをご覧ください。

3. ウィジェットのカスタマイズ

テーブルのカスタマイズ

ウィジェットのコンポーネントを要件に応じてカスタマイズします。いくつかの例を表示しましたのでご参考ください。

表示する列を増やす

例) デバイスID列を追加する

  • HTMLのtable要素のヘッダーにデバイスID列を追加し、データ行に表示するデバイスIDのデータ列d.device.idをヘッダーと同じ位置に追加します。

    表形式のtable表示は、table:表要素をご参考ください。

table-template.component.html

  :
  <thead>
    <tr>
      <th style="text-align: center;">No.</th>
      <!-- 8< デバイスID列 ヘッダーを追加 -->
      <th style="text-align: center;">デバイスID</th>
      <!-- デバイスID列 ヘッダーを追加 >8 -->
      <th style="text-align: center;">デバイス名</th>
      <th style="text-align: center;">最終計測値</th>
      <th style="text-align: center;">最終イベント</th>
      <th style="text-align: center;">最終アラーム</th>
    </tr>
  </thead>
  <tbody>
    <tr *ngFor="let d of dataSource; let i = index">
      <td style="text-align: center;">{{ i+1 }}</td>
      <!-- 8< デバイスID列 データ行を追加 -->
      <td style="text-align: left;">{{ d.device.id }}</td>
      <!-- デバイスID列 データ行を追加 >8 -->
      <td style="text-align: left;">{{ d.device.name }}</td>
      <td style="text-align: left;">{{ d.measurement ? d.measurement[config.fragmentType][config.fragmentSeries].value : ' - '}}</td>
      <td style="text-align: left;">{{ d.event ? (d.event.text)  : ' - '}}</td>
      <td style="text-align: left;">{{ d.alarm ? (d.alarm.text)  : ' - '}}</td>
    </tr>
  </tbody>
  :
表示するセルの配色を変える

例) アラームが「ACTIVE」の場合、アラーム列の文字を赤色にする

  • HTMLのtableのアラーム列のtd要素にステータスが「ACTIVE」の場合、redというクラスを追加します。

    HTML要素のスタイリングは、CSS入門をご覧ください。

table-template.component.html

  :
  <tbody>
    <tr *ngFor="let d of dataSource; let i = index">
      <td style="text-align: center;">{{ i+1 }}</td>
      <td style="text-align: left;">{{ d.device.name }}</td>
      <td style="text-align: left;">{{ d.measurement ? d.measurement[config.fragmentType][config.fragmentSeries].value : ' - '}}</td>
      <td style="text-align: left;">{{ d.event ? (d.event.text)  : ' - '}}</td>
      <!-- 8< classを追加: アラームのステータスがACTIVEの場合 red -->
      <td style="text-align: left" [ngClass]="d.alarm?.status == 'ACTIVE' ? 'red' : ''">{{ d.alarm ? (d.alarm.text)  : ' - '}}</td>   
      <!-- classを追加: アラームのステータスがACTIVEの場合、red >8 -->
    </tr>
  </tbody>
  :

table-template.component.css

.red {
    color: red;
}
表示する値を変える

例) メジャーメントに1ヶ月の合計値を表示する

  • データ取得のメジャーメントフィルタに2022年2月の1ヶ月間という条件を追加し、集計した値を算出するコードを追加します。(1ヶ月間のデータ件数は1000件以下とします。)

    配列データに関するJavaScript関数は、filterやreduceをご覧ください。

データの取得や、filterに指定できるパラメータに関する詳細は以降に説明します。

table-template.component.ts

async getData(config: any) : Promise<any> {
    :
    const measurementFilter: any = {
        // 8< フィルタ条件を追加
        dateFrom: "2022-02-01T00:00:00.000+09:00",
        dateTo: "2022-02-28T23:59:59.999+09:00",
        pageSize: 1000
        // フィルタ条件を追加 >8
    };
    :
    const measurements = await this.thingsCloudDataSupplier.getMeasurementsArray(deviceId, measurementFilter);
    :
    return { devices, measurements, alarms, events };
}
prepareDataSource(data: any): any[] {
    const dataSource = [];
    data.devices.forEach((device: any) => {
        dataSource.push({ 
            device: device,
            // 8< 計測値をデバイス毎に集計
            measurement: data.measurements
                .filter(measurement => measurement.source.id === device.id)
                .reduce((previous, current) => previous + current[this.config.valueFragmentType][this.config.fragmentSeries].value, 0),
            // 計測値をデバイス毎に集計 >8
            event: data.events.find(event => event.source.id === device.id),
            alarm: data.alarms.find(alarm => alarm.source.id === device.id)
        })
    });
    return dataSource;
}

データの取得

Things Cloud のデータは、tc-data-supplierを使いフィルタリング情報をもとにテーブルに表示したいデータを取得しています。

カスタムウィジェットのコンポーネント table-template.component.tsで ThingsCloudDataSupplier クラスを利用し、get{Devices or Measurements or Alarms or Events}Array メソッドからグラフに表示するデータを取得しています。デバイス、メジャーメント、アラーム、イベントのデータを取得していますので、ご活用ください。

table-template.component.ts

export class TableTemplate implements OnInit {
  :
  async getData(config: any) : Promise<any> {
    const deviceId = config.device.id;
    const devices = await this.thingsCloudDataSupplier.getDevicesArray(deviceId);

    const dateTo = new Date().toISOString();
    const measurementFilter: any = {
      dateTo: dateTo,
      pageSize: 1,
      revert: true
    };
    if ( (!!config.fragmentType) && (!!config.fragmentSeries) ) {
      measurementFilter.valueFragmentType = config.fragmentType;
      measurementFilter.valueFragmentSeries = config.fragmentSeries;
    }

    const measurements = await this.thingsCloudDataSupplier.getMeasurementsArray(deviceId, measurementFilter);
    :
    return { devices, measurements, alarms, events };
  }
  :
}
対象のアセット もしくは デバイス

this.config には、カスタムウィジェットの構成画面で設定した情報が格納されています。

this.config.device.id には、選択されたデバイス、またはアセット(グループ)のIDが 設定されます。

this.config.valueFragmentType this.config.valueFragmentSeries には、入力されたMeasurementのフラグメント、シリーズ名が設定されます。同じように、EventやAlarmも入力されたタイプが設定されます。

このように構成画面ではテーブルに表示したいデータのフィルタ条件などをユーザに設定してもらうことが可能です。

filterに指定できるパラメータ
パラメータ
指定例 説明 Measurement Alarm Event
dateFrom dateFrom: “2022-02-01T00:00:00+09:00” データを取得する開始日時を指定します ○ ○ ○
dateTo dateTo: “2022-02-06T00:00:00+09:00” データを取得する終了日時を指定します ○ ○ ○
pageSize pageSize: 50 データを一度に取得する数を指定します ○ ○ ○
withTotalPages withTotalPages: true withTotalPages: true を指定すると、currentPage 指定ができます ○ ○ ○
currentPage currentPage: 1 withTotalPages: true を指定した場合に、取得するページの位置を指定できます ○ ○ ○
type type: “c8y_UnavailabilityAlarm” 取得するデータのタイプ名を指定します ○ ○ ○
valueFragmentType valueFragmentType: “c8y_Temperature” メジャーメントの値を格納しているフラグメントタイプを指定します ○ - -
valueFragmentSeries valueFragmentSeries: “T” valueFragmentType と合わせて、取得するフラグメントシリーズ名を指定します ○ - -
fragmentType fragmentType: “com_TestMeasurement” 取得するデータのフラグメントタイプ名を指定します - ○ ○
status status: “ACTIVE” 取得するアラームのステータスを指定します。“ACKNOWLEDGED”, “CLEARED”, “ACTIVE” を指定可能です - ○ -
severity severity: “CRITICAL” 取得するアラームの重大度を指定します。“CRITICAL”, “MAJOR”, “MINOR”, “WARNING” を指定可能です - ○ -
resolved resolved: true true を指定した場合、“CLEARED” ステータスのもののみが対象となり、false を指定した場合、“ACTIVE”/“ACKNOWLEDGED” のものが対象となります。 - ○ -

4. ローカル環境での動作確認

package.json の編集がされていることを確認し、以下のコマンドを実行してください。

$ npm run start
(node:33065) Warning: Accessing non-existent property 'padLevels' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
Proxying requests to remote instance https://<テナント名>.je1.thingscloud.ntt.com

http://localhost:9000/apps/cockpit-table/ 59 % - building - 415/417 modules

実行結果が100%になると上記のlocalhostへアクセスできます。ブラウザで http://localhost:9000/apps/cockpit-table/ へアクセス、ログインダイアログへテナントの認証情報を入力し、任意のダッシュボードへ移動します。

ダッシュボードで、「ウィジェットの追加」から「TableTemplate Widget」を選択した後、保存します。以下のようなウィジェットが作成されれば成功です。すでにウィジェットを追加済みの場合は、ブラウザをリロードします。

この時点ではプロキシしているテナントで修正中のカスタムウィジェットを確認することはできません。デプロイ後に、プロキシしているテナントでもカスタムウィジェットを確認することができます。

5. Things Cloud へのデプロイ手順

ローカル環境での動作が正常であることを確認したら、Things Cloud へデプロイします。アプリケーションのルートディレクトリ (cockpit-table/ 直下) に移動し、以下のコマンドを実行します。

$ npm run build
$ npm run deploy
prompt: Instance URL:  (http://demos.cumulocity.com) テナントのURLを入力 (例: https://<テナント名>.je1.thingscloud.ntt.com)
prompt: Username:  (admin) ユーザ名を入力
prompt: Password: パスワードを入力

npm run build コマンドを実行し、アプリケーションをビルドします。ビルド後、アプリケーションのディレクトリに dist/ ディレクトリが作成されます。このディレクトリが作成されたことを確認したら、npm run deploy コマンドで Things Cloud へアプリケーションをデプロイします。デプロイコマンド実行時に、アプリケーションのデプロイ先 URL とユーザ情報の入力が必要になります。

参考

以下に本レポートを実施する上で参考となる Web サイトへのURLを記載します。