
400エラーが返るんだけど??
こうした悩みを解決する記事を書きたいのですが、分からず苦しんでます…
と記事を書き始めたものの、書いてる途中に解決しました。
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を使うのがポイント!
 
  
  
  
   
    
コメント