BACnet Stack による BACnet 制御

オープンソースのプログラム BACnet Stackを使った、 BACnet IP による具体的な制御方法を、 実在のエアコンと BACnet server の組み合わせを例に解説します。 (注 1)

1. WhoIs requeset - 利用可能な Device ID の検出

BACnet による制御の最初の仕事はWhoIs/Iam Serice を使った、 利用可能な Device (BACnet interface) の検出と確認ですが、 BACnet IP では UDP port 47808 (0xBAC0) だけを使う設計になっていて、 Whois Service Request を使って、 制御可能なすべてDevice から I-Am という応答が得られます。

例えば、BACnet Stack の場合は、

  bacwi
を実行すると、
Interface: re0
IP Address: 192.168.3.5
IP Broadcast Address: 192.168.3.255
UDP Port: 0xBAC0 [47808]
Received I-Am Request from 1, MAC = 192.168.3.80.186.192
;Device   MAC (hex)            SNET  SADR (hex)           APDU
;-------- -------------------- ----- -------------------- ----
  1       C0:A8:03:50:BA:C0    0     00                   1024 
;
; Total Devices: 1
といった結果が得られて、現在、利用できるのは Device ID 1 だけで、 IP Address:Port は 192.168.3.80:47808 だということがわかります。

BACnet Stack のコマンドは必要な情報を UNix の stdout、説明や注釈を stderr に出力するので、awk などで処理するときは (FreeBSD の /bin/sh なら)

  bacwi 2>/dev/null | awk '/^[^;]/ { print substr($0, 2); }'
など、stdout の出力だけを処理するようにします。

通常、Device ID の値はシステム設計時点で設計者が決めますが、 仕様書に明記されていなくても、Whois で見付けることができます。

Device ID の割り当て範囲が 1 から 99 までなどと、わかっている場合は、 「bacwi 1 99」と探索範囲を制限することもできます。

2. Object の Type と Property

BACnet の制御では、DeviceID を持つ BACnet server が管理する 個々の(現実の)制御対象機器が持つ、TypePropertyInstance の概念が重要で、 BACnet では、Object (制御対象) を Type (データ型) と Property (特性用途) の 2 側面で分類し、それらの組み合わせを、 個々の Instance (現実の制御対象) に結びつけます。

2.1 Object Type

Object Type (Object 型) は、当初の規格 BACnet2004 では 25 種類でしたが、 BACnet2016 で 60 種類に拡張されました。

制御で必要になる Object Type ID (0, 1, 2, .. 1023) の値のうち 0 - 127 が ASHRAE 規格で予約され、 128-1023 の範囲につては利用者が使えます。

この解説の範囲では、下記の Object Type が良く使われます。

ID    名称     : 用途(Instance 制御対象) 例
------------------------------------------------------------------------------
 0 Analog-Input: 室内温度計測値、風向レベル(状態)
 1 Analog-Output:
 2 Analog-Value: 室内温度設定値、風向レベル(状態)
 3 Binary-Input: 発停(設定)、警報信号、フィルタサイン状態、強制サーモOFF(状態)、
	省エネ運転指令(状態)、サーモ状態、圧縮機状態、室内ファン運転状態、
	ヒーター運転状態、通信状態
 4 Binary-Output: 発停(状態)、強制サーモOFF(状態)、省エネ運転指令(状態)
 5 Binary-Value: フィルターサインリセットリモコン設定(発停/運転モード/設定温度)、
	下位集中操作システム強制停止
 8 Device: BACNETデバイス自体
13 Multistate-input: 運転モード(状態)、異常コード、風量レベル(状態)、
	換気モード(状態)、換気量(状態)
14 Multistate-output: 運転モード(設定)、風量レベル(設定)、換気モード(設定)、
	換気量(設定)
15 Notification-Class: 警報通知先情報
23 Accumulator: 積算電力量、積算ガス量
76 Object-list: サポートしている Object のリスト (Property Identifire と Type)
77 Object-name: 「DAIKIN MasterStation III No 1IDmin IDmax」などの製品名

Object Type の用途は機器によって異なります。 この用途例は DAIKIN のエアコンの例です。

Multistate というのは離散値で、例えば、風量制御なら 0(弱), 1(強), 2(急) という リモコンの風量段階を整数値で表現するときに使います。

2.2. Object Property

同じ Object Type でも、現在値として使われたり、上限値として使われたり、 使用目的と意味はいろいろですから、 Object Property で Object の用途や意味を限定します。

Object Property は BACnet 規格で、0 - 511 までが予約、 512-4194303 は利用者が使えます。 ASHRAE 規格では「21 FORMAL DESCRIPTION OF APPLICATION PROTOCOL DATA UNITS」、 BACnet Stack では include/bacenum.h の BACNET_PROPERTY_ID に記述されています。

実にたくさんあるのですが、この解説の範囲内で、よく使われるものを例示すると、 下記のようになって、最も重要なのは Present Value (現在値) です。

 ID Property      : 用途(Instance 制御対象) 例
-------------------------------------------------------------------------
  8 All           : 全て
 22 Cov Increment : COV 通知をした Present Value 値と現在の Present Value 値の差が、この値を超えると COV 送信する
 36 Event State   : 正常/上限異常/下限異常/故障などの警報状態
 35 Event Enable  : Event State の変化時に Event 通告を行うかどうかの設定
 45 High Limit    : Present Value がこの値を超えると上限異常状態と判断
 59 Low Limit     : Present Value がこの値を下まわると下限異常状態と判断
 52 Linmit Enable : 上限異常/下限異常の監視を行うかどうかの設定
 85 Present Value : 温度の設定値、温度の測定値
103 Reliability   : NoFaultDetected なら Present Value は正常値
105 Requierd      : 必須
110 Status Flags  : 警報中/故障中/メンテナンス中などの現況
113 Time Delay    : Present Value が警報値を超えてから、警報と判断するまでの時間

COV は Change Of Value (状態変化) の略語で通報に使われ、「Cov Increment」は過度の通報を防ぐのが目的です。
Property はビル管理の空調、照明、電気、防犯、防災、 衛生など多様な領域で必要になる特性を網羅していますから、 それらの一部をカバーする実際の機器がすべてに対応する必要はなく、 全ての機器に必須の R(Required) と書き込み可能な W(Writeable) と、 機能拡張用としての O(Optional) に分類(クラス分け)されていて、 個々の設備や機器が対応する Propery は、ごく一部になるのが普通です。

3. Device の BACnet プロトコル実装の把握

現実の機器の設計者は、BACnet の制御対象となる Instance (実際の制御対象) に独自の Instance ID (1, 2, 3, ..) を割り当て、それらが持つ Object Type ID と Object Property ID がわかるような PICS (Protocol Implementation Conformance Statement (プロトコル実装適合性仕様書) を作成提示し、 その電子版である bacepicsEPICS (PICS の電子データ) を BACnet で取得できるようにしなければならないことになっています。

BACnet Stack の場合は、bacepics で Device に実装された BACnet 機能を網羅した EPICS file の作成ができて、 例えば、Device ID が 1 なら、

  bacepics 1
を実行すれば、XML 形式のデータが表示され、Device 1 に実装された BACnet 機能の すべてがわかります。(注 2)

例えば、「BACnet Standard Application Services Supported:」で BACnet Service としては

 Subscribe-COV
 Add-List-Element
 Remove-List-Element
 Read-Property
 Read-Property-Multiple
 Write-Property
 Write-Property-Multiple
 Device-Communication-Control
 I-Am
 Time-Synchronization
 Who-Has
 Who-Is
 UTC-Time-Synchronization
がサポートされていることがわかりますし、 「Standard Object-Types Supported:」で
 analog-input
 analog-value
 binary-input
 binary-output
 binary-value
 device
 multi-state-input
 multi-state-output
 notification-class
 accumulator
の Object-Types がサポートされていることがわかります。

また、「List of Objects in Test Device:」を見ると、 Object Instance の詳しい内容がわかります。 例えば、BACnet 制御に必要な ObjectID, ObjectType と 割り当てた制御対象名をまとめて見ると、次のようになっています。

InstanceID TypeID(type) InstanceName_XXX
----------------------------------------------
Device 1 DAIKIN MasterStation III No 1 (D-BACS BACnet Gateway)
 1 4(binary-output) StartStopCommand_000
 2 3(binary-input) StartStopStatus_000
 3 15(notification-class) Intrinsic
 4 13(multi-state-input) MalfunctionCode_000 [512]
 5 14(multi-state-output) AirConModeCommand_000 [5]
 6 13(multi-state-input) AirConModeStatus_000 [5]
 7 14(multi-state-output) AirFlowRateCommand_000 [4]
 8 13(multi-state-input) AirFlowRateStatus_000 [4]
 9 0(analog-input) RoomTemp_000 (degrees-celsius)
10 2(analog-value) TempAdjust_000 (degrees-celsius)
11 3(binary-input) FilterSign_000
12 5(binary-value) FilterSignReset_000
13 5(binary-value) RemoteControlStart_000
14 5(binary-value) RemoteControlAirConModeSet_000
16 5(binary-value) RemoteControlTempAdjust_000
17 5(binary-value) CL_Rejection_000
18 23(accumulator) GasTotalPower_000 (cubic-meters)
19 23(accumulator) ElecTotalPower_000 (kilowatt-hours)
制御対象名の「_XXX」は装置番号で、同じ機器を複数使うとき、 機器の識別に使います。

XML 形式はコンピュータ処理に適していますので、awk などのプログラミング言語に よる簡単な script で必要な情報を人間が見やすいように表示することができますし、 BACnet 機器のテストの自動化にも使われています。(注 3)

InstanceName_XXX から InstaneID, TypeID がわかると、 BACnet による現実の Object の制御ができますの、 以下、よく使われるケースについて、具体的に説明します。

4. ObjectInstance の読み出し

実測値や設定値など、Object の状態を読み取る場合は BACRP (Read-Property) を使います。

 bacrp DeviceInsrance ObjectType ObjectInstance PropertyID [Index]
    DeviceInsrance: Device ID (0, 1, 2, ..)
    ObjectType: ObjectTypeID (0, 1, 2, ..)
    ObjectInstance: 機器固有 (1, 2, 3, ..)
    Property: Property ID (0, 1, 2, ..)
    Index: 配列の場合 (省略すると全要素を表示)
例えば、
  bacrp 1 0 9 85	# 室内温度を読み出す
  bacrp 1 2 10 85	# 設定温度を読み出す
  bacrp 1 13 8 85	# 設定風量を読み出す
  bacrp 1 13 6 85	# 運転モードを読み出す
  bacrp 1 3 30 85	# 室内ファンの運転状態を調べる
  bacrp 1 3 28 85	# サーモ状態を調べる
  bacrp 1 3 29 85	# 圧縮機運転状態を調べる
  bacrp 1 3 11 85	# フィルタ使用限度信号を調べる
なお、複数の ObjectInstance を読み出すための Read-Property-Multiple request を使った bacrpm もあって、
bacrpm 1 2 10 85, 1 9 85
といった使いかたとか、
bacrpm 1 8 1 8  .. 最初の 8 は device, 2 番目の 8 は全 PROPERTY の全ての意味
bacrpm 1 8 1 105  .. 8 は device, 105 は REQUIRED PROPERTY の全ての意味
bacrpm 1 8 1 80 .. 80 は OPTIONAL PROPERTY の意味
といった使いかたもあります。

5. ObjectInstance の書き込み

Object の制御は BACWR (Write-Property) を使います。

  bacwp DeviceInsrance ObjectType ObjectInstance Property priority index tag value [tag value ..]
    DeviceInsrance: Device ID (0, 1, 2, ..)
    ObjectType: ObjectTypeID (0, 1, 2, ..)
    ObjectInstance: 機器固有 (1, 2, 3, ..)
    Property: Property ID (0, 1, 2, ..)
    priority: 優先度 (0, 1, 2, .. 16) 0 なら無視、1 が最高、16 が最低レベル。
    Index: 配列の場合 (-1 なら無視)
    MAX_BACNET_APPLICATION_TAG = 16,
    tag: value の変数型 (下記参照)
    value: ObjectTypeID に書き込む値 (この値の型を tag で指定する)

   tag : tag が意味する型
  -------------------------------------
    0: NULL (null)
    1: ブール値 (Boolean: true/false)
    2: 正整数 (Unsiged: non-negative integer)
    3: 符号付整数 (Integer: full-range inaeger)
    4: 実数 (Real: single ptecision floaing point)
    5: 32 bit 実数 (Double: double precision floating point)
    6: 2 進数 (OctetString: binary data)
    7: 文字列 (String: unicode character string)
    8: ビット列 (BitString: collection of bit identifires concatenated into pne string)
    9: 列挙型 (Enumerated: string from restricted set, or number)
   10: 日付 (Date: Gregorian date)
   11: 時刻 (DateTimePattern: Gregorioan date and time)
   12: ObjectID (ObjectIdentifier: Object Identifire (type, instance)
   13: 予約 
   14: 予約 
   15: 予約 
bacwp が書き込む値の曖昧さを避けるために使われるもので、 tag の値(ID)は BACnetStack の include/bacenum.h の BACNET_APPLICATION_TAG で定義された値です。例えば、value が実数なら 4 を使います。

なお、現在の ANSI/ASHRAE Arandard 135-2012 では、Link, DatePattern, DateTimePattern, TimePattern, ObjectIdentifirePattern, WeekNDay が追加されました。

value は tag で指定した型の値を、c などのプログラミング言語で使われる ASCII 表記、例えば、実数の 100.0 なら「100.0」の文字列、 Boolean 型の場合は、「0」(false) と「1」(true .. 0 以外の値はtrue) の整数を記述ます。

例えば、DAIKIN のエアコンの例だと、次のようになります。

  bacwp 1 2 10 85 16 -1 4 24	# 設定温度を 24℃にする
  bacwp 1 14 7 85 16 -1 2 3	# 設定風量を 3 (強)にする
  bacwp 1 14 5 85 16 -1 2 2	# 運転モードを 2 (暖房)にする
  bacwp 1 4 1 85 16 -1 1 1	# 運転を開始にする (最後の 1 が 0 なら停止)

6. 時刻同期(設定)

BACnet Device の時刻同期には BACnet の Time Syncronization Request を使いますが、BACnetStack では bacts を使って、例えば

  bacts --mac 192.168.3.80:47808
    とか
  bacts --mac C0:A8:03:50:BA:C0
で DeviceID 1 のすべての機器の時刻が、実行したコンピュータの時刻になります。 Unix の場合は crontab(5) で 1 日 1 度とか実行させておけば、エアコンのリモコン を含めて、正確な時刻を表示するようになります。

7. WhoHas requeset

WhoIs は BACnet インタフェースを持つ Device を見付けましたが、 WhoHas は特定の object-instance(ID) あるいは object-name を持つ Decice を見付けます。

例えば、bacwh objet-type object-instance の構文で、

  bacwh 3 2
を実行すると、
Interface: re0
IP Address: 192.168.3.5
IP Broadcast Address: 192.168.3.255
UDP Port: 0xBAC0 [47808]
I-Have: binary-input 2 from device 1!
が得られます。また、bacwh object-name の構文で、
  bacwh RoomTemp_000
を実行すると、
Interface: re0
IP Address: 192.168.3.5
IP Broadcast Address: 192.168.3.255
UDP Port: 0xBAC0 [47808]
I-Have: analog-input 9 from device 1!
が得られます。

8. BACnet 通信のモニタと解析

BACnet 通信のプロトコル解析には wireshark が便利です。 キャプチャフィルタに「udp and port (47808)」を指定すれば、BACnet の全ての 通信を捕捉して、BACnet のいかなるパケットかも表示してくれます。

また、Linux ではソースコードはありませんが、 Yabe (Yet Another BACnet Explorer download) も、 mono を使って、 Windows 用の Yabe.exe を動かすことができて、 BACnet の動作確認には便利です。FreeBSD の mono は未完成で使えません。

9. 注

9.1 注 1 - BACnet と BACnetStack

ASHRAE, ANSI, ISO で標準化され、空調、照明、電気、衛生、防犯、防災、入退出などのビル管理の広範な 分野の(コンピュータによる)自動化を、設備供給者の垣根を超えて、 統一されたコンピュータ操作で行おうという、野心的な通信プロトコル規格で、 1987.06 に開発が始まり、1995 年に ASHRAE/ANSI Standard 135 が完成。 その後も継続的に開発が続けられています。

これまでに開発された全ての Field Network を含有する設計で、現時点の ANSI/ASHRAE 135-2016 は 1364 ページになっています。

通信回線としては、RS-485 を使った BACnet MS/TP、 Ethernet(UDP/IP) を使った BACnet IP、ZigBee など、いろいろありますが、 ここでは、家庭内の LAN 接続で使える、BACnet IP に限定しますので、 通信は 47808 (0xBAC0) port を使った UDP のみになります。

BACnet の実装としては、オープンソースのプログラムもいくつかありますが、 この解説では embedded systems (組み込みシステム) 用に開発されてた BACnet Stack を使っています。

この ports ディレクトリには arm7, at91sam7s, atmega168, atmega8, bdk-atxx4-mstp, bsd, dos, linux, lwip, pic18f6720, rtos32, rx62n, stm32f10x, vrs51c1000, win32 向けのコードがあって、この bsd は Mac OS X を意味しますが、 ほんの少し書換えるだけで、FreeBSD で使えるようになります。 私自身は長年 FreeBSD を使っていますので、この解説は FreeBSD でのテストを 元にしています。

この解説では、BACnet Deice を制御するケースだけを扱っていますので、 BACnet Stack の一部の機能しか使っていませんが、 BACnet Stack 自体は制御される Device 自体を開発するためのソフトウェアも たくさんあって、doc/README.developer などに概要が記述されています。

また、この解説で使う実機は DAIKIN DMS502B1 (MASTER STATION III) と DAIKIN FHMMP50DB (室内ユニット) の組み合わせですが、 BACnet Stack の中にも bacserv という BACnet server のシミュレータが ありますので、それを使って実験することができます。 (bacrp, bacwp, bacepics などを実験する場合は、 por t 47808 の奪い合いを避けるため、 「bacserv 1」(1 は DeviceID) を同じネットワークの別の PC で実行しておきます。

9.2 注 2 - EPICS file

EPICS file の起源は 1980 年代末から開発されてきた EPICS (Experimental Physics and Industrial Control System) と呼ばれる、 物理実験装置などの制御システム構築を目的としたソフトウェアツールにあります。

この解説で使われた実機の EPICS は下記のようになっています。 「表示」はブラウザで見るとき、「ダウンロード」は awk などの script を自分で 書いて実験するときに使ってください。

EPICS 表示  |  EPICS download

9.3 注 3 - awk script の例

前記の「InstanceID TypeID(type) InstanceName_XXX」の作成に使った awk script 例です。

awk script 例 表示  |  awk script 例 download

平林 浩一, 2019.09, 2024.07.29