#include <WiFi.h>
#include <WiFiClientSecure.h>
#define HTTP_REQUEST_VERSION "HTTP/1.0"
#define HTTP_GET_REQUEST "GET"
#define HTTP_POST_REQUEST "POST"
#define HTTP_HEADER_HOST "Host"
#define HTTP_HEADER_CONTENT_LEN "Content-Length"
#define HTTP_HEADER_ROBOT_ID "robot-id"
#define HTTP_HEADER_CONNECTION_CLOSE "Connection: close"
#define API_HOST_PORT 443
#define API_HOST "robot-api.hacknao.edu.vn"
#define API_PATH_WR_INIT "/robot/api/v1/device/game/word_race/init"
#define API_PATH_WR_SUMMARY "/robot/api/v1/device/game/word_race/summary"
#define API_READ_HEADER_TIMEOUT 30000
#define API_READ_RESPONSE_TIMEOUT 30000
typedef enum {
API_OK = (0),
API_WIFI_DISCONNECTED,
API_HOST_CONNECT_FAILED,
API_HEADER_TIMEOUT,
API_RESPONSE_TIMEOUT,
API_RESPONSE_PARSE_ERROR,
API_RESPONSE_STATUS_ERROR,
} ApiReturnType_e;
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* server = "www.howsmyssl.com"; // Server URL
// www.howsmyssl.com root certificate authority, to verify the server
// change it to your server root CA
// SHA1 fingerprint is broken now!
const char* test_root_ca= \
"-----BEGIN CERTIFICATE-----\n" \
"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\n" \
"-----END CERTIFICATE-----\n";
// You can use x.509 client certificates if you want
//const char* test_client_key = ""; //to verify the client
//const char* test_client_cert = ""; //to verify the client
WiFiClientSecure _client;
ApiReturnType_e BACKEND_PostRequest(const char *host, const char *path, String &response, String &headers)
{
ApiReturnType_e ret = API_OK;
unsigned long long lrequest_time = 0;
char buffer[128] = {0};
if (WiFi.status() == WL_CONNECTED)
{
_client.setInsecure();
if (!_client.connect(host, API_HOST_PORT)) {
log_e("Failed to connect to server: %s:%d", host, API_HOST_PORT);
ret = API_HOST_CONNECT_FAILED;
} else {
uint16_t distance = 20;
uint16_t score = 1250;
String json_data = "{\"distance\": " + String(distance) + ",\"word_count\": " + String(distance) + ",\"score\": " + String(score) + "}";
log_i("Server connected: %s:%d", host, API_HOST_PORT);
Serial.println(json_data);
/* Make a HTTP request */
sprintf(buffer, "%s %s %s", F(HTTP_POST_REQUEST), path, F(HTTP_REQUEST_VERSION));
_client.println(buffer);
sprintf(buffer, "%s: %s", F(HTTP_HEADER_HOST), host);
_client.println(buffer);
sprintf(buffer, "%s: %s", F(HTTP_HEADER_ROBOT_ID), "123");
_client.println(buffer);
_client.println("Content-Type: application/json");
sprintf(buffer, "%s: %d", F(HTTP_HEADER_CONTENT_LEN), json_data.length());
_client.println(buffer);
_client.println(F(HTTP_HEADER_CONNECTION_CLOSE));
_client.println();
/* POST data */
_client.println(json_data.c_str());
_client.println();
/* Read headers */
lrequest_time = millis();
while (_client.connected()) {
String line = _client.readStringUntil('\n');
if (line == "\r") {
log_d("Response headers received!");
break;
}
if (millis() - lrequest_time > API_READ_HEADER_TIMEOUT) {
ret = API_HEADER_TIMEOUT;
break;
}
}
/* Read response */
if (API_OK == ret) {
lrequest_time = millis();
while (_client.available()) {
response += (char)(_client.read());
if (millis() - lrequest_time > API_READ_RESPONSE_TIMEOUT) {
ret = API_RESPONSE_TIMEOUT;
break;
}
}
}
_client.stop();
}
} else {
ret = API_WIFI_DISCONNECTED;
}
return ret;
}
ApiReturnType_e BACKEND_GetRequest(const char *host, const char *path, String &response, String &headers)
{
ApiReturnType_e ret = API_OK;
unsigned long long lrequest_time = 0;
char buffer[128] = {0};
if (WiFi.status() == WL_CONNECTED)
{
_client.setInsecure();
if (!_client.connect(host, API_HOST_PORT)) {
Serial.printf("Failed to connect to server: %s:%d", host, API_HOST_PORT);
ret = API_HOST_CONNECT_FAILED;
} else {
Serial.printf("Server connected: %s:%d", host, API_HOST_PORT);
/* Make a HTTP request */
sprintf(buffer, "%s %s %s", F(HTTP_GET_REQUEST), path, F(HTTP_REQUEST_VERSION));
_client.println(buffer);
sprintf(buffer, "%s: %s", F(HTTP_HEADER_HOST), host);
_client.println(buffer);
sprintf(buffer, "%s: %s", F(HTTP_HEADER_ROBOT_ID), "123");
_client.println(buffer);
_client.println(F(HTTP_HEADER_CONNECTION_CLOSE));
_client.println();
/* Read headers */
lrequest_time = millis();
while (_client.connected()) {
String line = _client.readStringUntil('\n');
if (line == "\r") {
Serial.printf("Response headers received!");
break;
}
if (millis() - lrequest_time > API_READ_HEADER_TIMEOUT) {
ret = API_HEADER_TIMEOUT;
break;
}
}
/* Read response */
if (API_OK == ret) {
lrequest_time = millis();
while (_client.available()) {
response += (char)(_client.read());
if (millis() - lrequest_time > API_READ_RESPONSE_TIMEOUT) {
ret = API_RESPONSE_TIMEOUT;
break;
}
}
}
_client.stop();
}
} else {
ret = API_WIFI_DISCONNECTED;
}
return ret;
}
void setup() {
//Initialize serial and wait for port to open:
Serial.begin(115200);
delay(100);
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
// attempt to connect to Wifi network:
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
// wait 1 second for re-trying
delay(1000);
}
Serial.print("Connected to ");
Serial.println(ssid);
String response = "";
String headers = "";
// ApiReturnType_e ret = BACKEND_GetRequest(API_HOST, API_PATH_WR_INIT, response, headers);
ApiReturnType_e ret = BACKEND_PostRequest(API_HOST, API_PATH_WR_SUMMARY, response, headers);
if (ret == API_OK)
{
Serial.println("Response OK:");
Serial.println(response);
} else {
LocalPrintApiError(ret);
}
}
void loop() {
// do nothing
}
void LocalPrintApiError(ApiReturnType_e ret)
{
switch (ret)
{
case API_OK: break;
case API_WIFI_DISCONNECTED:
Serial.printf("API_WIFI_DISCONNECTED"); break;
case API_HOST_CONNECT_FAILED:
Serial.printf("API_HOST_CONNECT_FAILED"); break;
case API_HEADER_TIMEOUT:
Serial.printf("API_HEADER_TIMEOUT"); break;
case API_RESPONSE_TIMEOUT:
Serial.printf("API_RESPONSE_TIMEOUT"); break;
case API_RESPONSE_PARSE_ERROR:
Serial.printf("API_RESPONSE_PARSE_ERROR"); break;
case API_RESPONSE_STATUS_ERROR:
Serial.printf("API_RESPONSE_STATUS_ERROR"); break;
default: break;
}
}