Hello
I'm trying to connect to a Google Apps Script (GAS) server using ESP32/SIM7600 to send data. However, after receiving a 302 response, when I access the redirection URL "https://script.googleusercontent.com/macros/echo?user_content_keynone", I get a 404 error.
I think the issue is with "user_content_keynone" in the URL - it looks incorrect and the server isn't responding with the proper address. Is there something wrong with my configuration? Does anyone know how to fix this?
Thank you for your support!
When I access the site through a web browser on my PC, the redirection URL looks like this:
Code ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
#define TINY_GSM_MODEM_SIM7600
#define SerialMon Serial // デバッグ用のシリアル
#define SerialAT Serial1 // AT コマンド用のシリアル
#define TINY_GSM_DEBUG SerialMon
// GPRS credentials
const char apn[] = "soracom.io";
const char gprsUser[] = "xxxx";
const char gprsPass[] = "xxxx";
#include <TinyGsmClient.h>
#include <Ticker.h>
TinyGsm modem(SerialAT);
// アクセス先の設定
const char server[] = "script.google.com";
const char resource[] = "/macros/s/AKfycbxxxYkTbjN63KQlr8Z9yEsaPm7eHOlwdPqhq1J2p7XaSQ8X-6VCK3g91W4H3WIkuzMX/exec";
Ticker tick;
#define TIME_TO_SLEEP 60
#define PIN_TX 27
#define PIN_RX 26
#define UART_BAUD 115200
#define PWR_PIN 4
#define LED_PIN 12
#define POWER_PIN 25
#define IND_PIN 36
bool reply = false;
void modem_on() {
Serial.println("\nStarting Up Modem...");
pinMode(PWR_PIN, OUTPUT);
digitalWrite(PWR_PIN, HIGH);
delay(300);
digitalWrite(PWR_PIN, LOW);
delay(10000);
int i = 10;
Serial.println("\nTesting Modem Response...\n");
while (i) {
SerialAT.println("AT");
delay(500);
if (SerialAT.available()) {
String r = SerialAT.readString();
Serial.println(r);
if (r.indexOf("OK") >= 0) {
reply = true;
break;
}
}
delay(500);
i--;
}
}
// リダイレクト先URLに対してGETリクエストを送信する関数
void sendRedirectRequest(String baseUrl, String data) {
// URLにパラメータを追加
String url = baseUrl;
if (url.indexOf("?") >= 0) {
url += "&info=" + data; // すでに?がある場合は&で追加
} else {
url += "?info=" + data; // ?がない場合は?で追加
}
SerialMon.println("\n====== Sending GET request to redirect URL ======");
SerialMon.println("URL with params: " + url);
// URLを設定
SerialAT.println("AT+HTTPPARA=\"URL\",\"" + url + "\"");
delay(1000);
printResponse();
// GETリクエストを実行
SerialMon.println("Executing GET request to redirect URL");
SerialAT.println("AT+HTTPACTION=0"); // 0 = GET
delay(10000);
// レスポンスを待つ
bool httpActionComplete = false;
int statusCode = 0;
int responseLength = 0;
unsigned long startTime = millis();
while (millis() - startTime < 20000) {
if (SerialAT.available()) {
String response = SerialAT.readStringUntil('\n');
response.trim();
SerialMon.println(">> " + response);
if (response.indexOf("+HTTPACTION: 0,") >= 0) {
httpActionComplete = true;
int firstComma = response.indexOf(',');
int secondComma = response.indexOf(',', firstComma + 1);
statusCode = response.substring(firstComma + 1, secondComma).toInt();
responseLength = response.substring(secondComma + 1).toInt();
break;
}
}
delay(100);
}
SerialMon.println("Redirect Response - Status Code: " + String(statusCode));
SerialMon.println("Redirect Response - Length: " + String(responseLength));
if (responseLength > 0) {
// レスポンスボディを読み取る
SerialMon.println("\n====== Reading response from redirect URL ======");
SerialAT.println("AT+HTTPREAD");
delay(1000);
// レスポンスの読み取り
startTime = millis();
bool dataStarted = false;
String responseBody = "";
while (millis() - startTime < 5000) {
if (SerialAT.available()) {
String line = SerialAT.readStringUntil('\n');
line.trim();
SerialMon.println(">> " + line);
if (line.indexOf("+HTTPREAD: ") >= 0) {
dataStarted = true;
continue;
}
if (dataStarted && line.length() > 0 && line != "OK") {
responseBody = line;
break;
}
}
delay(100);
}
if (responseBody.length() > 0) {
SerialMon.println("\n====== Final Response Content ======");
SerialMon.println("Response: " + responseBody);
}
}
}
void sendHTTPSRequest() {
// 前回のセッションを確実に終了
SerialMon.println("\n====== Cleanup previous session ======");
SerialAT.println("AT+HTTPTERM");
delay(1000);
printResponse();
// HTTPSサービスを開始
SerialMon.println("\n====== Starting HTTPS service ======");
SerialAT.println("AT+HTTPINIT");
delay(1000);
printResponse();
// 正しいURLを設定
String url = "https://script.google.com/macros/s/AKfycbxxxYkTbjN63KQlr8Z9yEsaPm7eHOlwdPqhq1J2p7XaSQ8X-6VCK3g91W4H3WIkuzMX/exec";
SerialMon.println("\n====== Setting URL parameter ======");
SerialMon.println("URL: " + url);
SerialAT.println("AT+HTTPPARA=\"URL\",\"" + url + "\"");
delay(1000);
printResponse();
// User-Agentを設定
SerialMon.println("\n====== Setting User-Agent ======");
SerialAT.println("AT+HTTPPARA=\"UA\",\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36\"");
delay(1000);
printResponse();
// Content-Typeを設定
SerialMon.println("\n====== Setting content type ======");
SerialAT.println("AT+HTTPPARA=\"CONTENT\",\"application/json\"");
delay(1000);
printResponse();
// POSTデータを準備
String postData = "{\"info\":\"20250127,20250128,20250129\"}";
int dataLength = postData.length();
// データ入力モードを開始
SerialMon.println("\n====== Input HTTPS data ======");
SerialAT.println("AT+HTTPDATA=" + String(dataLength) + ",10000");
// DOWNLOADプロンプトを待つ
bool downloadReady = false;
unsigned long startTime = millis();
while (millis() - startTime < 5000) {
if (SerialAT.available()) {
String response = SerialAT.readStringUntil('\n');
response.trim();
SerialMon.println(">> " + response);
if (response.indexOf("DOWNLOAD") >= 0) {
downloadReady = true;
break;
}
}
delay(100);
}
if (downloadReady) {
// データを送信
SerialMon.println("\n====== Sending data ======");
SerialAT.print(postData);
delay(1000);
printResponse();
// POSTリクエストを実行
SerialMon.println("\n====== Execute HTTPS POST ======");
SerialAT.println("AT+HTTPACTION=1");
delay(10000);
// レスポンスを待つ
bool httpActionComplete = false;
String redirectUrl = "";
startTime = millis();
while (millis() - startTime < 20000) {
if (SerialAT.available()) {
String response = SerialAT.readStringUntil('\n');
response.trim();
SerialMon.println(">> " + response);
if (response.indexOf("+HTTPACTION: 1,302,") >= 0) {
// 302レスポンスを受信したらヘッダーを読み取る
SerialMon.println("\n====== Reading redirect location ======");
SerialAT.println("AT+HTTPHEAD");
delay(1000);
// Locationヘッダーを探す
while (SerialAT.available()) {
String line = SerialAT.readStringUntil('\n');
line.trim();
SerialMon.println(">> " + line);
if (line.startsWith("Location: ")) {
redirectUrl = line.substring(10);
break;
}
}
break;
}
}
delay(100);
}
// リダイレクト先URLが見つかった場合、新しいGETリクエストを送信
if (redirectUrl.length() > 0) {
SerialMon.println("\nFound redirect URL: " + redirectUrl);
// 元のPOSTデータから "info" の値を抽出
String info = "20250127,20250128,20250129"; // 元のJSONから値を抽出
sendRedirectRequest(redirectUrl, info);
}
}
// HTTPSセッションを終了
SerialMon.println("\n====== Terminating HTTPS session ======");
SerialAT.println("AT+HTTPTERM");
delay(1000);
printResponse();
}
// レスポンス表示用の補助関数
void printResponse() {
while (SerialAT.available()) {
String line = SerialAT.readStringUntil('\n');
if (line.length() > 0) {
line.trim();
SerialMon.println(">> " + line);
}
}
}
void setup() {
// 初期化
SerialMon.begin(115200);
delay(10);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
pinMode(POWER_PIN, OUTPUT);
digitalWrite(POWER_PIN, HIGH);
delay(3000);
SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
// モデム初期化
int retry = 5;
while (!reply && retry--) {
modem_on();
}
if (!modem.init()) {
SerialMon.println("Failed to restart modem");
return;
}
// LTEモードに設定
while (!modem.setNetworkMode(38)) {
delay(500);
}
// LED点滅設定
pinMode(IND_PIN, INPUT);
attachInterrupt(
IND_PIN, []() {
detachInterrupt(IND_PIN);
tick.attach_ms(1000, []() {
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
});
},
CHANGE);
// ネットワーク接続
SerialMon.println("Waiting for network...");
if (!modem.waitForNetwork()) {
delay(10000);
return;
}
if (modem.isNetworkConnected()) {
SerialMon.println("Network connected");
}
// GPRS接続
SerialMon.println("Connecting to " + String(apn));
if (!modem.gprsConnect(apn, gprsUser, gprsPass)) {
delay(10000);
return;
}
if (modem.isGprsConnected()) {
SerialMon.println("GPRS connected");
}
// HTTPSリクエスト実行
sendHTTPSRequest();
// 接続終了処理
modem.gprsDisconnect();
if (!modem.isGprsConnected()) {
SerialMon.println("GPRS disconnected");
}
modem.poweroff();
SerialMon.println("Modem power off");
// ディープスリープ設定
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000ULL);
delay(1000);
esp_deep_sleep_start();
}
void loop() {
// ディープスリープを使用しているため、このループは実行されません
}