Go言語でスマートメーターから電力量取得してみる

なんか最近電気代高くなってきたのでスマートメーターから電力量を取得してみた。
いまどきアプリとかで電気代見ることできるのであんまりやる意味はないと思う・・・
リアルタイム性と瞬時電力量が取れるのが一番のメリットだと思うがNeture Remote Lite Eを使えばUIもいい感じで表示されるし値段もそんな変わらないのでそっち買うのがおすすめ。

準備するもの

  • BP35A1
    • Wi-SUNモジュール
  • BP35A7A
    • ピッチ変換アダプタ
  • BP35A7-accessories
    • ピンヘッダー
  • USBシリアル変換
    • なんか家にあったやつを使った
  • BルートのIDとパスワード

Wi-SUN系のものはコアスタッフってところで買った。
トータルで1万円ぐらいだった。

ドキュメント

参考にした記事

BP35A1のセットアップ

cuコマンドでシリアル通信を行う。
sudo cu -l cu.usbserial-AI06IYRS -s 115200

デフォルト設定だとスマートメータからデータがバイナリで表示されるので16進数に変更しておく
WOPT 1

瞬時電力量の取得方法

送信コマンドの組み立て方

ミドルウェア仕様書のとおりにECHONETLiteデータフレームを組み立てていく。

  • EHD1
    • 0x10
    • ECHONET Lite規格
  • EHD2
    • 0x81
    • 形式1
  • TID
    • 0x01
    • 2Byteであればなんでもいいが今回は0x01で固定している
  • SEOJ
    • 0x05FF01
    • 送信元
    • コントローラークラス規定
  • DEOJ
    • 0x028801
    • 送信先
    • 低圧スマート電力メータクラス規定
  • ESV
    • 0x62
    • 読み出し要求
  • OPC
  • 0x01
  • 1プロパティしか読み込まないため
  • EPC
    • 0xE7
    • 瞬時電力計測値
  • PDC
    • 0x00
    • 読み出し要求の場合は0x00
  • EDT
    • PDCが0の場合はたぶんいらない

こららを全部結合すると\x10\x81\x00\x01\x05\xFF\x01\x02\x88\x01\x62\x01\xE7\x00になるのでSKSENDTOで送信する。

受信データ読み方

瞬時電力量のコマンドを送信すると以下みたいなERXUDPから始まるデータのレスポンスがくる。

ERXUDP FE80:0000:0000:0000:0280:xxxx:xxxx:xxxx FE80:0000:0000:0000:021D:xxxx:xxxx:xxxxx 0E1A 0E1A 008087003010D9C1 1 0012 1081000102880105FF017201E704000000DE

空白区切りの最後の部分が瞬時電力計測値が含まれているデータ(ECHONETLiteデータフレーム)である。
DEOJまでは送信元と受信元が逆になったぐらい違いしかない。

  • ESV
    • `0x72
    • 応答
  • OPC
  • 0x01
  • 要求時と同じ値
  • EPC
    • 0xE7
    • 要求時と同じ値
  • PDC
    • 0x04
    • EDTのサイズ
  • EDT
    • 0x000000DE
    • 16 * 13 + 14 = 222W

ソースコード

Goで書いてみたが、結構長くなったのでGithubのリンク貼っておく。積算電力量も取得できるようにしている。

github.com

エラーハンドリングは結構適当なので長時間動かす時は手加えないといけない。

serial通信のパッケージにgo-serialを使ってみたが、タイムアウトを設定してもエラーが返ってこないのでio.ReadLine()で読み込もうとすると永遠にブロックされてしまう。
issueは上がっているが破壊的変更なのでv2がでるまで改善されてないみたいなので、自分でそこの部分は実装した。
このパッケージでラップすればいけるみたいなコメントもみた。

PostgreSQL, MySQLで重複したデータがあるカラムでorder byするときの注意点

業務でソートのキーとlimitとoffsetを指定できるList APIで,offset間でデータが重複するバグがありそのときに知ったRDBorder by句の注意点についてまとめる。

検証

PostgreSQLにテーブルとデータを準備する。

create table test
(
    id integer primary key,
    val integer
);

INSERT INTO test (id, val) VALUES
    (1, 1),
    (2, 1),
    (3, 1),
    (4, 1),
    (5, 1),
    (6, 1),
    (7, 1),
    (8, 1),
    (9, 1),
    (10, 1);

そして以下のクエリを実行する。

select * from test order by val limit 2 offset 0;
select * from test order by val limit 2 offset 2;
select * from test order by val limit 2 offset 4;
select * from test order by val limit 2 offset 6;
select * from test order by val limit 2 offset 8;

すると以下のような結果になる。 id = 1の行がoffset 0とoffset 2に重複し、id = 3の行が取れていない。

select * from test order by val limit 2 offset 0;
 id | val 
----+-----
  2 |   1
  1 |   1
(2 rows)

select * from test order by val limit 2 offset 2;
 id | val 
----+-----
  4 |   1
  1 |   1
(2 rows)

select * from test order by val limit 2 offset 4;
 id | val 
----+-----
  5 |   1
  6 |   1
(2 rows)

select * from test order by val limit 2 offset 6;
 id | val 
----+-----
  7 |   1
  8 |   1
(2 rows)

select * from test order by val limit 2 offset 8;
 id | val 
----+-----
  9 |   1
 10 |   1
(2 rows)

原因

ORDER BYとLIMIT, OFFSETの組み合わせには注意しように詳しく書いてあるが、ユニークなカラムでない場合の並び順は順序不定になっている。リンク先のブログはMySQLになっているがPostgeSQLでもチュートリアルに順序不定であることが書かれている。

この例では、ソート順は十分に指定されていません。 ですので、San Franciscoの行は順序が異なるかも知れません。

対策

  • ユニークなカラムをorder byで指定する
  • order byで指定するカラムを2つにする
    • ただし2つめのカラムはユニークなものにする

rsyncとsftpコマンドの使い方

まえがき

SCPコマンドは2019年に脆弱性が見つかり現在は非推奨のコマンドとなっています。この脆弱性自体は、修正済みであるようです。
今までscp非推奨であることを知りつつも新しいコマンド調べるのがめんどくさくプライベートではSCP使い続けてました。新卒で入社して、仕事で使うのはいかがなものかということで今回はSCPの代替コマンドであるrsyncとSFTPコマンドでファイルとディレクトリの送受信について調べてみました。

rsync

rsyncとは

リモート環境とファイルやディレクトリを同期するコマンドです。ローカル環境でも使用可能です。
差分のみ更新することやパーミッションやグループなどを保持したまま同期することができます。 SSH経由で使うことでセキュアに転送することが可能です。

ファイル・ディレクトリの送信

sshのポート番号の変更や鍵認証を使っているときは、eオプションを付けます。

ファイルの送信

$ rsync -e 'ssh -p <ポート番号>' /path/to/file <ユーザー名>@<ホストネーム>:~/path
$ rsync -e 'ssh -i ~/.ssh/keyfile' /path/to/file <ユーザー名>@<ホストネーム>:~/path

ディレクトリの送信

rオプションでもできますが、aオプション付けるのが一般的らしいです。aオプションだとディレクトリの同期だけでなく、シンボリックリンク、グループ、タイムスタンプ、所有者、パーミッション、デバイスファイル、特殊ファイルの情報も同期できるみたいです。

/dir1/だとdist_path内に直接ファイルが配置されます。
/dir1だとdist_path内にdir1が配置されます。

$ rsync -e 'ssh -p <ポート番号>' /path <ユーザー名>@<ホストネーム>:~/dist_path

ファイル・ディレクトリの受信

順番逆にすればできます。

ファイルの受信

$ rsync -e 'ssh -p <ポート番号>' <ユーザー名>@<ホストネーム>:~/path/to/file /path

ディレクトリの受信

$ rsync -e 'ssh -p <ポート番号>' <ユーザー名>@<ホストネーム>:~/path/to/dir /dir1/test_file1 /path

便利そうなオプション

オプション 説明
v 詳細表示
P 進捗表示と転送を中断したファイルを保持する
u 同期先のほうが新しい場合はスキップ
n dry run

SFTP

SFTPとは

ftpコマンドのように対話形式でファイル転送をすることができるコマンドです。すべての操作はSSHで暗号化された通信経路を経由して行われます。
ちなみにですが、SSLを利用して暗号化を行うFTPSというものもあります。

サーバとの接続

port番号指定
$ sftp -P <ユーザー名>@<ホストネーム>

認証鍵
$ sftp -i /path/to/keyfile <ユーザー名>@<ホストネーム>

ssh config
$ sftp -F <接続名> <ユーザー名>@<ホストネーム>

ファイル・ディレクトリの送信

接続中は、cdlsmkdirなどのコマンドが使えます。ローカルに対して実行したい場合は先頭にlをつけます。

ファイルの送信

sftp> cd <送信したいpath>
sftp> put local/path/to/file

ディレクトリの送信

sftp> cd <送信したいpath>
sftp> put -r local/path/to/dir

ファイル・ディレクトリの受信

ファイルの受信

sftp> lcd <受信したいpath>
sftp> get /path/to/file

ディレクトリの受信

sftp> lcd <受信したいpath>
sftp> get -r /path/to/dir

感想

sftpは対話式のため若干めんどくささがあるので、今後はrsyncのほうを使っていこうと思います。

参考文献

  1. SCP は SFTP よりも安全か?
  2. 【 rsync 】コマンド(その1)――ファイルやディレクトリを同期する
  3. Rsyncでローカルとリモートのディレクトリを同期する方法
  4. Linuxコマンド【 sftp 】安全なファイル転送