PR

M5stackに接続したSORACOMの3G拡張ボードからスプシにHTTPリクエストが送れない件

M5stackに接続したSORACOMの3G拡張ボードからスプシにHTTPリクエストが送れない件 組み込み機器

400エラーが返るんだけど??

こうした悩みを解決する記事を書きたいのですが、分からず苦しんでます…

と記事を書き始めたものの、書いてる途中に解決しました。

立プロ

新卒でメーカーに入り、10年間組み込みの現場で設計を行う。
今は個人事業主として自作の組み込み機器開発や、エージェント様に紹介いただき業務委託を行っています。
C,C#,JavaScript, Vue, PHP, VBA, GAS, Kotlinなど、扱う言語が増えゆく日々。

立プロをフォローする

WiFiだと簡単に送れる

WiFiだとHTTPクライアントライブラリと連携して簡単にHTTPリクエストが送れます。

URLを指定して、POSTだったらJSON形式のデータを引数にPOST関数に入れれば良いだけです。

JSON形式のデータを作るのもArduinoJSONライブラリで、キー作成してバリュー設定してすぐ作れます。

「M5stack wifi スプシ」とでもググれば、スプレッドシートでのGoogleWEBAPIの作り方も含めてサンプルコードがたくさん見つけられます。

今回SORACOMの3G拡張ボード(携帯回線)を使って送りたいのですが…GSMクライアントでの実装になり…スプレッドシート…ちょっとクセあることが分かってきました。

スプシのWebAPIのURLはHTTPS接続必須

スプシへのアクセスはHTTPSでないといけないらしいです。

HTTPでGoogleのWEBAPIにアクセスするとリダイレクトされてHTTPSにつなぐようで、これはセキュリティ懸念のためとのこと。

WiFiだとWiFiClientSecureがあって、これがHTTPS通信に対応してるんですよね。だから簡単。

400エラーに悩まされる

一方の3G拡張ボード、というかGSMクライアントはHTTP通信にしか対応していない様子…。

ずっと400エラーが返ってきていて、訳わからんかったんです。

400エラーは特定できない何かしらの原因で発生するエラー…つまりどこが問題か分からないのです。

Secureがほしいんだよ、GSMクライアントにもSecureが…。

長く組み込みをやってますが、ネットワークにつなぐのが今回が初めてで、HTTPS通信という考えに至るまで2日要しました。

それまで自分のコードの書き方が悪いのだと思い込んでいて、いくら書き直してもつながらない…。

ソラコムのサンプルにある時刻サーバーからのGETはできているのに、なぜスプシへのPOSTができないのかな、HTTPリクエストの書き方が悪いのかな?

80と443って何?Hostにはドメインを書くの?POSTの後のURLにドメインいらないの?

HTTP/1.1?HTTP1.0?JSONで書いてるからダメなの?

参考)ソラコムのサンプルコード→HTTP でアクセスする

HTTPSRedirect.hライブラリを試す

やっとのことでHTTPリクエストするとリダイレクトされることを知り、今度はHTTPSRedirect.hライブラリが公開されていたので、それを試すもつながらない…

これでつながりました!のブログをたくさん見ました、なのにつながらない…

なぜ俺のはつながらんのや…

よく見たらHTTPSRedirect.hはWiFiクライアントに対してのライブラリやん、俺はGSMクライアントなんだよ、誰か作ってくれてないわけ?(もはや他力本願

あー、ダメだ、どうすればいいんだ…

そう思いつつ、できないことをブログに書いてるときに、ふと…

GSMクライアントにSecureがないって本当?

あれ、WiFiクライアントにはSecureが~、とか言ったもののGSMクライアントにSecureがないってどうして分かったんだっけ?

…そういえばGSMクライアントのヘッダ見てなくない?…え??まさか…

そうしてTinyGsmClient.hを覗くと…

#include "TinyGsmClientUBLOX.h"
typedef TinyGsmUBLOX                       TinyGsm;
typedef TinyGsmUBLOX::GsmClientUBLOX       TinyGsmClient;
typedef TinyGsmUBLOX::GsmClientSecureUBLOX TinyGsmClientSecure; ←!!!

なんと!GSMClientSecureあるじゃん!!

うおー、気づかなかったー…

ということでTinyGsmClientをTinyGsmClientSecureに変更したところ、無事動作しました!

だいぶ回り道しましたが、HTTPリクエストをよく理解できました。

これでWiFi環境に依存しない携帯回線使用の組み込み機器が作れそうです!

サンプルコード

M5stack側

#include <M5Stack.h>
#define TINY_GSM_MODEM_UBLOX
#include <TinyGsmClient.h>
#include <ArduinoJson.h>

TinyGsm modem(Serial2); /* 3G board modem */
TinyGsmClientSecure ctx(modem);

void Init3G(void){
  Serial2.begin(115200, SERIAL_8N1, 16, 17);
  modem.restart();
  String modemInfo = modem.getModemInfo();
  M5.Lcd.println(modemInfo);
  while (!modem.waitForNetwork()) M5.Lcd.print(".");
  M5.Lcd.println(F("Ok"));
  modem.gprsConnect("soracom.io", "sora", "sora");
  while (!modem.isNetworkConnected()) M5.Lcd.print(".");
  IPAddress ipaddr = modem.localIP();
  M5.Lcd.print(ipaddr);
}

void loop(){
  /* HTTP GET example */
  int stat = ctx.connect("script.google.com", 443);
  if (stat == 0) return;

  // HTTPリクエストの送信
  StaticJsonDocument<500> doc;
  char pubMessage[256];
  // JSONメッセージの作成
  JsonArray temperature = doc.createNestedArray("TEST");
  temperature.add(12);

  ctx.println(F("POST /macros/s/(自分で発行したWEBAPIのURLを書く)/exec HTTP/1.1"));
  ctx.println(F("Host: script.google.com"));
  ctx.println(F("Content-Type: application/json"));
  char content_length_hdr[32];
  sprintf(content_length_hdr, "Content-Length: %lu", strlen(pubMessage));
  ctx.println(F(content_length_hdr));
  ctx.println("");
  ctx.print(F(pubMessage));

  /* receive response */
  while (ctx.connected()) {
    String line = ctx.readStringUntil('\n');
    M5.Lcd.print(line);
    if (line == "\r") {
          M5.Lcd.println("headers received.");
      break;
    }
  }
  char buf[1 * 1024] = {0};
  ctx.readBytes(buf, sizeof(buf)); /* body */
  ctx.stop();
  M5.Lcd.println(buf);
}

GAS側

function doPost(e) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('シート1');
  
  var params = JSON.parse(e.postData.getDataAsString());
  var temp = params.TEMP;

  // データをシートに追加
  sheet.insertRows(2,1);  // 2行1列目に列を挿入する

  sheet.getRange(2, 2).setValue(temp);

   // JSON形式のレスポンスを返す
  var response = {
    message: "Success"
  };
  return ContentService.createTextOutput(JSON.stringify(response)).setMimeType(ContentService.MimeType.JSON);

}

まとめ

WiFiがなくてもソラコムの3G拡張ボードでSecureな通信ができます

TinyGsmClientSecureを使うのがポイント!

コメント

タイトルとURLをコピーしました