IoT用SIMの実測通信量について　【結果のみ】


# はじめに
[少し前の記事](https://qiita.com/f-mio/items/6dce12777d57d1d21e17)にてSoracomさんのSIMカード購入前に使用するデータ容量を試算しました。
2週間程度プログラムを稼働しましたので、予想したデータ量と実測のデータ量を比較してみようと思います。
(大幅な違いがあったが、原因はよくわかっていないです）

# 結果

予測値と大幅に違いがありました。
- 実測値： 2206400 byte
- 予想値：　133920 byte


## 使用したソースコード
```c++
#include <M5StickCPlus2.h>
#include <WiFiClient.h>
#include <WiFiClientSecure.h>
#include <PubSubClient.h>
#include <time.h>
#include "porthub.h"

// porthub type b
PortHub porthub;
uint8_t HUB_ADDR[6] = {
  HUB1_ADDR, HUB2_ADDR, HUB3_ADDR,
  HUB4_ADDR, HUB5_ADDR, HUB6_ADDR};

// wifi
#define QOS 0
WiFiClientSecure httpsClient;
PubSubClient mqttClient(httpsClient);

// [Secret]
// WiFi config information.
extern const char *WIFI_SSID;
extern const char *WIFI_PASSWORD;
extern const char *MQTT_SERVER;
extern const int MQTT_PORT;

// secret_info.cpp (aws iot core)
extern const char *AWS_CLIENT_ID;
extern const char *PUB_TOPIC_NAME;
extern const char *AWS_IOT_ROOT_CA;
extern const char *AWS_IOT_DEVICE_CERT;
extern const char *AWS_IOT_PRIVATE_KEY;


// For fetch date time from ntp server.
const char* ntpServer = "ntp.nict.jp";
const long gmtOffset_sec     = 9 * 3600;
const int daylightOffset_sec = 0;

// For mqtt publisher.
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (200)
char msg[MSG_BUFFER_SIZE];
int value = 0;

uint16_t analogRead_value = 0;
uint16_t digitalRead_value = 0;

void setup_wifi() {
  M5.Lcd.print("Connecting to ");
  M5.Lcd.print(WIFI_SSID);

  WiFi.disconnect(true);
  delay(1000);

  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    M5.Lcd.print(".");
  }

  M5.Lcd.print("\nWiFi connected");
}

void callback(char*, byte* , unsigned int);

void setup_awsiot() {
  const int port = 8883;
  httpsClient.setCACert(AWS_IOT_ROOT_CA);
  httpsClient.setCertificate(AWS_IOT_DEVICE_CERT);
  httpsClient.setPrivateKey(AWS_IOT_PRIVATE_KEY);
  mqttClient.setServer(MQTT_SERVER, port);
  mqttClient.setCallback(callback);
}

void connect_awsiot(){
  while (!mqttClient.connected()) {

    M5.Lcd.setTextColor(BLUE);
    M5.Lcd.setCursor(10, 2);
    M5.Lcd.fillScreen(YELLOW);
    M5.Lcd.print("Attempting MQTT connection...\n");
    M5.Lcd.setTextSize(1);
    M5.Lcd.print(AWS_CLIENT_ID);
    M5.Lcd.print("\n");
    M5.Lcd.print(MQTT_SERVER);
    M5.Lcd.print("\n");
    M5.Lcd.setTextSize(2);

    if (mqttClient.connect(AWS_CLIENT_ID)) {
      M5.Lcd.print("Connected.");
    }
    else {
      M5.Lcd.print("Failed\n   rc=");
      M5.Lcd.print(mqttClient.state());
      M5.Lcd.print("\n Try again in 5 seconds");
      delay(5000);
    }
  }
}

void mqtt_callback(char* topic, byte* payload, unsigned int length) {
    Serial.print("Recieved. topic=");
    Serial.println(topic);

    char sub_message[length];
    for (int i = 0; i < length; i++) {
      sub_message[i] = (char)payload[i];
    }
    Serial.println(sub_message);
}

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);

  porthub.begin();

  M5.Lcd.setTextSize(2);
  M5.Lcd.setTextColor(BLUE);
  M5.Lcd.setCursor(10, 2);
  M5.Lcd.fillScreen(YELLOW);
  setup_wifi();
  setup_awsiot();
  configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}

void callback(char* topic, byte* payload, unsigned int length) {
}

void loop() {

  if (!mqttClient.connected()) {
    connect_awsiot();
  }

  mqttClient.loop();

  unsigned long now = millis();
  if (now - lastMsg > 60000) {
    lastMsg = now;
    ++value;
    String json = createJson();
    char jsonStr[200];
    json.toCharArray(jsonStr,200);
    snprintf(msg, MSG_BUFFER_SIZE, jsonStr);

    // Set display color
    if (porthub.hub_a_read_value(HUB_ADDR[2]) < 2500) {
      M5.Lcd.fillScreen(RED);
    } else if (porthub.hub_a_read_value(HUB_ADDR[1]) < 2500){
      M5.Lcd.fillScreen(YELLOW);
    } else if (porthub.hub_a_read_value(HUB_ADDR[0]) < 2500){
      M5.Lcd.fillScreen(GREEN);
    } else {
      M5.Lcd.fillScreen(WHITE);
    }

    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(10, 2);
    M5.Lcd.printf("UNIT LIGHT STATUS\n");
    M5.Lcd.setCursor(0, 20);
    M5.Lcd.printf(
      " green  : %d\n yellow : %d\n red    : %d", 
      porthub.hub_a_read_value(HUB_ADDR[0]),
      porthub.hub_a_read_value(HUB_ADDR[1]),
      porthub.hub_a_read_value(HUB_ADDR[2])
    );
    M5.Lcd.setCursor(10, 90);
    M5.Lcd.setTextSize(1);
    M5.Lcd.println(msg);

    mqttClient.publish(PUB_TOPIC_NAME, msg);
  }
}

String createJson() {
  String timestampStr = fetchTimestamp();
  String json = "{";
    json +=  "\"timestamp\": \"";
    json +=  timestampStr;
    json +=  "\", ";
    json +=  "\"green\": ";
    json +=  porthub.hub_a_read_value(HUB_ADDR[0]);
    json +=  ", ";
    json +=  "\"yellow\": ";
    json +=  porthub.hub_a_read_value(HUB_ADDR[1]);
    json +=  ", ";
    json +=  "\"red\": ";
    json +=  porthub.hub_a_read_value(HUB_ADDR[2]);
    json += "}";
  return json;
}

String fetchTimestamp() {

  struct tm timeInfo;
  getLocalTime(&timeInfo);

  char timestamp[20];
  sprintf(timestamp, "%04d/%02d/%02d %02d:%02d:%02d",
    timeInfo.tm_year + 1900,
    timeInfo.tm_mon + 1,
    timeInfo.tm_mday,
    timeInfo.tm_hour,
    timeInfo.tm_min,
    timeInfo.tm_sec);

  return timestamp;
}
```


## 1日あたりの実測したデータ量

Soracomコンソール上でデータ量を確認した結果を記載します。
- 実測値合計： 2,206,400 byte
- 1日あたりアップロード数：　1,528,078 byte
- 1日あたりダウンロード数：　678,322 byte

![２月26日のDownloadデータ量](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671049/04d227ef-2840-d472-25ae-e7c3b33e0bc4.png)

![２月26日のUploadデータ量](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/671049/58c5fa1f-2e84-979e-9bfb-db81ae57d0f6.png)

## 推測したデータ量
実際に使用したデータを元に送信データ推測値を計算してみます。
(若干jsonが違うので以前の記事と少し変わっています）

| 内容 | データ量 |
| --- | --- |
| ヘッダ | 12 byte |
| ボディ | 81 byte |


```json
{"timestamp": "20XX-XX-XX XX:XX:XX", "green": XXXX, "yellow": YYYY, "red": ZZZZ}
```
合計93　byteです。
1分ごとに送信しているため、$ 133920 = 93 \times 60 \times 24 \verb|(byte)|$となります。


# 考察

## 比較
結果を比較すると下記のようになります。
| 内容 | 実測値（byte） | 実測値（byte） |
| --- | --- | --- |
| アップロード | 1,528,078 | 133,920 |
| ダウンロード | 678,322 | - |

## その他情報 (参考)

### 証明書

AWSとの接続にあたり、証明書の文字列を渡す必要があります。
この部分で何回かやり取りが発生している可能性があると思われます。

証明書の合計文字数： **4134文字**（改行コード込み）でした。
| 証明書種類 | 文字数 |
| --- | --- |
| プライベートキー | 1682 |
| ルート証明書 | 1208 |
| デバイス証明書 |1244|

## 推測
おそらく何時間かに一度、再認証を行い、証明書情報を送信し、何かしらのトークンを受け取っているのでは、と予想しています。
再認証プロセスや、アップロード時にトークンが含まれていない文字数で試算したために大幅な差異が発生したものと推測しています。
今の時点ではよくわからない状態ですが、このあたり情報を探して理解できたら何かしらの発信をしていければ、と思います。