IEEE1888 SDKをMacで使う: Javaプログラミング篇

前回SDKの構成について確認しましたが、今回は実際にWRITEするプログラムを作成してみます。

環境構築

基本的にはSDKに付属する「IEEE1888プログラミング・スタートアップ・マニュアル」の説明通りに進めます。

まず、Axis2のダウンロードをおこないます。マニュアルでは1.5系を使用するように指定されているので、その中で最新版を選択します。
今回は、axis2-1.5.6-bin を利用します。

ダウンロードしたら、以下のディレクトリ構成に展開します。

app/                # 開発のトップ
    + axis2-1.5.6/  # zipを展開してできるディレクト

Macjava が入っているかどうかは環境によります。java や javac コマンドを起動してみて、動作すれば良いですし、無ければ「インストールしますか?」と聞いてくるので、そこでインストールを選択します。(OSX 10.8.1の場合)
聞いてこなければ http://support.apple.com/downloads/#java からダウンロードしてインストールします。

次に WSDL からStub等のファイルを生成します。

$ cd app
$ export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
$ ./axis2-1.5.6/bin/wsdl2java.sh -uri http://192.168.11.12/axis2/services/FIAPStorage?wsdl

これで、以下のような構成になります。準備OKです。

app/
    + axis2-1.5.6/
    + build.xml
    + src/org/fiap/soap/FIAPStorageStub.java
    + src/org/fiap/soap/FIAPStorageCallbackHandler.java

コード

次にテストソースを記述します。ファイルは以下の場所に作成します。

app/
    + ....
    + src/kahnn/SampleFIAPApp.java

コードは以下のようになります。

package kahnn;

import org.fiap.soap.FIAPStorageStub;
import org.apache.axis2.databinding.types.URI;
import java.util.Calendar;
import java.util.Date;
import java.text.SimpleDateFormat;

public class SampleFIAPApp {

    static private String USAGE_MSG =
    "SampleFIAPApp id value [time [target_endpoint]]\n"
    + "  time: yyyy-MM-dd'T'HH:mm:ss.SSSZ\n"
    + "  target_endpoint: http://x.x.x.x/axis2/services/FIAPStorage/";

    /** WRITE */
    public static void write(String id, String data,
                             Calendar dtime, String endpoint)
        throws Exception
    {
        // Pointの作成 (1つだけ). Point[]を取り扱うことも可.
        FIAPStorageStub.Point point = new FIAPStorageStub.Point();
        {
            FIAPStorageStub.Value value = new FIAPStorageStub.Value();
            point.setId(new URI(id));
            value.setTime(dtime);
            value.setString(data);
            point.addValue(value);
        }

        // PointSetは使用しないが使う場合は以下のようになる. 配列でなくても可.
        //FIAPStorageStub.PointSet[] ps = new FIAPStorageStub.PointSet[n];
        //ps[0] = new FIAPStorageStub.PointSet();
        //ps[0].setId(new URI("http://.... pointset id ..../"));
        //ps[0].setPoint(point);
        // ....

        //  Body
        FIAPStorageStub.Body body = new FIAPStorageStub.Body();
        body.addPoint(point);  // -or- setPoint(points[])
        // body.setPointSet(ps);

        // Transport
        FIAPStorageStub.Transport transport = new FIAPStorageStub.Transport();
        transport.setBody(body);

        // DataRQ
        FIAPStorageStub.DataRQ dataRQ = new FIAPStorageStub.DataRQ();
        dataRQ.setTransport(transport);

        // Stub & WRITE REQUEST
        FIAPStorageStub server =
            ((null == endpoint) ? new FIAPStorageStub()
                                : new FIAPStorageStub(endpoint));
        FIAPStorageStub.DataRS dataRS = server.data(dataRQ);

        // Get Header
        transport = dataRS.getTransport();
        FIAPStorageStub.Header header = transport.getHeader();
        if (null == header) {
            exitErr("Fatal Error: Header object was not found.");
        }

        // Check OK -or- NG
        FIAPStorageStub.OK ok = header.getOK();
        if (ok != null) {
            System.out.println("Successfully uploaded "
                               + "\'" + id + "\'=\'" + data + "\' ...");
        }
        else {
            FIAPStorageStub.Error error = header.getError();
            if (error != null) {
                exitErr("Error: type=\'" + error.getType() + "\'"
                        + "; message=\'" + error.getString() + "\'");
            } else {
                exitErr("Fatal Error: Neither OK nor Error object was not found.");
            }
        }
    }

    //////////////////////////////////////////////////////////

    public static void usage() {
        System.err.println(USAGE_MSG);
        System.exit(-1);
    }

    public static void exitErr(String msg) {
        System.err.println(msg);
        System.exit(-2);
    }

    public static void main(String[] args)
        throws Exception
    {
        if (args.length < 2) {
            usage();
        }

        // Get pointID
        String id = args[0];

        // Get value data
        String data = args[1];

        // Set calender
        Calendar dtime = Calendar.getInstance();
        if (3 <= args.length) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            dtime.setTime(sdf.parse(args[2]));
        }

        // Set endpoint
        String endpoint = null;
        if (4 <= args.length) {
            endpoint = args[3];
        }

        write(id, data, dtime, endpoint);
    }
}

Ant を使用して build します。Mac には標準でインストールされているので、何も考えずに利用できます。

$ export AXIS2_HOME=/Users/kahnn/Desktop/IEEE1888/app/axis2-1.5.6
$ ant
.....
jar.client:
      [jar] Building jar: /Users/kahnn/Desktop/IEEE1888/app/build/lib/FIAPStorage-test-client.jar

BUILD SUCCESSFUL
Total time: 3 seconds

これで、Client 用の FIAPStorage-test-client.jar ができました。

実行

さっそく、テストプログラムを実行してみます。axis2 に含まれる axis2.sh を利用すると必要なクラスパスの設定が楽になります。
まずは USAGE の確認。

$ axis2-1.5.6/bin/axis2.sh -cp build/lib/FIAPStorage-test-client.jar kahnn.SampleFIAPApp
 Using AXIS2_HOME:   /Users/kahnn/Desktop/IEEE1888/app/axis2-1.5.6
 Using JAVA_HOME:       /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
SampleFIAPApp id value [time [target_endpoint]]
  time: yyyy-MM-dd'T'HH:mm:ss.SSSZ
  target_endpoint: http://x.x.x.x/axis2/services/FIAPStorage/

大丈夫のようなので、いよいよデータ投入。

$ axis2-1.5.6/bin/axis2.sh -cp build/lib/FIAPStorage-test-client.jar kahnn.SampleFIAPApp http://test.kahnn/ps/point_int_1 100 2012-09-05T21:20:56.001+0900
....
Successfully uploaded 'http://test.kahnn/ps/point_int_1'='100' ...

例のごとく、「Sensors in this FIAPStorage」の画面で確認します。上手く登録できたようです。

ここまでできれば FETCH の方も簡単ですね。後は実際に使用する際に色々とやれば良さそうです。

PointID登録の仕様について

色々とさわっていたら、pointSetTree テーブルに存在しないPointIDを指定しても、データが登録できることに気づきました。PointIDが未登録でWRITEした場合、error(POINT_NOT_FOUNDとか)が返されると思っていたのですが、そうでは無いようです。

あらためて、ドキュメントを見直しても、このあたりの仕様についてはハッキリとしません。(やはり正式な仕様が必要なのでしょうかね)
それでも、SDK (IEEE1888SDK-20120617) に付属のドキュメント「IEEE1888 Storageとの通信仕様.pdf」(2011-09-04) を確認してみますと、「第6章 エラーの種類」に以下のように記載されています。

6.3. type=”POINT_NOT_FOUND”
  key 要素で id 属性により指定していたポイントが、サーバ側に存在しないことを示す。
  一点でも該当するケースがあれば、このエラーが返ることがある(その id 属性の読出
  しがトライされるまでは、必ずしもこのエラーが返るとは限らない)。

6.4. type=”FORBIDDEN”
  指定されたポイントへのアクセスが禁止されていることを示す。FETCH の場合であれば、
  key 要素の id 属性で指定したポイントの読出しが禁止されていることを意味し、WRITE 
  の場合であれば、point の id 属性で指定したポイントへの書込みが禁止されている
  ことを 意味する。通常は、クライアントが認証された上で、ポイントへの読出し・書込み
  権限の 検証が行われるため、現バージョンの東大版 IEEE1888 ストレージでは、この
  エラーが返ることはない。将来のために用意されている。

この説明からは、POINT_NOT_FOUND は query の場合に返される可能性のあるエラーで、WRITE で PointID の登録までは許さない場合は(将来的には)FORBIDDENが使用できるように思えます。
SDKで使っているStorageの参照実装では、使い勝手を考えて、特別な指定なしに任意のIDが登録可能なようにしているという事なのでしょう。

実際に参照実装(fiap-reference-201205)を確認しても、POINT_NOT_FOUND(に対応するPointNotFoundException) は、query時に指定された id が pointsettree テーブルに無い場合に返されるようですし、FORBIDDEN(に対応するForbiddenException)は定義されているけど使用されていないようです。org.fiap.storage 内のソースでは pointsettree に登録する部分も確認できました。やはり、無ければ追加する処理となっています。

データのクリーンアップ

まちがって登録してしまったポイントやデータを削除する場合は、SQL を使うしか無いようです。
pointsettree 以外のテーブルについては、pointeettree を親とする参照制約がついています。ですから、あるidとそれに紐づくデータを全部消したい場合は、子供から順番に削除する必要があります。 (テーブル作成時の REFERENCES 指定に ON DELETE CASCADE があれば、一気に消せるはずなんですが、残念ながらそうはなっていません。まあ、ALTERで制約をつけ直したり、最初からやり直す場合は、テーブル定義を最初から変更しても良いかもしれません)
試しに psql を使用して http://test.kahnn/ps/point_int_X を削除してみます。(これは Pointsetは存在しません)

gut_storage=# \set PID '\'http://test.kahnn/ps/point_int_X\''
gut_storage=# \set
...
PID = ''http://test.kahnn/ps/point_int_X''
...

gut_storage=# delete from pointValueLatest where id = :PID;
DELETE 0
gut_storage=# delete from pointValue where id = :PID;
DELETE 1
gut_storage=# delete from pointAttribute where id = :PID;
DELETE 0
gut_storage=# delete from pointSetTree where id = :PID;
DELETE 1

gut_storage=# select count(*) from pointvalue where id = 'http://test.kahnn/ps/point_int_X';
 count 
-------
     0

gut_storage=# select count(*) from pointsettree where id = 'http://test.kahnn/ps/point_int_X';
 count 
-------
     0

この要領で既存のデータを全て削除して、新しく追加した Point にデータを追加してみます。
このようにすっきりします。

次回

java も良いですが、スクリプト系でも一つ試しとくと、ちょっとした確認などで便利そうです。マニュアルにはサンプルがない python あたりでしょうか。

IEEE1888 SDKをMacで使う:構成確認篇

前回VMの環境設定でしたが、今回は、プログラミングの前にSDKの構成について確認します。

サービス構成

SDKの中核は FIAPStorage コンポーネントで、これに幾つかのツール群を加えてSDKとしています。
個々のツールの説明に関してはSDKのドキュメントに含まれますが、StorageについてはSDKとは別に配布されている FIAPStorage単体パッケージ内のドキュメントが構成の参考になります。具体的には FIAPStorage単体のダウンロード から最新のアーカイブ(私の時は FIAPStorage-20120428.zip でした)をダウンロードして展開、「FIAPStorageインストールマニュアル.pdf」がそれにあたります。

これを見ながら確認すると、FIAPStorage の本体は tomcat 上で動作する AXIS2 のサービスであることがわかります。そして、http のフロントエンドとして apache を置いています。ポート番号80番のトップページである「Sensors in this FIAPStorage」や FIAPSimpleSCADA は apache から起動される php のアプリケーションです。
個々のサービスと対応するURLは以下の通りです。(IPアドレスは各自読み替えてください)

Apache2のトップ:
  http://192.168.11.12/
  ドキュメントルート /var/www/ にある index.php が実行されます。
   (phpサンプルである「Sensors in this FIAPStorage」がコレ)

Tomcat6のトップ:
  http://192.168.11.12:8080/

AXIS2のトップ:
  http://192.168.11.12:8080/axis2/

apache経由で axis2 のサービスを実行するために、ajpapachetomcat を繋いでいます。

$ cat /etc/apache2/httpd.conf
<Location /axis2>
ProxyPass ajp://localhost:8009/axis2
</Location>

これで、例えば http://192.168.11.12/axis2/services/FIAPStorage?wsdl でサービスの WSDL が取得できるようになるわけです。

データベース構成

FIAPStorage ではポイントデータを登録・参照できます。そして、SDKの実装では、このデータ管理のために PostgreSQL を使っています。
そこで、実際にどのようなテーブル構成になっているか確認してみます。
(SDKに付属のドキュメントでは、このあたりの説明は見あたりませんでした。まあ、「中身」については今後変わる事もあるでしょうし、それに依存した作りのアプリを作られても困るので、わざと説明していないのだと思われます。)

テーブル定義

前述のFIAPStorage単体パッケージには gut_storage.sql というファイルが含まれており、これがテーブル定義です。もちろん、psql 等を使用して確認する事も出来ます。

$ sudo su - postgres
$ psql gut_storage

gut_storage=# \d
                リレーションの一覧
 スキーマ |       名前       |    型    |  所有者
----------+------------------+----------+----------
 public   | pointattribute   | テーブル | postgres
 public   | pointsettree     | テーブル | postgres
 public   | pointvalue       | テーブル | postgres
 public   | pointvaluelatest | テーブル | postgres

gut_storage=# \d pointsettree
     テーブル "public.pointsettree"
 カラム  |        型         |  修飾語
---------+-------------------+----------
 id      | character varying | not null
 parent  | character varying |
 ispoint | boolean           | not null

.......

とりあえず、各テーブルの中身を確認すると、SDKの場合には pointsettree, pointvalue の2つのテーブルしか利用していないように見えます。具体的には、PointSet および Point の登録と構成を管理するのが pointsettree テーブル、Pointの値を管理するのが pointvalue テーブルとなっているようです。
更にデータを見ていくと、それぞれのテーブル・カラムは以下のように意味づけされているようです。

pointsettree(ポイントセットとそれに紐づけられたポイントを管理するテーブル)

カラム名 内容
id ポイント(セット)IDが入る。 (ex. http://www.gutp.jp/dummy/)
parent 最上位のポイント(セット)の場合は null。そうでない場合は上位のポイントセットIDが入る。
ispoint ポイントの場合は true。ポイントセットの場合は false。

pointvalue(ポイントの値を入れるテーブル)

カラム名 内容
id ポイント(セット)IDが入る。 (ex. http://www.gutp.jp/dummy/)
time 設定時間。
attrstring 現在はすべて null。本来は値に関する属性情報を設定する?
value 実際の値が入る。

このような構成になっているので、例えばポイントIDの一覧取得をしたい場合は以下のようなSQLを使用すれば良いわけです。

gut_storage=# SELECT id FROM pointsettree WHERE ispoint=true;
....

SQLによる登録確認

これまでの解析が正しいか、実際にデータベースに値を登録して確認します。

まず、 pointsettree に登録することでポイントを追加します。

insert into pointsettree (id, parent, ispoint) \
    values ('http://test.kahnn/ps/', null, false);
insert into pointsettree (id, parent, ispoint) \
    values ('http://test.kahnn/ps/point_int_1', 'http://test.kahnn/ps/', true);

これで、トップページの「Sensors in this FIAPStorage」にポイント「http://test.kahnn/ps/point_int_1」が表示されるようになりました。ただし、値の方はありません。

次はポイントの値を登録してみます。

insert into pointvalue (id, time, attrstring, value) \
    values ('http://test.kahnn/ps/point_int_1', \
            to_timestamp('2012.09.04 00:11:22', 'YYYY.MM.DD HH24:MI:SS'), \
            null, 100);
insert into pointvalue (id, time, attrstring, value) \
    values ('http://test.kahnn/ps/point_int_1', \
            to_timestamp('2012.09.04 00:22:33', 'YYYY.MM.DD HH24:MI:SS'), \
            null, 200);

reload すると、最新の値が表示されました。

ポイントIDをクリックすると、chartが表示されます。確かに登録した2つの値が使用されているようです。

次回

これで、SDK(FIAPStorage)のおおよその構成がわかったので、次回は、今回追加したポイントに対してプログラムで値をWRITEする事をやってみます。まあ、ここまでくれば、後はサンプルの手順どおりにやれば良いはずなので大したことはやらないです。(予定)

IEEE1888 SDKをMacで使う:環境設定篇

前回はIEEE1888SDKのVMを起動するまでをおこないましたが、今回はVMの環境設定です。人によっては全く必要の無い作業となります。

キーボード設定

日本語キーボードの設定になっていますが、私の場合は英語キーボードなので変更します。Ubuntuのメニューから以下のように辿って、キーボード設定ダイアログを表示します。
・システム -> 設定 -> キーボード

レイアウトタブで、キーボードの型式を「Apple, MacBook/MacBook Pro(Intl)」に設定。
続けて、レイアウトの追加(A)...で、国をアメリカ合衆国、系列をUSAに設定。この追加した設定「USA」を「日本」の上に移動します。

アップデートマネージャの設定変更

外部に公開するとかでなく個人で試すだけならば、セキュリティに気を遣うよりも、下手にアップデートして動かなくなる方が嫌なので、「アップデート・マネージャ」の自動更新設定は止めてしまいます。
メニューから以下のように辿ってアップデート・マネージャを起動。
・システム -> システム管理 -> アップデート・マネージャ

設定ボタンを押して、設定ダイアログを表示。アップデートタブで全てのチェックを外してしまうことで、自動チェックをおこなわないようにします。

SSHのインストール

gnome上で作業するのも良いのですが、Macからアクセスできるように、sshをインストールします。

$ sudo aptitude install ssh
$ sudo /etc/init.d/ssh restart

これで、MacのTerminalからログインして作業可能です。

$ ssh gutp@192.168.11.12
gutp@192.168.11.12's password: 
gutp@ubuntu:~$ 

CUIモードへの変更

使っているのが MacBook Air なので、あまりリソースが潤沢にあるわけでは無く、sshでのアクセスも可能になったので、GUIを止めてしまいます。止める事が可能なサービスは他にもあるでしょうが、細かく追求はしません。Serverとしてちゃんと設定したいなら、Ubuntu Server版とか CentOS等に入れ直した方が良いでしょうし。以下の設定だけでも、100MB以上のメモリ節約が可能です。

# Grubの設定変更, text設定をおこなう。(splashを外すのは好み)
$ cp /etc/default/grub ./grub.original
$ sudo vi /etc/default/grub
$ diff ./grub.original /etc/default/grub 
9c9
< GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
---
> GRUB_CMDLINE_LINUX_DEFAULT="quiet text"

# GRUB設定の反映。
$ sudo grub-mkconfig -o /boot/grub/grub.cfg

# 再起動
$ sudo shutdown -r now

Storage SDK ダミーデータ投入機能の停止

SDKではFIAPDummyDataGeneratorがセットアップされていて、定期的にダミーデータを投入するようになっています。自分で色々とやる場合は邪魔な側面もあるので、止めてしまいます。

# ドキュメントでは cron で設定しているとの記述があったので、crontab の確認。
gutp@ubuntu:~$ sudo su -
root@ubuntu:~# crontab -l
# m h  dom mon dow   command
* * * * * /usr/local/dummy/FIAPDummyDataGeneratorWatchDog.sh

# この設定を削除
root@ubuntu:~# crontab -r 
root@ubuntu:~# crontab -l
no crontab for root

# crontab に登録されていたスクリプトは、FIAPDummyDataGenerator 本体が
# 動作中かどうか確認し、停止していたら再起動するためのもの。 (WatchDog)
# したがって、すでに起動中の FIAPDummyDataGenerator があれば停止させる。
root@ubuntu:~# /bin/ps auxwww | /bin/grep FIAPDummyDataGenerator | /bin/grep php
root      1176  0.0  1.4  23592  7608 ?        S    22:40   0:00 /usr/bin/php /usr/local/dummy/FIAPDummyDataGenerator.php
root@ubuntu:~# kill 1176

ここまでで、とりあえずの環境設定については完了です。
次回は、SDK(プログラム)の構成と、ポイントの取り扱い方法(DBMSにおける)について確認してみます。

IEEE1888 SDKをMacで使う:VM起動篇

前回はIEEE1888プロトコル教科書を読んだわけですが、せっかくSDKが用意してあるのだから動かしてみる事にします。
ですが、SDKVmware のイメージで提供されています。私が使っているのは Macで、有料の VMware Fusion は持っていません。そこで、無料で利用可能なVirtualBoxで動かします。

環境

使用した環境は以下の通りです。普通にダウンロードしてインストールします。

仮想マシンの登録

VirtualBoxを起動し、以下の手順で仮想マシンを登録します。

  1. 「新規」を選択。新規仮想マシンの作成ウィザードを開く。
  2. 仮想マシン名とOSタイプを入力。「名前 -> IEEE1888SDK」「OS -> Linux」「バージョン -> Ubuntu」とする。(名前は任意)
  3. メモリ量を指定。「メモリ -> 512MB」とする。
  4. 仮想ハードディスクの設定画面で「既存のハードディスクを使用(U)」を選択。ハードディスクを選ぶ必要があるが、ここでは、SDKを展開して得られるVirtual Machines の中にある IEEE1888SDK.vmdk を選択。(ファイル名IEEE1888SDK-s00x.vmdkの方ではない)

これで登録が出来たので起動できます。
あとは、利用環境や何をしたいかによりますが、私の場合はネットワーク設定を bridge にしました。それ以外はデフォルトのままです。

起動


特に問題もなく立ち上がりました。
IPアドレスは、我が家の環境では 192.168.11.12 に割り当てられました。
Mac(ホスト)の方から、http://192.168.11.12/ にアクセスすると、Sensors in this FIAPStorage のページが表示されました。正しく起動しているようです。

VMWare-tools のアンインストール

このままでも、とりあえずの動作には支障が無いようですが、必要が無いものを入れとくのも何なので VMWare Tools を削除します。

$ sudo /usr/bin/vmware-uninstall-tools.pl

念のために 再起動します。

これから色々とさわってみます。

「落合秀也. スマートグリッド対応IEEE1888プロトコル教科書. インプレスジャパン. 2012」を読んで

IEEE1888が話題になり調べる事になったのですが、「1888-2011 - IEEE Standard for Ubiquitous Green Community Control Network Protocol」経由で仕様書を購入して読み込む程でもなかったりして、どうしようかと思ったらちょうど良いタイミングで本書が出版されていたようなので読んでみました。

本の概要

「まえがき」には以下のように書かれています。

東大グリーンICTプロジェクト(GUTP:Green University of Tokyo Project)が研究開発において重要な役割を果たし、2011年2月にIEEEによって国際標準技術として認められたスマートグリッド向けの新プロトコルIEEE 1888-2011(UGCCnet)」(略称:IEEE 1888)の全体像とその活用事例、そして開発に必要な技術や方法論を解説したものです。

この、「開発に必要な技術や方法論を解説」というところがポイントになっています。実際には元々公開されている情報も多い*1のですが、これ一冊で概要から実際の導入まで一通りの情報をまとめているのはありがたい事です。

本書の構成は以下のようになっています。

第1章 Q&Aで学ぶIEEE1888の基礎知第識(19Page)
Q&A形式でIEEE 1888がどのような技術なのか等の概要が書かれています。FAQを最初に持ってきたイメージです。
第2章 本格的なスマートグリッド/グリーンICT時代を支えるIEEE1888技術(25Page)
これまでの計測・制御システムの歴史を振り返りながら、なぜIEEE1888かについて開設されています。一般的な技術書だと、これが第1章になりますね。
第3章 IEEE1888の通信規格:アーキテクチャ編(21Page)
IEEE1888システムが、BEMSで必要な要素をどのようにモデリングしているか、各モデル要素がどのように連携(通信)するか、について解説されています。本書の最大のポイントはここでしょう。正式な仕様書には当然書いてあるのでしょうが、公開されている情報だけ見てると今一つ解りにくかった「実デバイス<->ポイント<->コンポーネント」の関係がわかってすっきりです。
第4章 IEEE1888の通信規格:データフォーマット編(26Page)
コンポーネントレジストリ間での通信フォーマットが要素ごとに解説されています。具体的な例が示されますが、名前空間を含めたXMLの知識が無いと読むのはきついかもしれません。
第5章 IEEE1888システムの設計および構築の基本(16Page)
具体的なシステム構築を行う際の基本的な流れや注意点が解説されています。ここも参考にはなりますが、基本的な部分だけなので過大な期待は禁物です。
第6章 IEEE1888ソフトウェア開発キット(SDK)を使った開発(57Page)
公開されている IEEE 1888ソフトウェア開発キット(SDK)の解説です。内容的には SDKのドキュメント(セットアップマニュアル、スタートアップマニュアル、プログラミングスタートアップマニュアル)とほとんど同じで、かつ、説明しているSDKのバージョンは最新版と比較すると少し古いので、その辺りは適宜読み替えが必要です。また、当たり前ですがソースコードを読める人でないと、どうにもなりません。紹介されているコードは C#, Java, PHP です。
第7章 IEEE1888組込み通信ボードによる高速プロトタイピング(21Page)
IEEE 1888の組込み通信ボードを紹介し、これを用いたプロトタイプシステムの開発実例が解説されていますが、ここはちゃんと読んでません。
第8章 IEEE1888参照コードの読み進め方(25Page)
前述のSDK配布ページとと同じ場所から入手できる、IEEE 1888の参照実装(ほぼJava)の解説です。BSDライセンスのようなので、これをベースに開発もありですね。
第9章 IEEE1888のセキュリティを強化するために(7Page)
IEEE 1888.3として標準化作業が進められている、セキュリティ対応の概要が解説されています。ここは最も興味があったのですが、まだまだですね。直ぐにでも商用として展開したい場合は、このあたりをどうするかが考えどころですかね。
付録 IEEE 1888(FIAP) ソースコード例(62Page)
第7章で取り上げたIEEE 1888通信ボードの実際のプログラム例(ソースコード)が掲載されています。ですが、これは必要だったんですかねえ? ちゃんと見てませんが、上述の配布ページから同じものが入手できそうな気配ですし、今時、延々と紙でソースコードを読みたい人がどれくらいいるのか疑問です。値段は今のままでも構わないので、削ってもらった方がページ数が減って持ちやすくなるので歓迎です。

以上、否定的なことも書きましたが、なんだかんだ言っても、IEEE1888の仕様書を購入して読み込むよりはずっととっつきやすい(はず)です。少なくともプロトタイプ作成くらいまでは、この一冊で何とかなりそうに思います。

著者について

著者は実際にIEEE1888(FIAP) - 東大グリーンICTプロジェクトでも活躍されていたようで、現在は東京大学助教をされているようです。監修にはGUTPの代表である江崎浩さんですから、まさに当事者が書いていると言ってよいかと思います。

どんな人向けなのか

IEEE1888について知りたいという人であれば、とにかく読めばよいかと。
概要から実装の話までが一冊にまとまっているので、読む人の目的によって読む箇所は違ってくると思います。企画・営業系でしたら前半だけでも良いし、開発者であればむしろ後半でしょうし。
ただ、規格が「IEC」ではなくて「IEEE」なんですよね。今はフィールドの制御ネットワークもIPをベースとしたオープン化に進んでますが、こっちは完全にインターネット系の技術を基盤とした話になってます。技術者でも、「通信のレイヤーモデル」「HTTP」「XML」と聞いて、大体どんなものかを知っていないで読むのはつらいでしょう。

電気の話はあまり出てこない*2ので、インターネット系の技術に関わっている人がBEMSにおける制御ネットワーク(IEEE1888にかぎらず)の知識や開発に必要な要素を知りたい場合に、最も役立つような気がします。
逆に、電気系の設備をやってて、これからはオープンなネットワークでつながって制御される、とか言われた時にネットワーク側がどうなるかを知りたい際にも役立つとは思うのですが、前述のように「予習」はいると思います。

得られるメリット

教科書と言っていますが、実用書の側面も持っています。
これまで書いたように、以下のような疑問が解けるかもしれません。

  1. IEEE1888はこれまでの制御ネットワークとどう違うの?
  2. IEEE1888ではどんな範囲をサポートしているの?
  3. IEEE1888では今後どのような事を決めていくの?
  4. IEEE1888に準拠したシステムでは制御機器側はどんな対応が必要なの?
  5. IEEE1888に準拠したシステムを作って監視に役立てたいけど、どんなことが必要なの?

キーワード

色々あるのですが、スマートグリッドとか言ったらなんでもありで良くわからなくなってしまいます。挙げるとしたら「BEMS」ですかね。(他にもあるけど、ちょっと絞りきれない)
興味はあるし公開されている情報は見たけどピンとこない、という方は、それほど量のある本でもないので、まずは手に取ってみるのが良いかと思います。


*1:もちろん、再編集だって手間はかかりますし執筆期間短縮のためにも正解です。

*2:もちろん全く知らないわけにはいきませんし、業務レベルでは必要でしょうが、この本を読む際にはたいした知識は必要ないです。

金星樹[佐藤史生]

第1弾の時は半信半疑でしたが、無事、第2弾が発売されました。どこまでいくのか不安と期待がありますが、今はただ楽しみたいです。

奇想天外社版との比較

新潮社版は持ってないので、奇想天外コミックスと比較してみます。


外観は復刊ドットコムの方が、やや落ち着いた感じ。奇想天外社版ではトリミングされていたイラスト全体が見られるのは嬉しいところ。
構成の方も新潮社版をベースにして、奇想天外社版にあった萩尾望都氏の解説、未発表のカラーイラスト、「花咲く星々のむれ」2色(!)カラーページ収録という正に完全版になっているので、ファンの人ならば買い直すのもありだと思います。(奇想天外社版にあった伊東愛子さんによる著者近影は無いんですけどね、さすがに)

他には、幾つかのセリフが変更されたりもしているようです。例えば「花咲く星々のむれ」の中で、宋先生がアデライルの過去について説明する場面があります。奇想天外社版では「そこからひきだされたショックから立ちなおるのにアディルは八年かかった/自閉症失語症/退行・・・」なのですが、今回は「そこからひきだされたショックから立ちなおるのにアディルは八年かかった/言葉を忘れ自らの内に閉じこもった」となっています。(新潮社版ではすでに変更されていたのでしょうかね?)
奥付には「本書は原稿を元に、再編集しました。原稿の内容をそのまま収録しているため、奇想天外社版、新潮社版と一部内容が異なる部分があります。」とあるので、経緯はどうあれこれが最終形ということになるのでしょう。

星樹

あらためて読むと、やはり表題作が一番完成度が高いなあと。
この作品は「美亜へ贈る真珠、梶尾真治(1971)」との類似性を言われたりしますけど、ストーリーは全く違います。年代的にみて佐藤先生が読んでいるのは間違いないところだと思いますが、特に言及していません(と思う)。あとがきには「若かりし私が感涙にむせんだ、古き良きハッピーエンドSF感というものを描きたかった」とあるので、時間に引き離された恋人どうしを書くにしても、むしろ、こうだろうという思いはあったのかもしれません。

そしてこの作品、奇想天外社版との違いが最も大きい作品でもあります。月刊フラワーズのインタビューアーカイブには、「20世紀名作招待席」として『金星樹』が掲載された際のインタビュー(2001.7)が載っていて、その中には以下のやりとりがあります。

Q3.今回のPF版で手を加えた所はありますか。

加筆はほとんどしていません。トーンなど効果を加えました。

小学館コミック -フラワーズ-

今回は、PFに掲載する際に修正された原稿が採用されていると思われます。それが良くわかるカットを一つ。最初の方が奇想天外社版です。

多くのページに修正が入っており、比べてみると奇想天外社版は随分と白い(笑)ものに見えます。まあ、こんな違いを見るのも楽しみだったりするわけですけどね。

他にも、トリミング(?)の違いがあります。これは元原稿の違いでは無いと思いますので、編集の違いという事になるのでしょうか? それが、良くわかるのは表紙です。これも最初の方が奇想天外社版です。

比べてみるとわかりますが、今回は、奇想天外社版ではトリミングされていた側面までをちゃんと見る事ができるようになっています。ただ、常に今回の方が全体を見られるようになっているかというと、そうでもなくて、奇想天外社版の方が(ほんの僅かですが)側面がトリミングされずに残っていたりするページもあります。こういうのは、何かポリシーがあるんでしょうかね? ファンとしては悩ましいです。

今後の話とか

さて、なぜ「金星樹」が<佐藤史生コレクション>第2弾に選ばれたかと言えば、復刊ドットコムの復刊リクエストでも上位にあることが大きいんでしょう。復刊の容易さ(画集や共著は大変そう)からすると、「この貧しき地上に」が次の復刊候補になるのでしょうか?
「佐藤史生」(著者)のリクエスト一覧
もちろんそれも良いのですが、やはりリクエスト数でダントツ1位となっている「竜の夢その他の夢 <夢みる惑星ノート>」に「竜の姫君」を追加収録して出してほしいですね。両方持ってはいますが、これはまとまって1冊になっているべきだと思うんですよね。期待してます。

護るべきもの − 石垣の祭りアンガマーの場合

連日の暑さには嫌になるけど、ガッツリと汗をかいてから冷たい水でシャワーを浴びる気持ちよさも捨てがたい今日この頃。ふと、友人から聞いた石垣の祭りの話を思い出した。

その祭りアンガマー(八重山地方全般であるようだけど)については探せば色々と見つかるけど、石垣島発 私設かってに観光協会 アンガマ隊が行くから引用。

アンガマ−は、あの世からの使者であるウシュマイ(お爺)とウミー(お婆)が子孫(ファーマー)と呼ばれる花子を連れて現世に現れ、石垣島の家々を訪問、珍問答や踊りなどで祖先の霊を供養するという八重山独特の旧盆行事だ。

石垣島発 私設かってに観光協会 アンガマ隊が行く

その起源や南方諸島あるいは中国との文化的交流の跡など、興味深いところは色々とあるのだけれど、何が面白いといって「子孫(ファーマー)と呼ばれる花子たち、なぜか、みんなマスクとサングラスで顔を隠し、なかなか怪しい行列なのです。」に勝るところは無い。伝統行事でサングラス、こんなのありなの?変じゃない?

友人からすると、こういうところに沖縄の柔軟な合理性があると言う。「元々、祭りで大事なことは何か、ということだよ。」「この祭りでは花子たちは顔を隠し誰かわからないようにすることが必要で、それは花子という踊り手の正体が何者か、という祭りの構成に関わる大事なんだ。」「そして、その根本が達成されるならば、手段について細かい事は言わないんだ。」「それって伝統を守りながらも自由だよね。」

***

「北海道人」情報メールマガジン内にある【若月元樹の『南の島から――沖縄県黒島の日々』】第12回には以下のようにある。

アンガマーの最中、唄者(うたしゃ)以外は裏声しか発してはならない。なぜならば、仮装した青年たちは「精霊」であって、「この世の者ではない」からである。サングラスは現代風であるが、昔は「ミーカガン」と呼ばれる木製の水中メガネを装着して踊っていたらしい。

「北海道人」情報メールマガジンバックナンバー第82回:北海道人

つまり、生者が花子という精霊を演じるにあたって「誰だかわからなくすることでこの世の者ではない事を表現」し、「その手段は時代によって適切なものに変わっていく」という祭りなわけだ。

前者については、そもそも伝統的な祭りでは、神話や伝説化した偉人(これも一種の神ですね)の業績を再現する形のものが多いけど、生者がそのままで神になれるはずが無いので、憑かせるためにはそれなりの「舞台装置」が必要という事で一般的な考え方だと思う。
やはりユニークなのは後者で、「手段は時代によって変わって良い」し、それが「サングラス」であっても問題ない、とする心のあり方が柔軟で合理的なんだと。良い意味での「適当さ」というところもあるんだろうけど、「型」ではなく「本質」を守ろうとしている点で、より伝統に忠実とも言えるんだと。そういう事を友人は話してくれたわけです。


そんな事を思い出しながら東京の日射しの下で歩き回り、久しぶりに沖縄に行きたいなあと思った一日でした。