I have a series of messages incoming to Arduino over 6 different MQTT topics, they look like this:
Topic Payload
--------------------------------------------------------------------------------
/home/weath/now -> Overcast;5.90;78.00;1005.00;08:04;16:12 // Weather now
/home/weath/0 -> 2.00;7.00;60.00;Overcast // Weather today
/home/weath/1 -> Wednesday;2.00;7.00;0.00;Partly Cloudy;77.00 // Weather tomorrow
/home/weath/2 -> Thursday;1.00;5.00;20.00;Partly Cloudy;79.00 // etc.
/home/weath/3 -> Friday;0.00;6.00;20.00;Clear;73.00
/home/weath/4 -> Saturday;-1.00;6.00;0.00;Clear;72.00
There’s no specific reason for them to come in on different topics, it was an arbitrary decision.
The message format I’ve created for myself is, rightly or wrongly, consistent for the last 4 messages (day name;min temp;max temp;chance of precip;text desc;humidity), but not for the first two, which don’t require the day name, and also have barometric pressure, sunrise and sunset times.
MQTT library for Arduino presents the incoming payload as a character array, and there’s no reason for me to convert numerical values to ints/floats as I’m not doing anything with them except display on a screen.
So here’s a struct which holds the values (supports the latter 4 payloads mentioned, not the first 2):
struct weather {
char name[10]; // this is the DAY name
char min[7]; // e.g. -11.35 + null terminator
char max[9];
char precip[4]; // Percentage, e.g. up to 3 chars plus null terminator
char conditiontext[25]; // Longest = "scattered thunderstorms"
char humid[4]; // Percentage
};
typedef struct weather Weather;
Weather weatherDay[5];
I wanted to avoid memcpy’ing the payload to a dedicated buffer, as I don’t want to waste sram.
My horrendous / unmaintainable solution is as follows, but can someone point me in the direction of a more sensible / economic use of code?!
For each day (starting on array index 1 not 0), iterate through the payload (int i) and write the character array for the setting (int j), resetting j each time I start writing to the new setting. Each setting finishes with null terminator being added, and i is incremented again to skip over the delimiter ready for the next setting. As there’s no delimiter at the end, use length, which is provided by the MQTT callback function to determine when to stop writing the last setting.
It works, but it’s ugly. Please be as brutal as possible in suggesting better ways to do this:
for (int h=1;h<5;h++) { // start at weatherDay[1], 0 is reserved
sprintf (buff,"%s/%s/%i", rootvector, weathervector, h); // i.e. topic "home/weath/1" to "...4"
if(strcmp(topic, buff) == 0) {
int i=0;
int j=0;
do {
weatherDay[h].name[j] = payload[i];
i++;
j++;
} while (payload[i] != ';');
weatherDay[h].name[j] = '\0';
i++;
j=0;
do {
weatherDay[h].min[j] = payload[i];
i++;
j++;
} while (payload[i] != ';');
weatherDay[h].min[j] = '\0';
i++;
j=0;
do {
weatherDay[h].max[j] = payload[i];
i++;
j++;
} while (payload[i] != ';');
weatherDay[h].max[j] = '\0';
i++;
j=0;
do {
weatherDay[h].precip[j] = payload[i];
i++;
j++;
} while (payload[i] != ';');
weatherDay[h].precip[j] = '\0';
i++;
j=0;
do {
weatherDay[h].conditiontext[j] = payload[i];
i++;
j++;
} while (payload[i] != ';');
weatherDay[h].conditiontext[j] = '\0';
i++;
j=0;
do {
weatherDay[h].humid[j] = payload[i];
i++;
j++;
} while (i <= length);
weatherDay[h].humid[j] = '\0';
}
}