This is the multi-page printable view of this section. Click here to print...

Return to the regular view of this page

As of 2025-07-24

Using the REST API

mwings-v1.1.3
    This is an explanation of the sample sketch spot-httpbin, which acts as a Wi-Fi child device and sends received packet data to the mock server httpbin.org.

    Getting the Source Code

    You can obtain it from the GitHub repository monowireless/spot-httpbin.

    System Overview

    spot-httpbin sends part of the data received by the TWELITE parent device along with the current time obtained via NTP as an HTTP GET request to a mock server, and displays the response on the serial monitor.

    Requirements for Development

    Environment Setup

    Installing IDE and Toolchain

    See Setting up the development environment using Arduino IDE 1.x.

    Installing Libraries

    This sample includes required libraries from the beginning.

    Obtaining the Project Files

    1. Download the ZIP file from GitHub (monowireless/spot-httpbin)
    2. Extract the ZIP file and rename the folder from spot-httpbin-main to spot-httpbin
    3. Place the spot-httpbin folder in your Arduino sketchbook directory (set in Arduino IDE preferences, e.g. C:\Users\foo\Documents\Arduino)

    Modifying User Settings

    Open config.h from the tabs at the top of the Arduino IDE and set your Wi-Fi SSID and password. WPA2-PSK network is assumed. Also, register the root certificate. The root certificate can be obtained from the security page for each website using Chrome or another browser.

    Writing the Project File

    See How to upload a sketch to the ESP32.

    Sketch

    This section explains the Arduino sketch spot-httpbin.ino and config.h.

    Including Libraries

    Official Arduino and ESP32 Libraries

    Lines 4–6 include official Arduino and ESP32 libraries.

    #include <Arduino.h>
    #include <WiFiClientSecure.h>
    #include <WiFiUdp.h>
    Header FileDescriptionRemarks
    Arduino.hBasic Arduino libraryCan sometimes be omitted, but included for safety
    WiFiClientSecure.hEnables SSL communication on ESP32
    WiFiUdp.hHandles UDP communicationRequired for NTP

    Third-Party Libraries

    Lines 9–10 include bundled third-party libraries.

    #include "src/NTPClient/NTPClient.h"
    #include "src/Time/TimeLib.h"
    Header FileDescriptionRemarks
    NTPClient.hAccesses NTP servers
    TimeLib.hConverts epoch time

    MWings Library

    Line 13 includes the MWings library.

    #include <MWings.h>

    Defining User Settings

    Line 16 includes the configuration file.

    #include "config.h"

    Definition of Data Types

    Lines 19–26 define the struct type used to store data received from the child device.

    struct DataFromAria {
        uint32_t serialId;
        uint8_t logicalId;
        uint16_t supplyVoltage;
        uint8_t linkQuality;
        int16_t temp100x;
        uint16_t humid100x;
    };
    NameDescription
    serialIdSerial ID
    logicalIdLogical device ID
    supplyVoltageSupply voltage
    linkQualityLQI (Link Quality Index)
    temp100xTemperature ×100
    humid100xHumidity ×100

    Here, TWELITE ARIA is used.

    config.h

    Definition of Reboot Interval

    Line 4 of config.h specifies the reboot interval for the ESP32.

    const uint32_t REBOOT_INTERVAL = 21600; // seconds
    

    Here, 21600 seconds = 6 hours.

    Definition of TWELITE Settings

    Lines 7–8 of config.h define the settings applied to the TWELITE parent device installed in TWELITE SPOT.

    const uint8_t TWE_CH = 18;
    const uint32_t TWE_APPID = 0x67720102;
    NameDescription
    TWE_CHTWELITE channel
    TWE_APPIDTWELITE application ID

    Definition of Wi-Fi Settings

    Lines 11–12 of config.h define the Wi-Fi settings applied to the ESP32 installed in TWELITE SPOT.

    const char* WIFI_SSID = "YOUR SSID";
    const char* WIFI_PASSWORD = "YOUR PASSWORD";
    NameDescription
    WIFI_SSIDSSID of the network to connect to
    WIFI_PASSWORDPassword of the network to connect to

    Root Certificate

    Lines 14–16 of config.h provide a template for describing the contents of the root certificate.

    const char *CA_CERT =
        "-----BEGIN CERTIFICATE-----\n"
        "-----END CERTIFICATE-----\n";

    Obtain the root certificate from the security screen for each website using Chrome or another web browser. All lines must be enclosed in double quotes, and a newline character \n must be added before the ending double quote.

    Host Settings

    Lines 18–19 of config.h define the host settings.

    const char *SERVER_HOST = "www.httpbin.org";
    const uint16_t SERVER_PORT = 443;
    NameDescription
    SERVER_HOSTServer host name
    SERVER_PORTServer port number

    Definition of Various Constants

    From line 21 of config.h, various constants are defined.

    const uint32_t NTP_UPDATE_INTERVAL = 10000; // ms
    
    const int QUERIES_MAX_LENGTH = 128;         // bytes (without \0)
    const int32_t CONNECT_TIMEOUT = 10;     // seconds
    const uint32_t RECONNECT_MIN_INTERVAL = 5; // seconds
    // SEND_MIN_INTERVAL must be longer than NTP_UPDATE_INTERVAL
    const uint32_t SEND_MIN_INTERVAL = 10; // seconds
    const uint32_t REQUEST_TIMEOUT = 10;   // seconds
    
    NameDescription
    NTP_UPDATE_INTERVALInterval for obtaining NTP time
    QUERIES_MAX_LENGTHMaximum length of query string (excluding null character)
    CONNECT_TIMEOUTTimeout when connecting to the server
    RECONNECT_MIN_INTERVALMinimum interval when reconnecting to Wi-Fi access point
    SEND_MIN_INTERVALMinimum interval between requests
    REQUEST_TIMEOUTTimeout from request to response

    Definition of Pin Numbers

    Lines 29–31 define the pin numbers.

    static const int RST_PIN = 5;
    static const int PRG_PIN = 4;
    static const int LED_PIN = 18;
    NameDescription
    RST_PINPin number connected to TWELITE’s RST pin
    PRG_PINPin number connected to TWELITE’s PRG pin
    LED_PINPin number connected to the ESP32 LED on the board

    Declaration of Global Objects

    Lines 34–37 declare global objects.

    static WiFiClientSecure client;
    static WiFiUDP ntpUDP;
    static NTPClient timeClient(ntpUDP, "ntp.nict.jp",
                                32400, NTP_UPDATE_INTERVAL); // JST(UTC+9)
    
    NameDescription
    clientInterface for HTTPS communication
    ntpUDPInterface for UDP communication for NTP
    timeClientInterface for NTP

    Declaration of Global Variables

    Lines 40–41 declare global variables.

    static DataFromAria LatestDataFromAria;
    static bool IsThereNewDataFromAria;
    NameDescription
    LatestDataFromAriaLatest data received from TWELITE ARIA
    IsThereNewDataFromAriaFlag indicating new data has been received from TWELITE ARIA

    Declaration of Function Prototypes

    Lines 44–56 declare function prototypes.

    void anotherLoopForTWELITE();
    void anotherLoopForNTP();
    NameDescription
    anotherLoopForTWELITELoop function for processing TWELITE data
    anotherLoopForNTPLoop function for obtaining time via NTP
    void initTWELITE();
    void initWiFi();
    void initNTP();
    NameDescription
    initTWELITEFunction to initialize TWELITE
    initWiFiFunction to initialize Wi-Fi
    initNTPFunction to initialize NTP
    void onAppAriaPacket(const ParsedAppAriaPacket& packet);
    NameDescription
    onAppAriaPacketCallback function when data is received from TWELITE ARIA
    void sendAriaData(const DataFromAria& data)
    NameDescription
    sendAriaDataFunction to send TWELITE ARIA data via HTTP GET request

    setup()

    Lines 59–87 perform overall initialization.

    void setup() {
        Serial.begin(115200);
    
        initTWELITE();
        initWiFi();
        initNTP();
    
        // Attach another loop function for TWELITE
        // Note: Core 0 is also used for the WiFi task, which priority is 19 (ESP_TASKD_EVENT_PRIO - 1)
        xTaskCreatePinnedToCore(
            [](void *params) {
                while (true) {
                    anotherLoopForTWELITE();
                    vTaskDelay(1); // IMPORTANT for Watchdog
                }
            },
            "Task for anotherLoopForTWELITE()", 8192, nullptr, 18, nullptr,
            0); // Priority is 18 (lower than WiFi)
        // Attach another loop function for NTP
        xTaskCreatePinnedToCore(
            [](void *params) {
                while (true) {
                    anotherLoopForNTP();
                    vTaskDelay(1); // IMPORTANT for Watchdog
                }
            },
            "Task for anotherLoopForNTP()", 8192, nullptr, 17, nullptr,
            0); // Priority is 17 (lower than WiFi and TWELITE)
    }

    xTaskCreatePinnedToCore() is used to register a separate task from the loop() function.

    The following part is an unnamed function without a capture. This avoids unnecessary pollution of the global namespace.

            [](void *params) {
                while (true) {
                    anotherLoopForTWELITE();
                    vTaskDelay(1); // IMPORTANT for Watchdog
                }
            },

    loop()

    Lines 90–111 are the main loop process.

    This handles HTTP requests, reconnection to Wi-Fi when disconnected, and periodic resets.

    void loop() {
        static uint32_t lastTimeReconnected = 0;
        if (WiFi.status() == WL_CONNECTED) {
            // Regular operations
            // Check for new data
            if (IsThereNewDataFromAria) {
                IsThereNewDataFromAria = false; // Clear first; data is updated on another thread
                DataFromAria data = LatestDataFromAria; // Now, the buffer is open for incoming data
                sendAriaData(data);
            }
        } else if (millis() - lastTimeReconnected > RECONNECT_MIN_INTERVAL * 1000) {
            // Lost connection, reconnect periodically
            Serial.println("Disconnected. Reconnecting to WiFi...");
            WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
            lastTimeReconnected = millis();
        }
        // Reboot every x interval
        if (millis() > REBOOT_INTERVAL * 1000) {
            Serial.println("Rebooting...");
            ESP.restart();
        }
    }

    anotherLoopForTWELITE()

    Lines 114–116 are the loop process for TWELITE.

    To sequentially receive and interpret data, this is run as a separate task from the (potentially blocking) loop().

    void anotherLoopForTWELITE() {
        Twelite.update();
    }

    anotherLoopForNTP()

    Lines 117–120 are the loop process for NTP.

    Since this involves UDP communication, it is also run as a separate task from the (potentially blocking) loop().

    void anotherLoopForNTP() {
        timeClient.update();
        setTime(timeClient.getEpochTime());
    }

    initTWELITE()

    Lines 123–130 perform the initialization process for TWELITE.

    This starts the TWELITE installed in TWELITE SPOT with the specified settings and registers a callback function for packet reception.

    void initTWELITE() {
        Serial2.begin(115200);
        if (Twelite.begin(Serial2, LED_PIN, RST_PIN, PRG_PIN, TWE_CHANNEL, TWE_APP_ID)) {
            Serial.println("Started TWELITE.");
        }
        // Attach event handlers to process packets
        Twelite.on(onAppAriaPacket);
    }

    initWiFi()

    Lines 133–157 perform Wi-Fi initialization.

    If not connected, reconnection is attempted every 5 seconds.

    void initWiFi() {
        Serial.print("\nConnecting to the WiFi network ");
        Serial.print(WIFI_SSID);
        Serial.println("...");
        // Begin
        WiFi.mode(WIFI_STA);
        WiFi.setAutoReconnect(true);
        WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
        // Wait for connection
        Serial.print("Connecting.");
        while (WiFi.status() != WL_CONNECTED) x
            static int count = 0;
            Serial.print('.');
            delay(500);
            // Retry every 5 seconds
            if (count++ % 10 == 0) {
                WiFi.disconnect();
                WiFi.reconnect();
                Serial.print('!');
            }
        }
        Serial.println("\nConnected!");
        // Set Root CA certificate
        client.setCACert(CA_CERT);
    }

    initNTP()

    Lines 160–164 perform NTP initialization.

    void initNTP() {
        timeClient.begin();
        timeClient.update();
        setTime(timeClient.getEpochTime());
    }

    onAppAriaPacket()

    Lines 167–177 describe the process performed when data is received from TWELITE ARIA.

    Here, HTTP transmission is not performed; instead, the data is set to a global variable. The data set in the global variable is processed by sendAriaData() in a separate task.

    void onAppAriaPacket(const ParsedAppAriaPacket& packet)
    {
        // Store data
        LatestDataFromAria.serialId = packet.u32SourceSerialId;
        LatestDataFromAria.logicalId = packet.u8SourceLogicalId;
        LatestDataFromAria.supplyVoltage = packet.u16SupplyVoltage;
        LatestDataFromAria.linkQuality = packet.u8Lqi;
        LatestDataFromAria.temp100x = packet.i16Temp100x;
        LatestDataFromAria.humid100x = packet.u16Humid100x;
        IsThereNewDataFromAria = true;
    }

    sendAriaData()

    Lines 180–237 define a function that sets TWELITE ARIA data into the query string of an HTTP GET request and sends it.

    To avoid excessive load on the server, transmission is skipped if packets arrive too frequently.

    void sendAriaData(const DataFromAria& data)
    {
        static uint32_t lastTimeRequested = 0;
        if (millis() - lastTimeRequested > SEND_MIN_INTERVAL * 1000 or lastTimeRequested == 0) {
            Serial.println("Connecting to the server...");
            if (not client.connect(SERVER_HOST, SERVER_PORT, CONNECT_TIMEOUT * 1000)) {
                Serial.println("Connection failed!");
            } else {
                Serial.println("Connected to the server!");
                // Make a query string
                char queries[QUERIES_MAX_LENGTH+1];
                snprintf(queries, sizeof(queries),
                         "datetime=%04d%02d%02d%02d%02d%02d&sid=%X&lid=%d&temp=%d&humid=%d&bat=%d&lqi=%d",
                         // Note that NTP_UPDATE_INTERVAL is set for 10000ms by default; second() delays up to 10s.
                         // To prevent duplication of datetime, SEND_MIN_INTERVAL is set for 10s.
                         year(), month(), day(), hour(), minute(), second(),
                         data.serialId,
                         data.logicalId,
                         data.temp100x,
                         data.humid100x,
                         data.supplyVoltage,
                         data.linkQuality);
    
                // Send a request
                client.println(String("GET https://") +
                               SERVER_HOST +
                               String("/get?") +
                               queries +
                               String(" HTTP/1.1"));
                client.println("Accept: */*");
                client.println(String("Host: ") + SERVER_HOST);
                client.println("Connection: close");
                client.println();
                uint32_t timeSentRequest = millis();
    
                // Handle a response
                while (client.connected()) {
                    String line = client.readStringUntil('\n');
                    if (line == "\r") {
                        Serial.println("Headers received");
                        break;
                    }
                    if (millis() - timeSentRequest > REQUEST_TIMEOUT * 1000) {
                        Serial.println("Request was timed out");
                        break;
                    }
                }
                while (client.available()) {
                    char c = client.read();
                    Serial.write(c);
                }
                client.stop();
            }
            lastTimeRequested = millis();
        } else {
            Serial.println("Requests are too frequently; skip.");
        }
    }