Particle Boron/Argon randomly reboot

Hello!

I have made an app that controls LED dimming via PWM frequency, after the hours of the sun. It also measures power usage, + temperature of the casing where it is sitting. PWM frequency (light strength) can be controlled via MQTT from Ubidots.

I currently have it running on two devices, one argon and one boron. On separate locations, and very steady power sources. The Boron also has a battery connected. They are both on 0.9.0 but it also happened on earlier firmware.

Everything works fine, but i am experiencing very random reboots. Sometimes it runs fine for days (3-4-5 days) with no reboots, and sometimes it has 1-3 reboots a day. It sends an MQTT message to ubidots in the setup function (including the reset reason), thats how i know when it last reboot.
It happens on both units, but not at the same times.
I have enable “Reset Reason” - but it gives me “USER” as reason. What can trigger a reset with USER as reason? Any idea where i should start looking?

// This #include statement was automatically added by the Particle IDE.
#include <UbidotsMQTT.h>.
#include <Sunrise.h>


// -----------------------------------------------------------------
// Sign Control v0.1 - Hardware 0.1
// -----------------------------------------------------------------


/****************************************
 * Enable reset info
 ****************************************/
 
STARTUP(System.enableFeature(FEATURE_RESET_INFO));
char resetreason[20];



/****************************************
 * Instances for MQTT
 ****************************************/
 
#ifndef TOKEN
#define TOKEN "###############"  // Add here your Ubidots TOKEN
#endif

UbidotsMQTT client(TOKEN, callback);



/****************************************
 * Different timed routines
 ****************************************/
 
// Initiate value for daily updates routine
#define ONE_DAY_MILLIS (24 * 60 * 60 * 1000)
unsigned long lastSync_oneday = millis();

// Initiate value for minute updates routines
#define ONE_MINUTE_MILLIS (60 * 1000)
unsigned long lastSync_minute = millis();

// minimum time between publish
#define PUBLISH_MINIMUM (1000)
unsigned long lastpublish = millis();

// minimum time before reset initiated from cloud
//This ensures that the device can report back to the cloud
#define RESET_WAIT (15 * 1000)
unsigned long resetinit = millis();
bool resetFlag = false;

#define CLOUD_WAIT (600 * 1000)
unsigned long cloudinit = millis();
int cloudinit_faultcount = 0;


/****************************************
 * GLOBAL VARIABLES
 ****************************************/

// We're going to start by declaring which pins everything is plugged into.
int led = D2; // PWM Output pin for LED
int volt = A5; // Input pin from voltage divider
int amp = A4; // Input pin from power measure
int temp = A3; // Input pin from temp measure

// Voltage divider settings
float resistor1 = 220000.00; // R1 Resistor value
float resistor2 = 33000.00; // R2 Resistor value

// Setting variables for pwm duty cycle
int lightvalue_old = 0;
int lightvalue;

// Default variables in case cloud is unavailable
int value_min = 45;
int value_mid1 = 100;
int value_mid2 = 160;
int value_max = 220;
int value;
int hertz = 500;


// Variables for power consumption
float amp_readout;
char amp_readout_string[20];
int amp_calibration = 0;
float volt_readout;
char volt_readout_string[20];
float watt_readout;
char watt_readout_string[20];
float temp_readout;
char temp_readout_string[20];

// Variables for sunset /sunrise
int sunrisetime;
int sunsettime;
int timeaftermidnight;


char publishString[40];

// Wifi/cellular global
int signalstrength = -1;




/****************************************
 * Get device ID
 ****************************************/

char* deviceid = string2char(System.deviceID());


/****************************************
 * Now for sunrise.h - we create an object for summer and wintertime
 ****************************************/
Sunrise winterSunrise(63.367948,10.371597, +1); // Trondheim - Tiller - Latitude/Longitude and UTC offset
Sunrise summerSunrise(63.367948,10.371597,+2); // Trondheim - Tiller - Latitude/Longitude and UTC offset


/****************************************
 * Software Watchdog
 ****************************************/
ApplicationWatchdog wd(60000, System.reset);




// Next we go into the setup function.
void setup() 
{
	
    // This is here to allow for debugging using the USB serial port
	// Serial.begin();

	
	// First, declare all of our pins.
	pinMode(led, OUTPUT); // Our LED pin is output (lighting up the LED)
	pinMode(volt, INPUT); // Voltage read input
	pinMode(amp, INPUT); // Ampere read input


    /****************************************
     * Wifi or cellular variables
     ****************************************/

    #if Wiring_WiFi
        waitUntil(WiFi.ready);
        delay(1000);
        char network[64];
        strcpy(network, WiFi.SSID());
        IPAddress local_ip = WiFi.localIP();
    #endif

    #if Wiring_Cellular
        waitUntil(Cellular.ready);
        delay(1000);
        // SYNTAX
        CellularSignal sig = Cellular.RSSI();
        char network[18];
        strcpy(network, "UNKNOWN");
        switch( sig.getAccessTechnology() )
            {
            	case NET_ACCESS_TECHNOLOGY_GSM:		strcpy(network, "2G RAT"); break;
            	case NET_ACCESS_TECHNOLOGY_EDGE:	strcpy(network, "2G RAT with EDGE"); break;
            	case NET_ACCESS_TECHNOLOGY_UMTS:    strcpy(network, "UMTS RAT"); break;
            	case NET_ACCESS_TECHNOLOGY_LTE:		strcpy(network, "LTE"); break;
            }
        IPAddress local_ip = Cellular.localIP();
    #endif
    
    
    //MQTT
    client.ubidotsSetBroker("industrial.api.ubidots.com");
    client.initialize();
    
    if(client.isConnected())
    {
        client.ubidotsSubscribe(deviceid, "max_duty_cycle");
        client.ubidotsSubscribe(deviceid, "min_duty_cycle"); 
    }
    
    
    
    // Get Reset Reason
    switch( System.resetReason() )
    {
    	case RESET_REASON_PIN_RESET:		strcpy(resetreason, "PIN_RESET"); break;
    	case RESET_REASON_POWER_MANAGEMENT:	strcpy(resetreason, "POWER_MANAGEMENT");	break;
    	case RESET_REASON_POWER_DOWN:		strcpy(resetreason, "POWER_DOWN"); break;
    	case RESET_REASON_POWER_BROWNOUT:	strcpy(resetreason, "POWER_BROWNOUT"); break;
    	case RESET_REASON_WATCHDOG:		    strcpy(resetreason, "WATCHDOG"); break;
    	case RESET_REASON_UPDATE:		    strcpy(resetreason, "UPDATE"); break;
    	case RESET_REASON_UPDATE_TIMEOUT:	strcpy(resetreason, "UPDATE_TIMEOUT"); break;
    	case RESET_REASON_FACTORY_RESET:	strcpy(resetreason, "FACTORY_RESET"); break;
    	case RESET_REASON_DFU_MODE:		    strcpy(resetreason, "DFU_MODE"); break;
    	case RESET_REASON_PANIC:		    strcpy(resetreason, "PANIC"); break;
    	case RESET_REASON_USER:			    strcpy(resetreason, "USER"); break;
    	case RESET_REASON_UNKNOWN:		    strcpy(resetreason, "UNKNOWN"); break;
    	case RESET_REASON_NONE:		 	    strcpy(resetreason, "NONE"); break;
    	default:                            strcpy(resetreason, "NOT_DEFINED");
    }
    
	
	// Cloud variables
	Particle.variable("Duty_cycle", &lightvalue_old, INT);
	Particle.variable("Signalstr", &signalstrength, INT);
	Particle.variable("Sunrisetime", &sunrisetime, INT);
	Particle.variable("Sunsettime", &sunsettime, INT);
	Particle.variable("Volt", volt_readout_string, STRING);
	Particle.variable("Amp", amp_readout_string, STRING);
	Particle.variable("AmpCal", &amp_calibration, INT);
	Particle.variable("Watt", watt_readout_string, STRING);
	Particle.variable("Temp", temp_readout_string, STRING);
	Particle.variable("ResetReason", resetreason, STRING);
	Particle.function("Restart", cloudResetFunction);


	


    
    // Sunset - define sunset/rise
    winterSunrise.Actual(); //Actual, Civil, Nautical, Astronomical
    summerSunrise.Actual();
    
    
    //Set timezone depending on dst
    if (IsDST())
        Time.zone(+2);
    else
        Time.zone(+1);
        
    // Set sunset/Sunrise variables
    sunsetrise_set();
    
    

    // Send an EVENT about startup
    char message[160];
    sprintf(message,"\"oppstart\":\"%s\", \"nettverk\":\"%s\", \"ip\":\"%s\", \"resetreason\":\"%s\"", string2char(Time.timeStr()), string2char(network), string2char(local_ip), resetreason);
    publish_event ("oppstart", message);
    
    
    // calibrate amp (While LED is still off)
    updatewatt();
    
    // Allow things to settle before resuming, and recieve some values from the sky before starting loop
    // This allows us to recieve last value from MQTT before starting loop function
    int i = 10;
    while (i > 0)
    {
        i--;
        client.loop();
        delay(500);
    }
   


}






// Next is the loop function...
void loop() 
{
    
    
    // Try to make a failsafe - if unit not is connected to cloud
    if (Particle.connected()) {
        cloudinit = millis();
        cloudinit_faultcount = 0;
    }
    else
    {
        if (millis() - cloudinit > CLOUD_WAIT)
        {
            Particle.connect();
            cloudinit = millis();
            publish_event ("log", "\"message\":\"Trying to reconnect to cloud after CLOUD_WAIT.\"");
            cloudinit_faultcount++;
        }
        else if (cloudinit_faultcount <= 12)
        {
            cloudinit = millis();
            resetFlag = true;
            resetinit=millis();
            publish_event ("log", "\"message\":\"Reset initiated from Particle.connect failsafe.\"");
        }
        
    }

    // This part checks if reset function has been initiated, and lets us delay reset
    if (resetFlag && (millis() - resetinit > RESET_WAIT))
    {
        System.reset();
    }
    
    //MQTT    
    if(!client.isConnected())
    {
        client.reconnect();
        client.ubidotsSubscribe(deviceid, "max_duty_cycle");
        client.ubidotsSubscribe(deviceid, "min_duty_cycle");
        publish_event ("log", "\"message\":\"MQTT Disconnected - reconnecting\"");
    }
    
    //Check for MQTT subscriptions
    client.loop();
    
    
    // Dailyroutine .. sync time once a day and check if DST status has changed
    if (millis() - lastSync_oneday > ONE_DAY_MILLIS)
    {
        if (IsDST())
            Time.zone(+2);
        else
            Time.zone(+1);
        
        sunsetrise_set();
        
        // Request time synchronization from the Particle Device Cloud
        Particle.syncTime();
        lastSync_oneday = millis();

    }
    
     // Minute routine .. update variables for cloud
    if (millis() - lastSync_minute > ONE_MINUTE_MILLIS)
    {
        updatewatt();
        temperature();
        
        lastSync_minute = millis();
    }   
    

    
    
    #if Wiring_WiFi
        //Wifi Signal strength
        WiFiSignal sig = WiFi.RSSI();
        signalstrength = sig.getStrength();
    #endif

    #if Wiring_Cellular
        CellularSignal sig = Cellular.RSSI();
        signalstrength = sig.getStrength();
    #endif
    
    

    /*###     OK! Down to business - this is the main function    ###*/
    timeaftermidnight = (Time.hour() * 60) + Time.minute();
    
    //if time is after sunset...
    if (timeaftermidnight >= sunsettime)
    {
        //Serial.printlnf("Value_mid1: %d Value_mid2: %d", value_mid1, value_mid2);
        
        if (timeaftermidnight > (sunsettime + 60))
            fade(value_min);
        else if (timeaftermidnight > (sunsettime + 30))
            fade(value_mid1);
        else 
            fade(value_mid2);
    }
    // if time is before sunrise
    else if (timeaftermidnight <= sunrisetime)
    {
        //Serial.printlnf("Value_mid1: %d Value_mid2: %d", value_mid1, value_mid2);
        
        if (timeaftermidnight < (sunrisetime - 60))
            fade(value_min);
        else if (timeaftermidnight > (sunsettime - 30))
            fade(value_mid1);
        else 
            fade(value_mid2);
    }
    // We reach here if it is daytime
    else
    {
        fade(value_max);
    }


}



void callback(char* topic, byte* payload, unsigned int length) {
    
    
    int len = strlen(topic) + 1;
    char p[len];
    memcpy(p, topic, len);
    p[len] = NULL;
    String message(p);

    
    if (message.indexOf("max_duty_cycle") > 0)
    {
        payload[length] = '\0'; // Make payload a string by NULL terminating it.
        value_max = atoi((char *)payload);
            
        value_mid1 = ((value_max - value_min) / 3) + value_min;
        value_mid2 = (((value_max - value_min) / 3) * 2) + value_min;
    }
    else if (message.indexOf("min_duty_cycle") > 0)
    {
        payload[length] = '\0'; // Make payload a string by NULL terminating it.
        value_min = atoi((char *)payload);
    
        value_mid1 = ((value_max - value_min) / 3) + value_min;
        value_mid2 = (((value_max - value_min) / 3) * 2) + value_min;
    }
   
}

int cloudResetFunction(String command)
{
  resetFlag = true;
  resetinit=millis();
  publish_event ("log", "\"message\":\"Reset initiated from cloud function.\"");
  return 1;
}

void updatewatt()
{

      // Get voltage
    volt_readout = voltage_calculation();
    sprintf(volt_readout_string, "%.2f", volt_readout);

    // Get amps
    amp_readout = amp_calculation();
    sprintf(amp_readout_string, "%.2f", amp_readout);
    
     // Get watt
    watt_readout = amp_readout * volt_readout;
    sprintf(watt_readout_string, "%.2f", watt_readout);
  
  
}


//Funtion that fades light to the desired value
int fade(int lightvalue) 
{
    
    if (lightvalue != lightvalue_old)
    {

        // Start fading light to new value
        while (lightvalue != lightvalue_old)
        {
            if (lightvalue > lightvalue_old) {
                analogWrite(led, lightvalue_old, hertz);
                lightvalue_old++;
            }
            else if (lightvalue < lightvalue_old) {
                analogWrite(led, lightvalue_old, hertz);
                lightvalue_old--;
            }
            else {
                return -1;
            }
            //This delay controls how fast the fading happens
            delay(20);
            
        }
        // Trigger watt publish
        updatewatt();
        client.add("duty_cycle", lightvalue); // Insert as first parameter your variable label
        client.add("daily_watt", calculate_daily_watt());
        client.add("watt", watt_readout); // Insert as first parameter your variable label
        client.ubidotsPublish(deviceid); // Insert your device label where the values will be stored in Ubidots
    
    }

    return 1;
}

// Function to check if DST is active (Europe version)
bool IsDST()
{ // (Central) European Summer Timer calculation (last Sunday in March/October)
  int dayOfMonth = Time.day();
  int month = Time.month();
  int dayOfWeek = Time.weekday() - 1; // make Sunday 0 .. Saturday 6

  if (month >= 4 && month <= 9)
  { // April to September definetly DST
    return true;
  }
  else if (month < 3 || month > 10)
  { // before March or after October is definetly standard time
    return false;
  }

  // March and October need deeper examination
  boolean lastSundayOrAfter = (dayOfMonth - dayOfWeek > 24);
  if (!lastSundayOrAfter)
  { // before switching Sunday
    return (month == 10); // October DST will be true, March not
  }

  if (dayOfWeek)
  { // AFTER the switching Sunday
    return (month == 3); // for March DST is true, for October not
  }

  int secSinceMidnightUTC = Time.now() % 86400;
  boolean dayStartedAs = (month == 10); // DST in October, in March not
  // on switching Sunday we need to consider the time
  if (secSinceMidnightUTC >= 1*3600)
  { // 1:00 UTC (=1:00 GMT/2:00 BST or 2:00 CET/3:00 CEST)
    return !dayStartedAs;
  }

  return dayStartedAs;
}

// Convert string to char
char* string2char(String command)
{
    if(command.length()!=0){
        char *q = const_cast<char*>(command.c_str());
        return q;
    }
}

void sunsetrise_set()
{
    bool daylightSavings = IsDST();
    
    // time in minutes after midnight
    timeaftermidnight = (Time.hour() * 60) + Time.minute();

    int hsr,msr,hss,mss;
    
    // minutes past midnight of sunrise/sunset
    if (daylightSavings)
    {
        sunrisetime = summerSunrise.Rise(Time.month(),Time.day());
        hsr=summerSunrise.sun_Hour();
        msr=summerSunrise.sun_Minute();
        
        sunsettime = summerSunrise.Set(Time.month(),Time.day());
        hss=summerSunrise.sun_Hour();
        mss=summerSunrise.sun_Minute();
    }
    else
    {
        sunrisetime = winterSunrise.Rise(Time.month(),Time.day());
        hsr=winterSunrise.sun_Hour();
        msr=winterSunrise.sun_Minute();
        
        sunsettime = winterSunrise.Set(Time.month(),Time.day());
        hss=winterSunrise.sun_Hour();
        mss=winterSunrise.sun_Minute();
    }
    

    // Send an EVENT about sunset
    char message[100];
    
    char msr_v[4];
    if (msr<10) sprintf(msr_v,"0%d", msr);
    else sprintf(msr_v,"%d", msr);
    char mss_v[4];
    if (mss<10) sprintf(mss_v,"0%d", mss);
    else sprintf(mss_v,"%d", mss);
    
 
    
    #if Wiring_WiFi
        //Wifi Signal strength
        WiFiSignal sig = WiFi.RSSI();
        signalstrength = sig.getStrength();
    #endif

    #if Wiring_Cellular
        CellularSignal sig = Cellular.RSSI();
        signalstrength = sig.getStrength();
    #endif


    sprintf(message,"\"Localtime\":\"%s\", \"Sunset\":\"%d:%s\", \"Sunrise\":\"%d:%s\", \"wifisignal\":\"%i\"", string2char(Time.timeStr()), hss, string2char(mss_v), hsr, string2char(msr_v), signalstrength);
    publish_event ("update", message);
    
    
}


void publish_event (char* topic, char* message)
{
    while(millis() - lastpublish < PUBLISH_MINIMUM) delay (100);
    client.add(topic, 1, message); // Insert as first parameter your variable label
    client.ubidotsPublish(deviceid); // Insert your device label where the values will be stored in Ubidots
    lastpublish = millis();
}


float voltage_calculation ()
{
    float denominator = resistor2 / (resistor1 + resistor2);
 
    int volt_average = 0;
    for (int i = 0; i <= 200; i++) {
        volt_average = volt_average + analogRead(volt); 
    }
    volt_average = volt_average / 201;
    
    //Convert to actual voltage (0 - 3.3 Vdc)
    float result = (((float)volt_average / 4096) * 3.3) / denominator;

    return result;    
}

float amp_calculation ()
{
    
        // Read amp at a sampling rate 
    // First, find sampling frequency
    float freq = 7 * (((float)1000000 / (float)hertz) / (float)256);
      
    int analogstatetotal = 0;
    int count = 0;
    unsigned long micros_start = micros();
    while (count <= 1792)
    {
        
        float totaltime = freq * count;
        if (micros() >= (micros_start + totaltime))
        {
            analogstatetotal = analogstatetotal + analogRead(amp);
            count++;
        }
    }
    

    int analogstate = analogstatetotal / count;
    
    if (lightvalue_old == 0)
    {
        amp_calibration = analogstate - 2048;
    }
    
    // Calibration
    analogstate = analogstate - amp_calibration;
    
    float vout = (((float)analogstate / (float)4096) * 3.3);
    float i = 73.3 * ((float)vout / 3.3) - 36.65;
    return i;
}


int compare (const void * a, const void * b) {
  float fa = *(const float*) a;
  float fb = *(const float*) b;
  return (fa > fb) - (fa < fb);
}


float calculate_daily_watt ()
{
    // Estimate watt usage 
    float watt_pr_ds = (float)watt_readout / lightvalue_old;
    
    
    float value_max_calc = (float)value_max * watt_pr_ds;
    float value_min_calc = (float)value_min * watt_pr_ds;
    float value_mid1_calc = (float)value_mid1 * watt_pr_ds;
    float value_mid2_calc = (float)value_mid2 * watt_pr_ds;
    
    
    //hours of daylight
    float value_max_hours = (sunsettime - sunrisetime) / (float)60;
    float value_min_hours = (float)0;
    float value_mid1_hours = (float)0;
    float value_mid2_hours = (float)0;
    
    if (value_max_hours > 22) 
    {
        
        if (value_max_hours > 23) 
        {
            value_mid2_hours = ((float)60 / 60) - (24 - value_max_hours);
        }
        else
        {
            value_mid1_hours = ((float)60 / 60) - (23 - value_max_hours);
            value_mid2_hours = (float)60 / 60;
        }
        
    }
    else
    {
        value_min_hours = (((22 * 60) - sunsettime) + sunrisetime) / (float)60;
        value_mid1_hours = (float)60 / 60;
        value_mid2_hours = (float)60 / 60;
    }
    
    float value_max_watt = value_max_hours * (float)value_max_calc;
    float value_min_watt = value_min_hours * (float)value_min_calc;
    float value_mid1_watt = value_mid1_hours * (float)value_mid1_calc;
    float value_mid2_watt = value_mid2_hours * (float)value_mid2_calc;
    
    
    float sum = value_max_watt + value_min_watt + value_mid1_watt + value_mid2_watt;
    
    return sum;

}


void temperature()
{
    int temp_average = 0;
    for (int i = 0; i <= 200; i++) {
        temp_average = temp_average + analogRead(temp); 
    }
    temp_average = temp_average / 201;
    temp_readout = temperature_calculation(temp_average);
    sprintf(temp_readout_string, "%.1f", temp_readout);    
}


float temperature_calculation (int voltage)
{
    //Convert to actual voltage (0 - 3.3 Vdc) and subtract base voltage, and divide on 10mV as per the datasheet
    float temperature  = ((((float)voltage / 4096) * 3.3) - 0.5) / 0.01;
    return temperature;    
}


You are using char arrays most the time, why are you using String here?
strstr() would be the function to use instead of indexOf() for char arrays.

I’m also not sure if the payload[length] = '\0'; instruction is safe. As I have pointed out to Ubidots on several occasions it’s not safe (and poor practice) to use non-const parameters where modification is not expected nor allowed.
You may not see any bad effect for 3/4 of the possible payload lengths due to padding, but if your length % 4 == 0 you may actually overwrite some active memory.

Also some divisions may cause DIV/0 exceptions
e.g.

If lightvalue_old should happen to be 0 your code will crash and (at least on Gen1&2) cause an SOS panic reboot.

BTW
When doing divisions (especially double-fractions like 7 * (((float)1000000 / (float)hertz) / (float)256) it’s better practice to do as few as possible divisions and rather simplify the formulae to use multiplications instead (e.g. 7000000.0 / (256.0 * hertz)). That’s usually better for readability and also for precision.
These are also better rearranged

    float vout = (((float)analogstate / (float)4096) * 3.3);
    float i = 73.3 * ((float)vout / 3.3) - 36.65;
    return i;

to

    // no need to factor in and out 3.3 in the same calculation.
    // float vout = 3.3 * analogstate / 4096.0;
    // float i = 73.3 * vout / 3.3 - 36.63;
    // simplifies to 
    return 73.3 * analogstate / 4096.0 - 36.65;
    // origin of the constants 73.3 and 36.65 would be good to clarify in comment tho'

and

float temperature  = ((((float)voltage / 4096) * 3.3) - 0.5) / 0.01;

is better written as

float temperature  = (3.3 * 100 * voltage) / 4096.0 - 500;

Also …

It’s not the PWM frequency you control but the PWM duty cycle. The frequency should be constant (default value is 500Hz, so no need to set that in the call).

2 Likes

Hey @ScruffR !

Thanks for the constructive feedback and your time!

Missed this one… coming from PHP programming i don’t really have a good understanding of how different types of variables are used, and reading around the forum i have got the understanding that using Strings is bad practice. So i have tried to remove all String usage in the code while searching for the error that causes random reboots. Now i have removed this as well, thanks for noticing!

I’m not really sure how i should handle the payload in a better way? Searching around the internet gives this solution as common practice, i think. Suggestion?

But these aren’t changed frequently and i think the device have never restarted/failed while i have sendt new max/min values to the device.

I don’t think it causes an error on argon/boron at least, having a lightvalue_old as 0 worked fine. But i understand that DIV/0 is bad practice so i have changed my code so this will not happen, thanks!

Thanks, i’ve worked trought some of the formulas and simplified them. I usually just write them the same way they work in my head :smile: :smile:

Brain malfunction … i know thanks :rofl::rofl::grin:
I’ve set the frequency in a variable so that i can easily experiment with different frequencies, without updating it several places (im samplig frequency for ampere for example)

I don’t know if any of these changes will help on my random rebooting … but at least it is fixed now. I appreciate the input, i’m not a very experienced programmer :slight_smile:

1 Like

You’ve already got the idea in your code when dealing with topic where it wouldn’t be required :wink: , so we just “repurpose” that

    char p[length+1];
    memcpy(p, payload, length);
    p[length] = NULL;

after that just use p instead of payload.

1 Like

Thanks, worked like a charm :slight_smile: