センスウェイのLoRaWANサービスを使ってみる　その４

ACK要求付きの下りデータ送信を試す前に、まずは前回の補足から。

[その１](https://qiita.com/akira-tt/items/28e999435e2d8fb047b9)
[その２](https://qiita.com/akira-tt/items/dd7f9286509735fcc9c3)
[その３](https://qiita.com/akira-tt/items/e64f0490abe9556f5c9c)

# ```tx_send```を受信するタイミング

前回、

>```tx_send```はデータが「送られた」時ではなく、デバイスが「受信した<font color=red>後</font>」に送られてくることになります。

と書きましたが、これはClass Aのタイミングチャートを参照することで理解できます。[LoRa Allianceが公開している資料](https://lora-alliance.org/resource-hub/lorawantm-101-technical-introduction)から図を抜粋します。

![Class A Timing Chart](https://qiita-image-store.s3.amazonaws.com/0/18746/eb43da03-3bcc-98c7-a6aa-de854d228d2c.png)

ここで「Transmit」となっているのが「デバイスがデータを送信する時間」です。デバイスはデータ送信が完了すると、RxDelay1で定義されている待ち時間が経過した後にRX1の期間だけ受信待ち受けを行います。この間にデータが受信できなかった場合、RxDelay2後に再びRX2の期間待ち受けを行います。

これを下敷きにして```tx_send```のタイミングを考えてみましょう。

![Class A Sequence](https://qiita-image-store.s3.amazonaws.com/0/18746/b365347e-beca-0dd6-5a6b-8db8ee0e0553.png)

既に述べたとおり、アプリケーションからLoRaWANサーバに送られたデータは、デバイスに送られる前に次のデータが来た場合には削除（上書き）されます。デバイスからのデータを受信した後、LoRaWANサーバは上図で示したとおりのタイミングで最新のデータをデバイスに送ります。これが完了したのを受け、アプリケーション側に```tx_send```が返されるということになります。

# ACK付きデータ送信

さて、それでは本題であるACK要求付きのデータ送信を試してみましょう。

## データを送ってみよう

前回同様にデータを送ってみます。ただし今回はACK要求付きなので、メッセージの中に```"cnf": true```を追加しておきます。また、メッセージ同士の関連を確認するための`Ref`も追加します。

```
$ docker run --rm -it test/mosquitto-client mosquitto_pub -h mqtt.senseway.net -p 1883 -u <useryname> -P <password> -t lora/<useryname>/<devEUI>/tx -m '{"port":14,"data":"01","ref":"1","cnf":true}'  -d
```

同様にデバイス側からデータを送信します。

```
> lorawan tx ucnf 1 01
>> Ok
>> rx 14 01
>> tx_ok
>
```

先にアプリケーション側から送信したデータが受信できました。この時のLoRaWANサーバの応答を見ると、

```
lora/<useryname>/<devEUI>/rx {"gw":[{"date":"2018-04-24T12:20:00.684738Z","rssi":-59,"snr":9.8,"gwid":"<gwid>"}],"mod":{"fq":927.4,"cnt":71,"data":"01","mt":"ucnf","devEUI":"<devEUI>","dr":"2","port":1}}
lora/<useryname>/<devEUI>/tx_send {"cnt":26,"cnf":true,"devEUI":"<devEUI>","date":"2018-04-24T12:20:01.078871Z","ref":"1","port":14,"size":1}
```

となり、正常に`tx_send`を受信できました。この時点でデバイスにデータが届いたことになります。さて、ACKはどうなったのでしょうか？　もう一度デバイスからデータを送り、LoRaWANサーバの応答を見てみます。

```
lora/<useryname>/<devEUI>/rx {"gw":[{"date":"2018-04-24T12:23:32.401519Z","rssi":-65,"snr":10.5,"gwid":"<gwid>"}],"mod":{"fq":927.4,"cnt":72,"data":"01","mt":"ucnf","devEUI":"<devEUI>","dr":"2","port":1}}
lora/<useryname>/<devEUI>/ack {"date":"2018-04-24T12:23:32.717703Z","ref":"1","devEUI":"<devEUI>"}
```

今度はACKが届きました。つまり、ACKは`tx_send`を返したもうひとつ先のデータ送信のタイミングで送り返されてくることが分かりました。

## 重送データはどうなるか

さて、これまでの検討で`tx_send`受信前にデータを送信すると、それ以前のデータが削除されて最新のものだけが届くことが分かっています。それではACKが届く前ではどうでしょうか？

まずアプリケーションからデータを送ります。

```
$ docker run --rm -it test/mosquitto-client mosquitto_pub -h mqtt.senseway.net -p 1883 -u <useryname> -P <password> -t lora/<useryname>/<devEUI>/tx -m '{"port":14,"data":"02","ref":"2","cnf":true}'  -d
```

続いてデバイスからデータを送ります。

```
> lorawan tx ucnf 1 01
>> Ok
>> rx 14 02
>> tx_ok
```

LoRaWANサーバの応答は次の通り。

```
lora/<useryname>/<devEUI>/rx {"gw":[{"date":"2018-04-24T12:33:23.364639Z","rssi":-65,"snr":11.3,"gwid":"<gwid>"}],"mod":{"fq":927.8,"cnt":75,"data":"01","mt":"ucnf","devEUI":"<devEUI>","dr":"2","port":1}}
lora/<useryname>/<devEUI>/tx_send {"cnt":27,"cnf":true,"devEUI":"<devEUI>","date":"2018-04-24T12:33:23.766234Z","ref":"2","port":14,"size":1}
```

ここまでは想定通りの動作ですね。これで`tx_send`の受信後、かつ`ACK`の受信前という状況になったので、アプリケーションから次のデータを送ってみます。

```
$ docker run --rm -it test/mosquitto-client mosquitto_pub -h mqtt.senseway.net -p 1883 -u <useryname> -P <password> -t lora/<useryname>/<devEUI>/tx -m '{"port":14,"data":"03","ref":"3","cnf":true}'  -d
```

すると今度は、LoRaWANサーバからこれまでに無い応答が返ってきました。

```
lora/<useryname>/<devEUI>/error {"date":"2018-04-24T12:35:54.239736Z","type":"DownlinkQueue","devEUI":"<devEUI>","error":"Currently could not update downlink queue item because waiting for ConfirmedDown ACK response. REF=2"}
```

`tx_send`の受信後、かつ`ACK`の受信前に次のデータを送ると`DownlinkQueue`エラー（下りの待ち行列あふれ）になります。理由は「`REF=2`のデータに対する`ACK`を受信していないから」となっており、状況と完全に一致しています。

確認のため、再度デバイスからデータを送ってACKが返ってくるのを確認した後、同じデータをもう一度アプリケーションから送ってみます。

```
$ docker run --rm -it test/mosquitto-client mosquitto_pub -h mqtt.senseway.net -p 1883 -u <useryname> -P <password> -t lora/<useryname>/<devEUI>/tx -m '{"port":14,"data":"03","ref":"3","cnf":true}'  -d
```

LoRaWANサーバの応答は

```
lora/<useryname>/<devEUI>/tx {"port":14,"data":"03","ref":"3","cnf":true}
```

となり、今度は正常にデータが送られたことが確認できました。

# まとめ

- ACK要求付きでデータを送った場合、`ACK`が返ってくるのは次々回のデバイス側データ送信のタイミングになる
- `tx_send`受信後、`ACK`受信前に次のデータを送った場合、`DownlinkQueue`エラーとなりデータ送信に失敗する

図にするとこんな感じでしょうか。

![Class A Sequence with ACK Request](https://qiita-image-store.s3.amazonaws.com/0/18746/4049ddc7-a4d7-2ab9-3c9a-4fd8515473d3.png)

# この後は

最後に残ったのはデバイス側からのACK要求付きデータ送信ですね。これまた話がややこしそうです。