Open6

OMRON BW55TでNetwork UPS Toolsを使う

jlandownerjlandowner

OMRON公式のシャットダウンソフト
https://socialsolution.omron.com/jp/ja/products_service/ups/support/download/ups.html

  • PowerAttendant Standard
  • PowerAttendant Lite
  • Simple Shutdown Software
  • PowerAct Pro

Simple Shutdown SoftwareはオープンソースでC++のコードが提供されていたのだが、PowerAttendant LiteとSimple Shutdown Softwareは2024/3で提供中止になるらしい。
https://socialsolution.omron.com/jp/ja/products_service/ups/info/topics/231018.html

jlandownerjlandowner

ネットで検索すると先人たちはNetwork UPS Toolsを使用していることがわかった。

https://qiita.com/sugi_0000/items/89c025e3804cfcfdf11e
https://blog.oomurosakura.co/archives/2022-08-03/
https://gist.github.com/ao-kenji/7164184

Network UPS Tools(nut)は20世紀からある歴史あるオープンソースプロジェクトでGitHubをみると今も非常にアクティブなよう。元々APCのUPSをサポートするところから始まったようで、今では多くのUPSがサポートされているがOMRONはリストにない。
https://networkupstools.org/stable-hcl.html

nutはUPSに直接接続してUPSの状態を配信するサーバプロセスと、サーバに接続してUPSの状態を拾うクライアントプロセスから構成される。このサーバとクライアントの接続プロトコルは2022年にRFCで標準化されている。
https://datatracker.ietf.org/doc/html/rfc9271

標準化されているので色々な言語でこのプロトコルを扱うライブラリがあったり、UPSのメトリクスをPrometheusに送るためのexporterなどがある(これは嬉しい)
https://github.com/DRuggeri/nut_exporter

nutのインストールはaptで簡単にインストールできる。

# フルインストール
apt install nut
# クライアントのみの場合
apt install nut-client

nutのdriver設定に対象のUPSに合わせたドライバーを設定するのだが、先人たちの記事を見ると皆driver = blazer_usbと設定している。

これが何者か調べていると、Ubuntuのマニュアルにて説明が見つかった。
https://manpages.ubuntu.com/manpages/focal/en/man8/blazer_usb.8.html

blazer_usb - Driver for Megatec/Q1 protocol USB based UPS equipment

Megatec/Q1 protocolについて調べるとnutsのドキュメントが出てくる。
https://networkupstools.org/protocols/megatec.html

プロトコルの基本となるUPSからの情報取得はめっちゃシンプルでQ1+改行と送るとUPSからバッテリーや入力電源の情報が返ってくる仕様。
Q1

これ実は、OMRONの公式が出しているオープンソース版のツールであるSimple Shutdown Softwareを見てみると確かにQ1をUPSに送信していることが確認できる。色々繋がってきた。

https://socialsolution.omron.com/jp/ja/products_service/ups/support/download/soft/sss/sss_linux.html

©OMRON Corporation. 2011 All Rights Reserved. 
//*************************************************************************************//
//  Parameters:
//      szData
//          [out] Storage location of data from UPS.
//  Return value:
//      Return 1, succeed; 0, failed.
//  Description:
//      Send "Q1" command to UPS, and store the data received from UPS into (szData).
//*************************************************************************************//
int CUPS::UPSCmdQ1(char *szData)
{
	UINT i;
	for (i = 0; i < MAX_PORT_FAIL_LOOP; i++)
	{
		if (WritePort("Q1") < 0)
			continue;

		if (ReadPort(47, szData) > 0)
		{
			if (strlen(szData) == 47)
				return 1;
		}
	}

	ClosePort();
	return 0;
}

jlandownerjlandowner

ここまでわかったのでblazer_usbドライバーを使用して、と思ったがよくよく調べるとうちのNAS(QNAP TS-262)が公式にOmron UPSをサポートしていることを思い出した(そもそもこれを見てOMRONのUPSを買ったんだった)

https://www.qnap.com/en/compatibility/?model=597&category=9&filter[brand]=OMRON
QNAP

あたらめて考えるとQNAPのOSであるQTSではOMRON UPSに繋ぐときドライバーは何なの?ということになる。調べてみるとQTSのUPS機能はNetwork UPS Toolsが内部で使われているらしい。

https://qiita.com/msy22831/items/89905b6bf22e0444f2b0

実際にUSBでUPSとQNAPを接続するとすんなり認識され接続ができた。
QTS

この状態でQNAP NASにSSH接続して状態を確認してみる。

OS情報

$ cat /etc/*release
NAME="QTS"
VERSION="5.1.2 (20230926)"
ID=qts
PRETTY_NAME="QTS 5.1.2 (20230926)"
VERSION_ID="5.1.2"
$ uname -a         
Linux NAS62AD78 5.10.60-qnap #1 SMP Tue Sep 26 01:55:25 CST 2023 x86_64 GNU/Linux

起動中のプロセス

$ ps -ef | grep ups | grep -v grep
 2159 admin      1456 S   /usr/local/ups/bin/omron_usb -a qnapups -u admin
 2222 admin      1484 S   /usr/sbin/upsd -u admin
23278 admin      6808 S   /usr/sbin/upsutil

まさにNetwork UPS Tools(nut)のserverプロセスであるupsdomron_usbというドライバーが動いていることが確認できた。

nutのクライアントコマンドであるupscで確認してみる。

$ upsc -l        
qnapups

$ upsc qnapups 
battery.charge: 100.0
battery.charge.low: 30
battery.charge.restart: 0
battery.runtime: 3900
battery.temperature: +19.8
battery.voltage: 13.70
battery.voltage.nominal: 024
device.mfr: OMRON
device.model: BW55T
device.serial: XXXXXXXXXX 
device.type: ups
driver.name: omron_usb
driver.parameter.pollinterval: 2
driver.parameter.port: /dev/ttyS1
driver.parameter.synchronous: no
driver.version: 2.7.4
driver.version.internal: 1.02
input.frequency: 50.10
input.sensitivity: N
input.voltage: 103.7
input.voltage.fault: 0.0
output.frequency: 50.0
output.voltage: 103.8
output.voltage.nominal: -
ups.beeper.status: enable
ups.delay.reboot: 14
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 0.32
ups.firmware.aux: 1.04
ups.load: 12.0
ups.mfr: OMRON
ups.model: BW55T
ups.power: 550
ups.productid: 00d0
ups.realpower: 340
ups.serial: XXXXXXXXXX 
ups.start.auto: yes
ups.start.battery: no
ups.status: OL
ups.temperature: 25.9
ups.type: offline / line interactive
ups.vendorid: 0590

ちゃんとUPSの情報を取得することができた。

nutの設定ファイルも確認できる。

$ ll /etc/config/ups
total 40K
drwxr-xr-x  2 admin administrators 4.0K 2024-01-09 11:49 ./
drwxr-xr-x 51 admin administrators  12K 2024-01-18 00:00 ../
-rw-r--r--  1 admin administrators   83 2024-01-09 11:49 ups.conf
-rw-r--r--  1 admin administrators 1.2K 2024-01-09 11:49 upsd.conf
-rw-r--r--  1 admin administrators 2.4K 2023-01-14 00:08 upsd.users
-rw-r--r--  1 admin administrators  12K 2024-01-09 11:49 upsmon.conf

そしてUPSの設定をみると、driver = blazer_usbではなくdriver = omron_usbが設定されていることがわかる。

$ cat ups.conf      
[qnapups]
driver = omron_usb
port = /dev/ttyS1
desc = "Workstation"
pollinterval=2

じゃあblazer_usbはないのかというと、先ほどプロセスを確認した際にomron_usb/usr/local/ups/binにあったので、そこを見てみるとblazer_usbもあった。

ll /usr/local/ups/bin
total 1.4M
drwxr-xr-x 2 admin administrators  160 2023-09-26 04:36 ./
drwxr-xr-x 7 admin administrators  140 2023-09-26 04:36 ../
-rwxr-xr-x 1 admin administrators 100K 2023-09-26 04:36 blazer_usb*
-rwxr-xr-x 1 admin administrators 784K 2023-09-26 04:36 nutdrv_qx*
-rwxr-xr-x 1 admin administrators  99K 2023-09-26 04:36 omron_usb*
-rwxr-xr-x 1 admin administrators  88K 2023-09-26 04:36 riello_ser*
-rwxr-xr-x 1 admin administrators  97K 2023-09-26 04:36 riello_usb*
-rwxr-xr-x 1 admin administrators 216K 2023-09-26 04:36 usbhid-ups*

やっと全体像がわかってきた。OMRONは公式でUPSへの接続を行う製品企業のためにUPSのプロトコルを開示している。
https://www.omron.co.jp/contact/ContactForm.do?FID=00014

個人で申請できるかわからないので開示請求はしていないが、要するにQNAPがこれを実装したドライバーがomron_usbなのだと思う。

オープンソース版のSimple Shutdown Softwareをみる限りでは、情報取得のためのQ1コマンドとUPS自体(?)をシャットダウンするためのSNコマンドの存在は確認できるが、プロトコル仕様の全量はわからない。
しかしblazer_usbではなくちゃんとomron_usbがあるということは、基本的にはMegatec/Q1 protocolをベースとしたものだろうが、恐らく何かしら拡張仕様などがあるものと思われる。

ただ先人たちの記事からUPSの電源喪失時にサーバをシャットダウンするような基本的な使い方であればblazer_usbでも代替できると思われる。

が、せっかくQNAPのNASを持っているので、QNAP NASにomron_usbドライバーを使用したnut serverになってもらい、他のサーバにはQNAP NASをMasterとしたnut-clientを導入しようと思う。これで構成が決まった。

jlandownerjlandowner

Master側、つまりNASの設定はQNAPだとめちゃめちゃ簡単だ。
USBでQNAP NASとUPSを繋いで、QTSのGUI上で設定を行うだけ。ちょっとややこしいのは
QTS上では「Network UPS Tools」や「upsd」といったNetwork UPS Toolsの専門用語は一切登場しないことだ。

QTS

NAS側をMasterにするため他のサーバから接続できるようにする必要がある。
QTSの画面上に「ネットワークUPSサポート」なるものがあるので、これを有効化して仮で立てた仮想マシンのIPを設定してみた。

この状態でSSH接続してnutの設定ファイルがどうなっているか確認してみる。

upsd.confが更新され、リスナーが他のサーバからの接続を受け付けられるようにし、ACLで接続元のIPがGUI上で設定したIPのみが許可されていることがわかる。

$ cat upsd.conf 
# Network UPS Tools: example upsd configuration file
#
# This file contains access control data, you should keep it secure.
#
# It should only be readable by the user that upsd becomes.  See the FAQ.

# =======================================================================
#
#
# REJECT <aclname> [<aclname>...]
#
#
# allowed to connect to upsd.
#
# This default configuration only gives access to localhost.  To allow
# other hosts or networks to connect, see the documentation and change
# these lines.

ACL all 0.0.0.0/0
ACL localhost 127.0.0.1/32
ACL client_1 192.168.1.111/32 <----追加された

ACCEPT localhost
ACCEPT client_1
REJECT all

MAXAGE		20

# =======================================================================
# MAXAGE <seconds>
# MAXAGE 15
#
# This defaults to 15 seconds.  After a UPS driver has stopped updating
# the data for this many seconds, upsd marks it stale and stops making
# that information available to clients.  After all, the only thing worse
# than no data is bad data.
#
# You should only use this if your driver has difficulties keeping
# the data fresh within the normal 15 second interval.  Watch the syslog
# for notifications from upsd about staleness.
LISTEN 0.0.0.0 <----追加された

仮で起動した仮想マシンにnut-clientをインストールしてQNAP NASのnut-serverに接続できることを確認する。

$ upsc qnapups@[NASのIPアドレス]
Init SSL without certificate database
battery.charge: 100.0
battery.charge.low: 30
battery.charge.restart: 0
battery.runtime: 3900
battery.temperature: +19.8
battery.voltage: 13.70
battery.voltage.nominal: 024
device.mfr: OMRON
device.model: BW55T
device.serial: XXXXXXXXXX 
device.type: ups
driver.name: omron_usb
driver.parameter.pollinterval: 2
driver.parameter.port: /dev/ttyS1
driver.parameter.synchronous: no
driver.version: 2.7.4
driver.version.internal: 1.02
input.frequency: 50.10
input.sensitivity: N
input.voltage: 103.7
input.voltage.fault: 0.0
output.frequency: 50.0
output.voltage: 103.8
output.voltage.nominal: -
ups.beeper.status: enable
ups.delay.reboot: 14
ups.delay.shutdown: 30
ups.delay.start: 180
ups.firmware: 0.32
ups.firmware.aux: 1.04
ups.load: 12.0
ups.mfr: OMRON
ups.model: BW55T
ups.power: 550
ups.productid: 00d0
ups.realpower: 340
ups.serial: XXXXXXXXXX 
ups.start.auto: yes
ups.start.battery: no
ups.status: OL
ups.temperature: 25.9
ups.type: offline / line interactive
ups.vendorid: 0590

問題なく接続できた(最初にSSLに起因するメッセージが出たが)

jlandownerjlandowner

とりあえずクライアントから接続できることは確認できたので、各サーバに導入するnut-clientの設定を試していきたい。

基本的にはUPSの電源喪失を検知したら適当なシャットダウンコマンドができればいい。Proxmoxのホストサーバ等にnut-clientを導入するつもりだが、上で動いているKubernetesクラスターではNASにiscsiで接続しているPodがいたりするため、このあたりはちゃんとPodを止めてシャットダウンしたい。が、ここは後からシャットダウンのスクリプトやプログラムを作ればいいので、とりあえず任意のコマンドが実行できるまで確認していきたい。

nutの設定は結構色々あるのでとりあえず主要な設定例を確認したい。と思ってドキュメントを眺めているとExample Bookというのがあった。
https://networkupstools.org/documentation.html

NUT Configuration Examples book maintained by Roger Price

オープンソースのExampleなのだが、Bookと名のつく通りLaTeXで書かれていてリリースがPDFという硬派というか歴史を感じるドキュメントだった。ただ非常によく書かれたドキュメントで大体の設定イメージがわかる。

クライアントプロセスはupsmonというデーモンプロセスで、これだけを起動する場合nut.confのMODEにnetclientを設定する。

$ cd  /etc/nut/
$ cat nut.conf
...
MODE=netclient

次にupsmon.confの設定を行う。設定する項目は大体以下のようなものになりそう(デフォルトで入っていたもの含め)

SHUTDOWNCMD "/sbin/shutdown -h +0" # シャットダウンコマンド
NOTIFYCMD /usr/sbin/upssched  # 通知コマンド
POLLFREQ 5 # サーバへのpolling間隔秒数
POLLFREQALERT 5 # サーバへのpolling間隔(UPSバッテリー駆動時)
DEADTIME 15 # この秒数UPSの情報が取得できなかった場合、UPS喪失とみなす。
POWERDOWNFLAG /etc/killpower
HOSTSYNC 5 # シャットダウン状況中にセカンダリが切断されるまで、プライマリが待つ秒数
MINSUPPLIES 1 # 複数のUPSを繋いでいる際にUPSの数がこの値を下回ったらシャットダウンを行う
RBWARNTIME 43200 # バッテリー交換アラート送信間隔秒数
NOCOMMWARNTIME 300 # UPS設定が1つもない場合のアラート
FINALDELAY 5 # NOTIFYCMDを実行した後にSHUTDOWNCMDを実行するまでの待機秒数

細かな設定は置いておいて、まず自分のためにカスタマイズする部分としては、SHUTDOWNCMDNOTIFYCMDのようだ。今回は何かイベントがあればDiscordに通知するようにしたい。上記のupsmonの設定に入れるのかと思ったが、いくつかの例を見るとNOTIFYCMDは上記のようにupsschedを設定することが一般的なようだ。

upsschedのマニュアルをみるとupsmonとは別プログラムとしてupsschedを作った背景などが書かれている。upsmonの設定上はNOTIFYCMDを1つ指定するだけになっているが、いくつかイベントの種類があるため、イベントの種類に応じたプログラムを実行できるようにしたみたい。イベントを区別する必要がない人はこの機能がいらないためとあるがその他の機能もあるため、いくつか先人のサイトをみる限り基本的にこれを使っている模様。
https://networkupstools.org/docs/man/upssched.html