jason millington jason millington - 13 days ago 10
C Question

Arduino turn char into a string

I am trying to turn a char into a string so I can extract the values I am interested in, however it just appears empty
the variable I am interested in is content.

I am perfoming a get and it retuns a json object. and want to extract the sunrise and sunset values.

#include <SPI.h>
#include <Ethernet2.h>

EthernetClient client;

const char* server = "api.sunrise-sunset.org"; // server's address
const char* resource = "/json?lat=53.440&lng=0.200&date=today"; // http resource
const unsigned long BAUD_RATE = 9600; // serial connection speed
const unsigned long HTTP_TIMEOUT = 10000; // max respone time from server
const size_t MAX_CONTENT_SIZE = 512; // max size of the HTTP response

// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
initSerial();
initEthernet();
}

// ARDUINO entry point #2: runs over and over again forever
void loop() {
if (connect(server)) {
if (sendRequest(server, resource) && skipResponseHeaders()) {
char response[MAX_CONTENT_SIZE];
//think remove 161 and 0 from response here
readReponseContent(response, sizeof(response));
}

disconnect();
}

wait();
}

// Initialize Serial port
void initSerial() {
Serial.begin(BAUD_RATE);

while (!Serial) {
; // wait for serial port to initialize
}

Serial.println("Serial ready");
}

// Initialize Ethernet library
void initEthernet() {
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[] = { 192,168,0,202 };

if (!Ethernet.begin(mac))
{
Serial.println("Failed to configure Ethernet");
return;
}

Serial.println("Ethernet ready");
delay(1000);
}

// Open connection to the HTTP server
bool connect(const char* hostName) {
Serial.print("Connect to ");
Serial.println(hostName);

bool ok = client.connect(hostName, 80);

Serial.println(ok ? "Connected" : "Connection Failed!");
return ok;
}

// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
Serial.print("GET ");
Serial.println(resource);
client.print("GET ");
client.print(resource);
client.println(" HTTP/1.1");
client.print("Host: ");
client.println(server);
client.println("Connection: close");
client.println();
return true;
}

// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
// HTTP headers end with an empty line
char endOfHeaders[] = "\r\n\r\n";
client.setTimeout(HTTP_TIMEOUT);

bool ok = client.find(endOfHeaders);

if (!ok) {
Serial.println("No response or invalid response!");
}

return ok;
}

// Read the body of the response from the HTTP server
void readReponseContent(char* content, size_t maxSize) {
size_t length = client.readBytes(content, maxSize);
Serial.println("about to display contents");

// how do I turn content into a string
Serial.println(content);
Serial.println("content displayed");
Serial.println("printing contentd of client readstring");
}

// Close the connection with the HTTP server
void disconnect() {
Serial.println("Disconnect");
client.stop();
}

// Pause for a 1 minute
void wait() {
Serial.println("Wait 60 seconds");
delay(60000);
}

Answer

I think there is a misunderstanding from your side. Certainly you want to process the response of the server and according to your code, this is char response[MAX_CONTENT_SIZE] where the response is stored.

Now this already is a string, more or less. An array of characters, chars. Definiton from here.

Strings are actually one-dimensional array of characters terminated by a null character '\0'. Thus a null-terminated string contains the characters that comprise the string followed by a null.


You can extract the relevant parts from it straight away.

Your response should look like something like this, according to sunrise-sunset.org/api. Note that I just copied the data into an array for testing purposes.

#include <stdio.h>
#include <string.h>

#define MAX_CONTENT_SIZE 512

char response[MAX_CONTENT_SIZE] = \
"{\
\"results\":\
{\
\"sunrise\":\"7:27:02 AM\",\
\"sunset\":\"5:05:55 PM\",\
\"solar_noon\":\"12:16:28 PM\",\
\"day_length\":\"9:38:53\",\
\"civil_twilight_begin\":\"6:58:14 AM\",\
\"civil_twilight_end\":\"5:34:43 PM\",\
\"nautical_twilight_begin\":\"6:25:47 AM\",\
\"nautical_twilight_end\":\"6:07:10 PM\",\
\"astronomical_twilight_begin\":\"5:54:14 AM\",\
\"astronomical_twilight_end\":\"6:38:43 PM\"\
},\
\"status\":\"OK\"\
}";

You can easily process it using strtok function from string.h. Using a {, delimiter first will separate "result":{ from "sunrise .... Then you can use a }, delimiter.

With strstr you can check for "sunrise" and "sunset" field, and if you find them you can copy their value into a new string with strncpy.

int main()
{
    char* field;
    char* sunset;
    char* sunrise;

    field = strtok(response,"{,");

    while (field != NULL)
    {
        field = strtok (NULL, ",}");

        if(field != NULL)
        {
            if(strstr(field, "sunrise") != NULL)
            {
                int length = strlen(field);
                sunrise = malloc(length * sizeof(char) + 1); // +1 for terminating null character '\0'
                strncpy(sunrise, field, length + 1);         // +1 to copy a terminating null as well
            }

            if(strstr(field, "sunset") != NULL)
            {
                int length = strlen(field);
                sunset = malloc(length * sizeof(char) + 1); // +1 for terminating null character '\0'
                strncpy(sunset, field, length + 1);         // +1 to copy a terminating null as well
            }
        }
    }

    printf("SUNRISE DATA: %s\n\n", sunrise);
    printf("SUNSET  DATA: %s\n\n", sunset);

    free(sunrise);  // do not forget to free the memory if not needed anymore
    free(sunset);   // do not forget to free the memory if not needed anymore

    return 0;
}

The output of this program is:

SUNRISE DATA: "sunrise":"7:27:02 AM"

SUNSET  DATA: "sunset":"5:05:55 PM"

You can further process these strings with strtok again if you like. This is just an example code, you can use it to implement your solution.