Error compiling Plotly Sketch


#1

Hi All,

I’ve found a ton of useful information out there on the Photon and for over a year now I’ve been teaching myself and resolving errors based on searching diligently for the answer. I’m three days into researching my current issue and have hit dead ends.

I’m trying to use the Photon to read two thermistors and have them populate a Plotly graph. When trying to compile the following code I get this error: “warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]”

Code:

// This #include statement was automatically added by the Particle IDE.
#include <spark-plotly.h>

// This #include statement was automatically added by the Particle IDE.
#include <thermistor-library.h>


// Define the Pin the Temperature sensor is on
#include "Particle.h"

#define NUM_TRACES 2 //There will be 2 data traces in the stream
// Wiring---- 3.3v-> Therm--> thermPin --> 10Kres----> GND
// Analog pins the thermistors are connected to
int headPin = A0;
int tankPin = A1;

// Voltage divider resistor value
int thermRes = 10000;

// Configure the Thermistor class
Thermistor headThermistor(headPin, thermRes);
double headTempF = 0.0;

Thermistor tankThermistor(tankPin, thermRes);
double tankTempF = 0.0;


char *streaming_tokens[NUM_TRACES] = {"XXXXXX","XXXXXX"}; //Enter the tokens you generated under Plotly API settings
plotly graph = plotly("morriswnichols","XXXXXX", streaming_tokens, "TempDataTest", NUM_TRACES); //Create a plotly graph with your username, API key, streaming tokens, and graph name

void setup()
{

  // Register a Particle variable here
  //Particle.variable("Head Temp", &headTempF, DOUBLE);
  //Particle.variable("Tank Temp", &tankTempF, DOUBLE);

  
  	// Initialize the Thermistor class
	headThermistor.begin();
	tankThermistor.begin();
	
	
    graph.fileopt = "extend"; //This will keep adding data to the file instead of overwriting in case your Core ever needs to restart
    graph.convertTimestamp = "true"; //Convert millis to a date/time stamp
    graph.timezone = "America/Denver"; //Choose your timezone
    graph.init(); //Initialize the graph
    graph.openStream(); //Fire up the stream

}

void loop()
{

  headTempF = (headThermistor.getTempF()); 
  unsigned long x = millis(); //Variable to store the time in milliseconds that your Core has been alive
  graph.plot(x, headTempF, streaming_tokens[0]); //Add a timestamped temperature data point to the graph
  
  tankTempF = (tankThermistor.getTempF()); 
  unsigned long x = millis(); //Variable to store the time in milliseconds that your Core has been alive
  graph.plot(x, tankTempF, streaming_tokens[1]); //Add a timestamped temperature data point to the graph
  
  
	// Wait 2 second
	delay(2000);
}

I’ve read that the line “char *streaming_tokens[NUM_TRACES]” isn’t the best method for using a string based array and so I’ve attempted to modify it to read:

const char streaming_tokens[NUM_TRACES] = {"XXXXX","XXXXXX"};

But then I receive this error:
error: too many initializers for ‘const char [2]’

I’ve researched everything that I know how to look up.

Can anyone point me in the right direction to figure this out?

Also… please forgive any mis-step in posting etiquette… its my first time.

Many thanks!
M


#2

A string literal already goes as initializer for multiple fields in a char[].
If you want multiple strings, you need a 2D array
e.g.

const char streaming_token[NUM_TRACES][32] = { "xxxxxx", "yyyyyy" };

But for your case the original pointer solution is actually best, since the string literals will never change anyway.
To ensure that neither the pointer nor its contents can be changed you could write

const char* const streaming_token[NUM_TRACES] = { "xxxxxx", "yyyyyy" };

#3

Thank you immensely for your help.

If I go with the options of:

const char* const streaming_token[NUM_TRACES] = { "xxxxxx", "yyyyyy" }; 

Then I still wind up with the error:
/src/internettemp.cpp:29:117: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
 
                                                                                                                     ^
/src/internettemp.cpp:29:117: warning: deprecated conversion from string constant to 'char*' [-Wwrite-strings]
/src/internettemp.cpp:29:117: error: invalid conversion from 'const char* const*' to 'char**' [-fpermissive]
In file included from /src/internettemp.cpp:2:0:
lib/spark-plotly/src/spark-plotly.h:9:9: error:   initializing argument 3 of 'plotly::plotly(char*, char*, char**, char*, int)' [-fpermissive]
         plotly(char *username, char *api_key, char* stream_tokens[], char *filename, int nTraces);

Again thank you… and I’m happy to supply any other details that may be missing.


#4

Should I just go with the 2D array and move on with life?


#5

These warnings can be ignored and an explicit cast (char**) or static_cast<char**> / const_cast<char**> can solve the problem as long you can be sure the function does not attempt to mess with the pointer or its content.

This is the signature of the library function

plotly::plotly(char *username, char *api_key, char* stream_tokens[], char *filename, int nTraces)

But how does your call look?

On the other hand sticking with the format outlined in the library’s own usage sample should be a safe bet :sunglasses:


#6

I’m using the SPARK-PLOTLY Library in the particle IDE… it is the same as you have above. BUT, I did notice that I was using “streaming_tokens[]” instead of the “stream_tokens[]” as called for in the library… sadly this didn’t fix my problem.

plotly::plotly(char *username, char *api_key, char* stream_tokens[], char *filename, int nTraces)
  {
    log_level = 2;  // 0 = Debugging, 1 = Informational, 2 = Status, 3 = Errors, 4 = Quiet (// Serial Off)
    dry_run = false;
    username_ = username;
    api_key_ = api_key;
    stream_tokens_ = stream_tokens;
    filename_ = filename;
    nTraces_ = nTraces;
    maxpoints = 30;
    fibonacci_ = 1;
    world_readable = true;
    convertTimestamp = true;
    timezone = "America/Montreal";
    fileopt = "overwrite";
}

This line:

char** stream_tokens[NUM_TRACES] [32] = {"XXXX","YYYY"};

Gives this error:

/src/internettemp.cpp:28:70: error: cannot convert 'const char*' to 'char**' in initialization

If I try this:

static_cast<char**> stream_tokens[NUM_TRACES] [32] = {"XXXXX","YYYYY"};

I get:

/src/internettemp.cpp:28:1: error: expected unqualified-id before 'static_cast'
 double tankTempF = 0.0;
 ^
/src/internettemp.cpp:29:64: error: 'stream_tokens' was not declared in this scope

Since I’m trying to stream two data points I’m going to need both tokens… but for the sake of progress I tried to just use one.

The code: (removing the reference to the other data stream)

#define NUM_TRACES 1 //There will be 2 data traces in the stream
// Wiring---- 3.3v-> Therm--> thermPin --> 10Kres----> GND
// Analog pins the thermistors are connected to
int headPin = A0;
int tankPin = A1;
// Voltage divider resistor value
int thermRes = 10000;
// Configure the Thermistor class
Thermistor headThermistor(headPin, thermRes);
double headTempF = 0.0;
Thermistor tankThermistor(tankPin, thermRes);
double tankTempF = 0.0;
char* stream_tokens[NUM_TRACES] = {"XXXXX"};

Sends me the same error I started with:
> /src/internettemp.cpp:28:48: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]

 double tankTempF = 0.0;

And the char** gives the “can’t convert in initialization” error similar to as before.

I’ve tried initializing the array and then adding the tokens one at a time but the compiler then tells me that I haven’t defined the variable “stream_tokens”

char** stream_tokens[NUM_TRACES];
stream_tokens[0] = “zmdbuuduxj”;
stream_tokens[1] = “b07qxv4szj”;

On one hand this is completely maddening… I know the answer lies somewhere in my mis-use of the syntax. On the other I’m sure this is going to be a very valuable lesson later in my programming life.

Again… any help is appreciated … even if it does insinuate that I am totally ignorant.


#7

These asterisks (*) are not to be sprinkled just like that without knowing how pointers work.
Just a quick primer

char c;     // this a character variable
char *pc;   // this is a variable that holds a pointer to a place where (at least) one character lives
char ac[5]; // this is an array of 5 characters
            // but ac (withoug []) is quite similiar to pc, a pointer to some characters

// --- now ---
char** stream_tokens[NUM_TRACES]; 
// this is a pointer to a pointer to an array (which in turn is a pointer again) 
// that's not what you want

Also a type cast is a way to get the compiler to treat a variable of one type as of another type. It can’t be used instead of a type in the variable declaration.

So what I meant would rather look like this

// this is an array of pointers, each pointing to a char* string where neither the pointers nor the strings can be altered
const char* const streaming_token[NUM_TRACES] = { "xxxxxx", "yyyyyy" }; 

// this is an array of pointers, each pointing to a char* string where both, the pointers and the strings, could be altered
char* alternative_token[NUM_TRACES] = { "xxxxxx", "yyyyyy" }; 

  // and the cast goes in the call
  plotly graph = plotly("morriswnichols","XXXXXX", (char**)streaming_token, "TempDataTest", NUM_TRACES);
  // or 
  plotly graph = plotly("morriswnichols","XXXXXX", const_cast<char**>(streaming_token), "TempDataTest", NUM_TRACES);

  // static_cast<char**> only works without the const modifiers
  plotly graph = plotly("morriswnichols","XXXXXX", static_cast<char**>(alternative_token), "TempDataTest", NUM_TRACES);

#8

Thank you for your patience… and the explanation. I’m going to play with this and study the concepts of pointers… which was hitherto unknown to me. :blush: