3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

BACnetプロトコルの装置からデータ収集

Posted at

BACnetとは

BACnet(バックネット)とは、ASHRAE(アメリカ暖房冷凍空調学会;アシュレ)などで標準化されたビルオートメーション用通信プロトコルです。
空調や衛生(給水・排水)、エレベータ、電気、防犯、防災(消火設備)などの装置間の通信において、広く利用されています。

もし、これらビル用装置からデータを取得したり、制御したりする場合、BACnetの知識が役に立ちます。
この投稿では、PythonライブラリであるBAC0を使って、BACnet対応装置と通信してみます。

Pythonライブラリ BAC0

BACnetプロトコルを実装したPythonライブラリとして、BACpypesが有名です。
しかし、データを取得するのには複雑なプログラムの記述が必要です。
そこで、もっとお手軽にデータ取得できるように、BACpypesをラッピングしたライブラリがBAC0です。

BAC0のインストール

Pythonが実行可能な環境で、以下のコマンドでインストールできます。

pip install BAC0

インストールし、以下のプログラムを書いて実行してみましょう。

import BAC0
print('BAC0', BAC0.version)

実行結果は以下の通りです。

BAC0 23.07.03

インストールしたBA0のバージョンが出力されました。
以上で、無事BAC0のインストールが完了したことを確認できました。

BACnetのデバイスを列挙

プログラムを実行する前に、あらかじめBACnetデバイスをネットワークに接続しておいてください。
ネットワークに接続する方法は様々ありますが、今回は簡単にBACnet/IPで接続しています。
つまり、スイッチングハブでPCとBACnetデバイスをイーサネット接続しています。

自身の端末をBACnetデバイスとして初期化し、ネットワークに参加します。

bacnet = BAC0.lite()

次に、同じネットワークに接続されたBACnetデバイスを探します。

bacnet.discover()
print(bacnet.devices)

私の環境における、出力結果は以下です。

出力結果
[('my-bacnet-device', 'my-vender-name', '192.168.0.248', 6367)]

出力された内容を表に整理します。

# 項目
1 デバイス名 my-bacnet-device
2 ベンダ名 my-vender-name
3 アドレス 192.168.0.248
4 デバイスインスタンス 6367

このうち、3「アドレス」と4「デバイスインスタンス」は、次のデバイス接続に必要です。
もしかしたら接続するBACnetデバイスにより出力される項目数が異なるかもしれません。

BACnetデバイスに接続

接続したいデバイスの「アドレス」と「デバイスインスタンス」を指定し、デイバスに接続します。

device = BAC0.device(address='192.168.0.248', device_id=6367, network=bacnet)

オブジェクトインスタンスのリストを取得します。

device.read_objects_list()

このデバイスは、6個のオブジェクトインスタンスを持つことが分かりました。

出力結果
[('device', 6367),
 ('networkPort', 1),
 ('analogInput', 0),
 ('analogOutput', 0),
 ('binaryInput', 0),
 ('binaryOutput', 0)]

では、このうちアナログ入力ブジェクトのプロパティを取得します。
bacnetのreadMultipleメソッドに引数として与える文字列は次の順番で記述します。

address object object_instance property

ここで、propertyをallとすると、指定したオブジェクトインスタンスのすべてのプロパティを取得できます。

bacnet.readMultiple('192.168.0.248 analogInput 0 all')
出力結果
[('analogInput', 0),
 'myAnalogInput',
 'analogInput',
 0.0,
 [0, 0, 0, 0],
 'normal',
 False,
 'liters',
 'hello world',
 'noFaultDetected',
 1.0]

出力された内容を表に整理します。

# 項目
1 Object Identifier ('analogInput', 0)
2 Object Name myAnalogInput
3 Object Type analogInput
4 Present Value 0.0
5 Status Flags [0, 0, 0, 0]
6 Event State normal
7 Out Of Service False
8 Units liters
9 Description hello world
10 Reliability noFaultDetected
11 COV Increment 1.0

このうちデータの値を表すのは4番目の「Present Value」です。
この場合は現在値が1.0を表します。

BACnetデバイスとデータを取得・設定

デバイス間で値の交換として多くの場合使われるのが、analogInput、analogOutput、binaryInput、binaryOutputです。
これらは現在の値を意味するpresentValueプロパティを持ちます。
presentValueプロパティをもつオブジェクトからpresentValueプロパティの値を取得するのが、以下のプログラムです。

device.points
出力結果
[my-bacnet-device/myAnalogInput : 0.00 liters,
 my-bacnet-device/myAnalogOutput : 1.00 percent,
 my-bacnet-device/myBinaryInput : False,
 my-bacnet-device/myBinaryOutput : False]

以下のようにオブジェクト名を指定しても可能です。

device['myAnalogInput']
出力結果
my-bacnet-device/myAnalogInput : 0.00 liters

逆に、BACnetデバイスのデータを変更するには、以下のように記述します。

device['myAnalogOutput'] = 2.0
device['myBinaryOutput'] = True

ちなみに、BAC0ではBACnetデバイスに接続した時点で、自動的に定期的にデータを収集しています。
デフォルトでは10秒ごとにすべてのデータを収集します。
収集したデータを出力してみます。

device['myAnalogInput'].history
出力結果
2024-02-24 15:50:22.588512+09:00    0.0
2024-02-24 15:50:46.295070+09:00    0.0
2024-02-24 15:50:56.744925+09:00    0.0
2024-02-24 15:51:07.195799+09:00    0.0
2024-02-24 15:51:17.626165+09:00    0.0
                                   ... 
2024-02-24 16:13:16.465508+09:00    0.0
2024-02-24 16:13:26.907661+09:00    0.0
2024-02-24 16:13:37.380533+09:00    0.0
2024-02-24 16:13:47.853849+09:00    0.0
2024-02-24 16:13:58.295078+09:00    0.0
Name: my-bacnet-device/myAnalogInput, Length: 134, dtype: float64

BACnetデバイスの値を監視

BACnetデバイスの中にはCOV(Change Of Value)という値の変化を監視する機能があります。

私が接続しているBACnetデバイスでもCOVが利用可能ですので、BAC0でCOVを設定してみます。

def cb(elements):
    print('cov recieved:', elements)
device['myAnalogOutput'].subscribe_cov(callback=cb)

これで、COVの設定ができました。
それでは、値を変更してみます。

device['myAnalogOutput'] = 2.0
出力結果
2024-02-24 16:16:34,045 - INFO    | Received COV Notification for {'source': <Address 192.168.0.248>, 'object_changed': ('analogOutput', 0), 'properties': {'presentValue': 2.0, 'statusFlags': [0, 0, 0, 0]}}
cov recieved: {'source': <Address 192.168.0.248>, 'object_changed': ('analogOutput', 0), 'properties': {'presentValue': 2.0, 'statusFlags': [0, 0, 0, 0]}}

無事、値を変更するとコールバック関数cbが呼ばれました。

BACnetデバイスと通信切断

COVをBACnetデバイスに設定したあとは、デバイスとの通信切断の前に、COVの設定解除を行いましょう。
これをしないと、BACnetデバイスをリセットするまで、よく分からないパケットがBACnetデバイスからPCに流れてしまいます。

device['myAnalogOutput'].cancel_cov()

次に、BACnetデバイスとの通信を切断します。
これで、BACnetデバイスからの定期的なデータ収集が終了します。

device.disconnect()

最後に、参加しているBACnetネットワークから自身を切断します。

bacnet.disconnect()

BACnetデバイスからのデータ収集、お疲れ様でした。
ビルのIoT化にご活用ください。

3
0
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?