ESP32+SIM800L调用OpenWeatherMap API遇HTTP 603错误求助
ESP32+SIM800L调用OpenWeatherMap API出现HTTP 603错误的解决方法
问题背景
已拥有可用的OpenWeatherMap API密钥,在Python环境中可正常获取城市温度数据,但使用ESP32搭配SIM800L模块发起GET请求时,出现HTTP 603错误,无法获取数据,目标是实现HTTP 200响应并解析温度数据。
错误原因分析
HTTP 603在SIM800L模块中通常表示HTTP请求参数格式错误或GPRS连接未正确建立,结合代码来看主要存在以下问题:
- 重复传递API密钥:OpenWeatherMap API仅需通过URL的
appid参数传递密钥,代码中额外通过USERDATA添加Authorization: Bearer头属于冗余操作,会导致请求格式异常。 - GPRS连接验证缺失:setup中仅执行
AT+SAPBR=1,1后延迟1秒,未确认连接是否成功获取IP地址。 - AT命令响应处理不严谨:sendATCommand函数未检查命令执行结果(如是否返回OK),可能导致后续命令在前置命令失败的情况下继续执行。
- HTTP请求等待逻辑不合理:固定延迟15秒无法适配网络波动,且可能错过响应时机。
- HTTP连接未正确关闭:
AT+HTTPTERM放在return语句之后,永远不会执行,导致模块HTTP资源占用。
修复步骤
- 移除冗余的Bearer认证:删除通过
AT+HTTPPARA="USERDATA"传递API密钥的代码。 - 验证GPRS连接状态:在setup中添加
AT+SAPBR=2,1命令,确认模块已获取IP地址,确保GPRS连接正常。 - 优化AT命令执行逻辑:修改sendATCommand函数,等待并检查响应是否包含
OK,确保命令执行成功后再继续。 - 替换固定延迟为响应等待:执行
AT+HTTPACTION=0后,等待模块返回+HTTPACTION:响应,确认请求完成。 - 调整HTTPTERM位置:将
AT+HTTPTERM移至函数末尾,确保每次请求后都关闭HTTP连接。 - 确认APN正确性:根据SIM卡运营商替换APN,如移动用
cmnet、联通用3gnet、电信用ctnet,避免因APN错误导致网络不通。
修正后的完整代码
#include <Arduino.h> #include <SoftwareSerial.h> #define SIM800L_IP5306_VERSION_20200811 #include "utilities.h" #include <ArduinoJson.h> SoftwareSerial sim800lSerial(26, 27); // RX, TX const char* apiKey = "bbb1506b80137280e7cbdc2c3c72e628"; const char* city = "adana"; const char* apn = "internet"; // 根据运营商修改,如cmnet/3gnet/ctnet void setupModem() { #ifdef MODEM_RST pinMode(MODEM_RST, OUTPUT); digitalWrite(MODEM_RST, HIGH); #endif pinMode(MODEM_PWRKEY, OUTPUT); pinMode(MODEM_POWER_ON, OUTPUT); digitalWrite(MODEM_POWER_ON, HIGH); digitalWrite(MODEM_PWRKEY, HIGH); delay(100); digitalWrite(MODEM_PWRKEY, LOW); delay(1000); digitalWrite(MODEM_PWRKEY, HIGH); pinMode(LED_GPIO, OUTPUT); digitalWrite(LED_GPIO, LED_OFF); } // 发送AT命令并等待OK响应 bool sendATCommand(String command, int timeout = 2000) { sim800lSerial.println(command); unsigned long start = millis(); String response = ""; while (millis() - start < timeout) { while (sim800lSerial.available()) { char c = sim800lSerial.read(); response += c; Serial.write(c); } if (response.indexOf("OK") != -1) { return true; } if (response.indexOf("ERROR") != -1) { return false; } } return false; } String readResponse(int timeout = 5000) { String response = ""; unsigned long start = millis(); while (millis() - start < timeout) { while (sim800lSerial.available()) { char c = sim800lSerial.read(); response += c; } } return response; } void setup() { Serial.begin(115200); sim800lSerial.begin(115200); setupModem(); delay(10000); // 初始化SIM800L并验证连接 if (!sendATCommand("AT")) { Serial.println("模块未响应"); while(1); } sendATCommand("AT+SAPBR=3,1,\"Contype\",\"GPRS\""); sendATCommand("AT+SAPBR=3,1,\"APN\",\"" + String(apn) + "\""); if (!sendATCommand("AT+SAPBR=1,1", 5000)) { Serial.println("GPRS连接失败"); while(1); } // 检查是否获取到IP sendATCommand("AT+SAPBR=2,1"); } float getTemperature(const char* city) { // 初始化HTTP if (!sendATCommand("AT+HTTPINIT")) { Serial.println("HTTP初始化失败"); return -999; } sendATCommand("AT+HTTPPARA=\"CID\",1"); String url = "http://api.openweathermap.org/data/2.5/weather?q="; url += city; url += "&appid="; url += apiKey; if (!sendATCommand("AT+HTTPPARA=\"URL\",\"" + url + "\"")) { sendATCommand("AT+HTTPTERM"); return -999; } // 发起GET请求 sim800lSerial.println("AT+HTTPACTION=0"); unsigned long start = millis(); String actionResp = ""; bool requestDone = false; int httpCode = -1; // 等待+HTTPACTION响应 while (millis() - start < 15000) { while (sim800lSerial.available()) { char c = sim800lSerial.read(); actionResp += c; Serial.write(c); if (actionResp.indexOf("+HTTPACTION:") != -1) { // 解析HTTP状态码 int codePos = actionResp.indexOf(",") + 1; httpCode = actionResp.substring(codePos, codePos+3).toInt(); requestDone = true; break; } } if (requestDone) break; } if (httpCode != 200) { Serial.print("HTTP请求失败,状态码:"); Serial.println(httpCode); sendATCommand("AT+HTTPTERM"); return -999; } // 读取响应内容 sendATCommand("AT+HTTPREAD"); String response = readResponse(); if (response == "") { Serial.println("未读取到响应内容"); sendATCommand("AT+HTTPTERM"); return -999; } // 解析JSON DynamicJsonDocument doc(2048); DeserializationError error = deserializeJson(doc, response); if (!error) { float temperature = doc["main"]["temp"]; temperature -= 273.15; sendATCommand("AT+HTTPTERM"); return temperature; } else { Serial.println("JSON解析失败"); sendATCommand("AT+HTTPTERM"); return -999; } } void loop() { float temperature = getTemperature(city); if (temperature != -999) { Serial.print(city); Serial.print(" 当前温度:"); Serial.print(temperature); Serial.println(" °C"); } else { Serial.println("获取温度失败"); } delay(600000); // 10分钟 }
额外注意事项
- 确保SIM卡已开通GPRS服务,且信号正常(可通过
AT+CSQ命令查看信号强度,返回值>=10表示信号良好)。 - 如果仍有问题,可通过
AT+HTTPDEBUG=1开启HTTP调试模式,查看详细的请求和响应内容,进一步定位问题。
内容的提问来源于stack exchange,提问作者enis
相关产品推荐
相关产品推荐

