0

A newbie in Arduino- and I'm trying to concatenate string and chars ( well in python it is quite different ).

I'm trying to post a MQTT message- constructed following format to the client.publish(outTopic, "["+outTopic+"]"+ msg)

while outTopic is a char* variable, and msg is char- but I get an error for such concatenation.

please your help

#include <ESP8266WiFi.h>
#include <PubSubClient.h>


// GPIOs on SONOFF board
int LED_SONOFF = 13;
int REL_SONOFF = 12;
int PIN_SW = 14;

const char* ssid = "HomeNetwork_2.4G";
const char* password = "pswd";
const char* mqtt_server = "192.168.2.113";

WiFiClient espClient;
PubSubClient client(espClient);


char msg[50];
const char* outTopic = "HomePi/Dvir/Messages";
const char* inTopic = "HomePi/Dvir/Windows/SONOFF";
const char* inTopic2 = "HomePi/Dvir/Windows/All";
const char* clientID = "Sonoff#1";
String m1, m2;

void start_wifi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");  
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP()); 
}

void setup() {
  start_wifi(); // start wifi service
  Serial.begin(115200); // start serial service
  delay(10);

  // define sonoff gpios
  pinMode(LED_SONOFF, OUTPUT);
  pinMode(REL_SONOFF, OUTPUT);
  pinMode(PIN_SW, INPUT_PULLUP); // GPIO14 has a pullup resistor
  digitalWrite(LED_SONOFF,HIGH); // LED high is OFF
  digitalWrite(REL_SONOFF,LOW); 

  // start mqtt
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);  
}

void switch_on() {
  digitalWrite(REL_SONOFF,HIGH);
  digitalWrite(LED_SONOFF, LOW); // LED ON
  pub_mqtt("Switch ON");
}

void switch_off() {
  digitalWrite(REL_SONOFF,LOW);
  digitalWrite(LED_SONOFF, HIGH); // LED OFF
  pub_mqtt("Switch OFF");
}

void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  if ((char)payload[0] == '1') {
    switch_on();   
  } 
  if ((char)payload[0] == '0') {
    switch_off();
    Serial.print("payload: ");
    Serial.println(payload[0]);
  }

}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP8266Client")) {
      Serial.println("connected");
      client.publish(outTopic, "Connected");

      client.subscribe(inTopic);
      m1="Subscribed to: "+inTopic;
      client.publish(outTopic, m1);
      if (inTopic2 !=""){
        client.subscribe(inTopic2);
        m2="Subscribed to: ";//+ String(inTopic2);
        client.publish(outTopic, m2);
      }

    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void pub_mqtt(char* msg) {
  client.publish(outTopic, msg);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (digitalRead(PIN_SW)==1) {
    if (digitalRead(REL_SONOFF)!=LOW) {
      switch_off();
    }
  }
  else if (digitalRead(PIN_SW)==0) {
    if (digitalRead(REL_SONOFF)!=HIGH){
      switch_on();
    }
  }
   delay(100);
}
1
  • Likely it would be best if you created a new string in which you place what you want to pass to the called method. Guessing, you have asked if the C/C++ compiler could implicitly do this by asking it to arrange for pulling out bits of the string from flash memory (the const outTopic and the "[" characters you added in the line of code) with bits from RAM (the string msg).
    – st2000
    Aug 11, 2018 at 14:37

1 Answer 1

2

You can't simply concatenate C strings like that. Instead you have to build them up into a new string. For formatting like that the simplest way is with sprintf:

char outMessage[strlen(outTopic) + strlen(msg) + 3]; // Room for topic, message, [ and ] and terminating \0
sprintf(outMessage, "[%s]%s", outTopic, msg);
client.publish(outTopic, outMessage);

Another method is with strcpy and strcat:

char outMessage[strlen(outTopic) + strlen(msg) + 3]; // Room for topic, message, [ and ] and terminating \0
strcpy(outMessage, "[");
strcat(outMessage, outTopic);
strcat(outMessage, "]");
strcat(outMessage, msg);
client.publish(outTopic, outMessage);

You have to ensure that your "holding" string outMessage is big enough to hold everything you want to send, plus a terminating NULL character, otherwise your program will crash.

Another way of creating the "holding" variable is with alloca(). That allocates bytes on the stack for a variable - just like malloc() does on the heap, but doesn't require free()ing because it's on the stack and is reclaimed when the function exits:

char *outMessage = (char *)alloca(strlen(outTopic) + strlen(msg) + 3);
8
  • thank you- i fund first method more short and sensable. does it matter that outTopic is char* ?
    – guyd
    Aug 11, 2018 at 16:26
  • %s connects to a char * data type.
    – Majenko
    Aug 11, 2018 at 16:26
  • I was referring to char outMessage[strlen(outTopic) + strlen(msg) + 3];
    – guyd
    Aug 11, 2018 at 16:29
  • char *foo and char foo[x] are essentially the same. The second is a char * with memory allocation added in.
    – Majenko
    Aug 11, 2018 at 16:30
  • @Mejnko - can you please explain why +3 is needed, since for purpose of string concatenation, it is not needed - does it relevent for sending ?
    – guyd
    Aug 12, 2018 at 19:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.