How to edit char array saved as a pointer?

Hi, first time I've run into a problem I haven't been able to solve through tutorials and reading previous posts. I've been stuck on this for 3 days now, and I'm hoping someone here will be able to clear the fog!

I'm not sure if the title accurately states the problem, let me know if I should change it.

I have two applications (smart bathroom fan through Sonoff Basic/ESP8285) which do the same thing at the same time, using the same code. Currently I'm keeping two parallel copies of the code with different IP addresses, OTA and mDNS names, which is a pain when I make tweaks to the code. I thought it would be smarter to instead use the same code, and just have a config file saved on each that then tells the code which settings to use.

I've followed the ArduinoJSON tutorial on doing this and it works for setting the IP address, but have run into a snag with changing the names. As I understand it, this is because those variables are passed as pointers, while the example is using a char array.

I've tried numerous ways to try and get this work, most wouldn't compile, the example I'm putting here did at least compile, but didn't change the variable. For simplicity the example only tries to change OTAName, as I figure it's exactly problem for both names.

Variable declarations:

char* mdnsName = "BathroomFan";
char* OTAName = "BathroomFan";

Attempting to change them:

  // Copy values from the JsonDocument to the Config
  const char *tempChar = doc["OTAName"];
  *OTAName = *tempChar;
  Serial.println(tempChar);
  staticIP[3] = doc["StaticIP"];

I think the problem is in the above lines of code, but here is the full code and JSON for diagnosis.

#include <ESP8266WiFi.h>      // for WiFi
#include <ArduinoOTA.h>       // for OTA updates
#include <FS.h>               // for SPIFFs file server
#include <ArduinoJson.h>      // for JSON support

#define BOARD_LED 13    // On board LED is on GPIO13
IPAddress staticIP(192, 168, 0, 250);
// WiFi and server variables
const char *ssid = "ssid";
const char *password = "password";
char* mdnsName = "BathroomFan";
char* OTAName = "BathroomFan";           // A name and a password for the OTA service
const char *OTAPassword = "password";


void setup() {
  Serial.begin(9600);       // Enable serial port
  SPIFFS.begin();           // Start the SPI Flash File System (SPIFFS)
  loadConfiguration();      // load the settings from flash memory
  startWiFi();              // Start the WiFi
  startOTA();               // Start the OTA service
}

void loop() {

  ArduinoOTA.handle();                // listen for OTA events
}

void startOTA() { // Start the OTA service
  ArduinoOTA.setHostname(OTAName);
  ArduinoOTA.setPassword(OTAPassword);
  ArduinoOTA.begin();
}

// Loads the configuration from a file
void loadConfiguration() {
  // Open file for reading
  File file = SPIFFS.open("/Config.json", "r");

  Serial.println("Initial values of variables");
  Serial.println(OTAName);

  // Allocate a temporary JsonDocument
  StaticJsonDocument<512> doc;

  // Deserialize the JSON document
  DeserializationError error = deserializeJson(doc, file);
  if (error)
    Serial.println(F("Failed to read file, using default configuration"));

  // Copy values from the JsonDocument to the Config
  const char *tempChar = doc["OTAName"];
  *OTAName = *tempChar;
  Serial.println(tempChar);
  staticIP[3] = doc["StaticIP"];

  Serial.println("Modified values of variables");
  Serial.println(OTAName);
  Serial.println(staticIP);

  // Close the file (Curiously, File's destructor doesn't close the file)
  file.close();
}

void startWiFi() { // Start a Wi-Fi access point, and try to connect to some given access points. Then wait for either an AP or STA connection
  WiFi.begin(ssid, password);   // Start WiFi
  int timer = 0;
  while (WiFi.status() != WL_CONNECTED && timer < 200)
  {
    delay(100);
    digitalWrite(BOARD_LED, !digitalRead(BOARD_LED));
    timer ++;           //  If wifi is not available, continue with boot up
  }
  WiFi.config(staticIP, WiFi.gatewayIP(), WiFi.subnetMask()); // set up the fixed IP address, in case mDNS doesn't work
}

JSON

{
  "OTAName": "BathroomFan2",
  "mdnsName": "BathroomFan",
  "StaticIP": 213,
  "target_humidity": 90,
  "hysteresis": 9,
  "minimum_run": 10 
}

I'm not familiar with JSON or the library you're using. But, it seems you need to go back to basics and learn the relationship between pointers and arrays in C / C++. This is a fundamental concept of the language.

Basically, dereferencing a pointer is the same as indexing into an array. So, the following two lines are equivalent:

  array[3] = 0;
  *(array + 3) = 0;

Here are a couple hits from a 2-second Google search:

Variable declarations:

char* mdnsName = "BathroomFan";

char* OTAName = "BathroomFan";

Another way to do that is

char mdnsName[] = "BathroomFan";
char OTAName[] = "BathroomFan";

The name of an array is actually a pointer.

...R

I managed to figure it out, so am posting this for the benefit of anyone else with the same problem who stumbles across this post.

The first issue is that char arrays/strings can't be copied the way that variables like int can be, hence the need to use strcpy (or strlcpy as used in the ArduinoJSON example). The second is that the ArduinoJSON code can give the output in a variety of types, eg. int, char, string, etc. Usually it infers what type you want from where you are putting it.

I changed the variable declaration to this:

char OTAName[16] = "BathroomFan";

I chose to specify a length as the name I'm changing it to could potentially be longer than the initial name, and my understanding is that the length isn't easily changed later.

The variable is now changed with:

strcpy(OTAName, doc["OTAName"].as<char*>());

The .as<char*>() explicitly tells the ArduinoJSON code to give the output as a char array, and strcpy then copies that array element by element to the destination.

This is my understanding of the problem I was having and the solution I found, I may have some details wrong, but at least it seems to work!

cubic_nz:
The variable is now changed with:

strcpy(OTAName, doc["OTAName"].as<char*>());

Be very careful to ensure that you do not copy something that is longer than the array OTAName

...R

cubic_nz:
The variable is now changed with:

strcpy(OTAName, doc["OTAName"].as<char*>());

The .as<char*>() explicitly tells the ArduinoJSON code to give the output as a char array, and strcpy then copies that array element by element to the destination.

Close. The .as<char*> template invocation causes the .as() function to return a pointer to an array of characters. That's what the "char *" inside the "<..>" means.