IoTデバイスとGo

IoTデバイスとの通信では、バイナリデータのパースや生成が不可欠です。
特にLoRaWANやSigfoxなどの低消費電力ネットワークでは、ペイロードサイズを削減するため、1バイト内に複数の値を詰め込むビット単位の操作が頻繁に行われます。
Go言語は標準パッケージでバイナリ操作やエンコーディングを強力にサポートしており、IoTプロトコルの実装にも適しています。
本記事では、Goの「binary」「hex」パッケージを活用したバイナリデータ操作の基本と、実際のIoTプロトコル実装例を紹介します。

バイナリデータ操作の基本

binaryパッケージ

Goのencoding/binaryパッケージは、数値型とバイト列の相互変換を簡単に行えます。

◆例:uint32をバイト列に変換

import "encoding/binary"

var buf [4]byte
binary.BigEndian.PutUint32(buf[:], 12345678)
// bufには[0x00, 0xbc, 0x61, 0x4e]が格納される

◆例:バイト列から数値型へ

val := binary.BigEndian.Uint32(buf[:])

hexパッケージ

encoding/hexはバイト列と16進文字列の相互変換に便利です。

import "encoding/hex"

b := []byte{0x01, 0x02, 0x0a, 0xff}
s := hex.EncodeToString(b) // "01020aff"

d, _ := hex.DecodeString(s) // []byte{0x01, 0x02, 0x0a, 0xff}

IoTプロトコル実装例

ここでは、IoTデバイスとクラウド間でバイナリデータをやり取りする例を紹介します。

1. データ構造の定義

type UplinkPayload struct {
  Data string // 16進文字列
  Device string
  SeqNumberStr string
  SensorValue int
}

2. 受信データのデコード

raw, _ := hex.DecodeString(payload.Data)
// rawは[]byte型。バイナリデータとして各種値を抽出できる

3. ビット単位のデータ抽出

IoTプロトコルでは1バイト内に複数の値が詰め込まれることがあります。以下は4bit、3bit、1bitの例です。

// 例: 1バイトに複数項目が含まれる場合
// bit 7-4: センサータイプ (4bit)
// bit 3-1: ステータス (3bit)
// bit 0: エラーフラグ (1bit)

statusByte := raw[2] // 例: 0xB5 (0b10110101)

sensorType := (statusByte >> 4) & 0x0F // 上位4bit抽出
status := (statusByte >> 1) & 0x07 // 3bit抽出
errorFlag := statusByte & 0x01 // 最下位1bit抽出

4. バイナリデータの生成

IoTデバイスへの応答(ダウンリンク)もバイナリで生成します。

import "encoding/binary"
import "encoding/hex"

var resp [8]byte
resp[0] = 0x80 // ヘッダ
binary.BigEndian.PutUint32(resp[1:5], unixTime)
resp[5] = 0x1a // コマンド

// ビットフィールドの組み立て例
mode := uint8(3) // 2bit
priority := uint8(1) // 1bit
resp[6] = (mode << 1) | priority // 0b00000111

resp[7] = 0x00 // テイル

downlink := hex.EncodeToString(resp[:])
// downlinkはIoTデバイスに返す16進文字列

5. テストでの活用

テスト時もバイナリデータを生成し、期待値と比較します。

expected := hex.EncodeToString([]byte{
  0x80, 0x00, 0x00, 0x00, 0x01, 0x1a, 0x07, 0x00,
})
if got != expected {
  t.Errorf("mismatch: got %s, want %s", got, expected)
}

 

まとめ。注意点など。

  • Goの標準パッケージだけで多くのバイナリ処理が完結できます。とても便利です。
  • バイナリのエンディアン(BigEndian/LittleEndian)に注意しましょう。Go側でデータを受けた後に謎の挙動として悩むことになりかねません。
  • IoTデバイスとのプロトコル仕様書、バイト配列のマッピングなどをデバイスメーカーの公式な仕様書と突き合わせた上で実際に送信されるデータも何度も確認することが重要です。
  • bit数が項目によって違う場合もあります。
  • 突然のデバイス側ファームウェアアップデートなどでbit位置の変更が発生しないか注意しましょう。
  • テストでは16進文字列で比較すると可読性が高くなります。