cannot convert 'const __FlashStringHelper*' to 'char*' in assignment

Dear arduino forum,
could anyone help me to convert a String in a F()-Makro to a char-Array?

   char *publishString;
   publishString = F("test message");

error: cannot convert 'const __FlashStringHelper*' to 'char*' in assignment

background: I want to send debugmessages to adafruit.io via MQTT. The publish-routine seems to only accept char*. I want to save RAM with the F()-Makro.

any hints are highly appreciated.

If we need to help you convert something it would be a good idea to post with what you started in the first place...

If the standard publish method can’t handle a string in PROGMEM, you may have to write a version that does.

Hi septillion,
thanks for your quick reply. Hoped the two code lines represent the whole problem. But here is the complete code:

/***************************************************
  Adafruit MQTT Library Ethernet Example

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Alec Moore
  Derived from the code written by Limor Fried/Ladyada for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/
#include <SPI.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#include <Ethernet.h>
#include <EthernetClient.h>
#include <Dns.h>
#include <Dhcp.h>

/************************* Ethernet Client Setup *****************************/
byte mac[] = {0x5A, 0xA2, 0xDA, 0x0D, 0x56, 0x7A};

//Uncomment the following, and set to a valid ip if you don't have dhcp available.
//IPAddress iotIP (192, 168, 0, 42);
//Uncomment the following, and set to your preference if you don't have automatic dns.
//IPAddress dnsIP (8, 8, 8, 8);
//If you uncommented either of the above lines, make sure to change "Ethernet.begin(mac)" to "Ethernet.begin(mac, iotIP)" or "Ethernet.begin(mac, iotIP, dnsIP)"


/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883
#define AIO_USERNAME    "..."
#define AIO_KEY         "..."

/************ Global State (you don't need to change this!) ******************/

//Set up the ethernet client
EthernetClient client;

Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

// You don't need to change anything below this line!
#define halt(s) { Serial.println(F( s )); while(1);  }


/****************************** Feeds ***************************************/

// Setup a feed called 'photocell' for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
Adafruit_MQTT_Publish photocell = Adafruit_MQTT_Publish(&mqtt,  AIO_USERNAME "/feeds/log");

// Setup a feed called 'onoff' for subscribing to changes.
Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/onoff");

/*************************** Sketch Code ************************************/

void setup() {
  Serial.begin(9600);

  Serial.println(F("Adafruit MQTT demo"));

  // Initialise the Client
  Serial.print(F("\nInit the Client..."));
  Ethernet.begin(mac);
  delay(1000); //give the ethernet a second to initialize
  

  mqtt.subscribe(&onoffbutton);
}

uint32_t x=0;

void loop() {
  // Ensure the connection to the MQTT server is alive (this will make the first
  // connection and automatically reconnect when disconnected).  See the MQTT_connect
  // function definition further below.
  MQTT_connect();

//  // this is our 'wait for incoming subscription packets' busy subloop
//  Adafruit_MQTT_Subscribe *subscription;
//  while ((subscription = mqtt.readSubscription(1000))) {
//    if (subscription == &onoffbutton) {
//      Serial.print(F("Got: "));
//      Serial.println((char *)onoffbutton.lastread);
//    }
//  }
   char *publishString;
   publishString = "testtext"; 
   publishString = F("test message");
  // Now we can publish stuff!
  Serial.print(F("\nSending photocell val "));
  Serial.print(publishString);
  Serial.print("...");
  if (! photocell.publish(publishString)) {
    Serial.println(F("Failed"));
  } else {
    Serial.println(F("OK!"));
  }

  // ping the server to keep the mqtt connection alive
  if(! mqtt.ping()) {
    mqtt.disconnect();
  }

}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.println(mqtt.connectErrorString(ret));
       Serial.println("Retrying MQTT connection in 5 seconds...");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
  }
  Serial.println("MQTT Connected!");
}

That's a HUGE program. Can't you start small?

Otherwise, hoe two lines (kind of) show what you tried, not what you started with and what you wanted to convert...

Hi gfvalvo,
thanks! Thats what I tried to do. I tried to cast the types in a wrapper function - but no success. Can't find out a way to convert these types. Is it possible after all?
Hope to find a way without touching the library.
regards.

sebfroeb:
I tried to cast the types in a wrapper function - but no success. Can't find out a way to convert these types. Is it possible after all?
Hope to find a way without touching the library.
regards.

Take a look at the source code for the library. It has no method for handling strings in PROGMEM. Casting is not going to fix that. If you don’t want to hack the library, then you could leave the strings in PROGMEM and pull them out one at a time into a common RAM c-string buffer which you then send to the publish method. That way only one c-string is in RAM at a time.

Eugh! I just looked at what you'd have to do to fix this in the library, it looks like a real bitch.

How much ram are you hoping to save this way? Do you have lots of constant strings that you plan to publish to MQTT? How desperate for ram are you? It may be that the cost (in effort, flash, complexity) is not worth it.

For that matter, what is the point of sending a constant string via MQTT? Don't you normally send like, data that changes, not constant strings? Maybe that's why Adafruit didn't add support for F() themselves?

Hey,
yes, I have a lot of debug-strings in my programm and RAM is almost finished. I definetely can not store them all in the RAM.
I am running a webserver on my Arduino waiting for HTTP GET commands to control several RC-sockets via a 433MHz-sender, send some IR-signals, wakeup my mediacenter with WOL. The uC also reads in some signals like a PIR motion detector and so on.
The idea was to use adafruit.io to write logging-messages to the cloud for information when something happened and to send signals like the PIR-sensor. For the second usecase I agree with you just some numbers are fine. But for the first usecase I need to send strings.
Didn't think that it'll be so dificult as .publish("something"); already worked just immediately.

I'm investigating about the pgm_read_byte() right now. Maybe that'll be a path.

How do you guys log out debug messages while the system isn't connected to the Serial COM?

wanted to let you know my solution in case anybody has a similar problem.
I used ifttt instead of adafruit.

the updateIFTTT-function is called:

updateIFTTT(F("teststring"));

the function looks like that:

void updateIFTTT(String dbgString){
  if (iftttClient.connect(iftttServer, 80)) {
    Serial.println(F("connected to iftttServer, sending..."));
    // Make a HTTP request:
    iftttClient.print(F("GET /trigger/ArduinoLogger/with/key/<key>/?value1="));
    iftttClient.print([b]dbgString.c_str()[/b]);
    iftttClient.println(" HTTP/1.1");
    iftttClient.println(F("Host: maker.ifttt.com"));
    iftttClient.println(F("Connection: close"));
    iftttClient.println();
    delay(1000);
    while(iftttClient.available()) {        // if there are incoming bytes available from the server, read them and print them: 
      char c = iftttClient.read();
      Serial.print(c);
    }
    // if the server's disconnected, stop the client:
    if (!iftttClient.connected()) {
     Serial.println(F("IFTTT: disconnecting."));
      iftttClient.stop();
    }
  }
  else{ Serial.println(F("connection_failed")); }// didn't get a connection to the server
}

the the content of the String-object is sent to the server via: dbgString.c_str()