Thanks for the replies, everyone - I pulled an all-nighter and found that payload wasn't null-temrinated, just like PeterH said. I can't change the way it's sent (as it's coming from a third party program (MQTT)) but I converted it to a String then sorted it out from there.
Sorry for omitting the entirety of my code - I had managed to narrow it down to the code that I posted (when removing the atoi line the value didn't change every second time) but yes, I should have put it all in. For those still interested, here it is below:
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#define datapin 2
#define clockpin 3
#define latchpin 4
int current = 0; // 00000000
const int relayValues[]={
1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int relayCheck[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int changeVal = 0;
//char OnOrOff[] = {"off","on"};
//char DataResult[100]="Publishing data - relay "; //24
String OnOrOff;
String DataMash;
String DataResult;
byte mac[] = {
0xDE, 0xC0, 0xDE, 0xC0, 0xFF, 0xEE };
byte mqttserver[] = {
192, 168, 2, 7 };
byte ip[] = {
192, 168, 2, 101 };
//char DataMash[30]=" ";
EthernetClient ethClient;
PubSubClient clientr(mqttserver, 1883, callback);
/////////////////// calculateRelayVal ///////////////////
int calculateRelayVal(int newVal) {
// if newVal==0 then return value as 11111111
// newVal has relay we need to toggle
// referenced in relayCheck as newVal-1
int intRelayToWorkWith = relayValues[(newVal-1)];
if(relayCheck[(newVal-1)]==0) {
// relay is currently off, turn on
changeVal = current | intRelayToWorkWith;
relayCheck[(newVal-1)]=1;
}
else {
// relay is currently on, turn off
changeVal = current ^ intRelayToWorkWith;
relayCheck[(newVal-1)]=0;
}
current = changeVal;
return current;
}
/////////////////// doWork ///////////////////
void doWork(int val) {
// as relays need a '0' to turn on and a '1' to turn off, need to NOT this value
unsigned int realVal = ~val;
uint8_t rVlow = realVal & 0xff;
uint8_t rVhigh = (realVal >> 8);
digitalWrite(latchpin,LOW);
shiftOut(datapin,clockpin,MSBFIRST,rVhigh);
shiftOut(datapin,clockpin,MSBFIRST,rVlow);
digitalWrite(latchpin,HIGH);
}
/////////////////// callback ///////////////////
static void callback(char* topic, byte* payload, unsigned int length) {
char PublishData[24];
char tina[4];
String tp = (char*)payload;
(tp.substring(0,length)).toCharArray(tina,4);
unsigned int readVar = (unsigned int)atoi(tina);
if(readVar<0 || (readVar>16 && readVar!=999)) {
// if input is outside of specification (greater than 16 and not 999 (status check) or less than zero then make -1
// -1 is used in the switch below to indicate invalid input
readVar=-1;
}
if(readVar==999){
String strGetStatus="S:";
for(int i=0;i<16;i++){
strGetStatus+=relayCheck[i];
}
strGetStatus.toCharArray(PublishData,100);
// clientr.publish("RelayControlReport",PublishData);
clientr.publish("WebControl",PublishData);
}
else {
if(readVar>=0 && readVar<=16) {
int registerValue=0;
if(readVar > 0) {
registerValue = calculateRelayVal(readVar);
}
else {
current=0;
for(int i=0;i<16;i++){
relayCheck[i]=0;
}
}
doWork(registerValue);
if(relayCheck[(readVar-1)]==1){
OnOrOff=" on";
}
else {
OnOrOff=" off";
}
if(readVar!=0){
DataMash="Relay: ";
DataResult = DataMash + readVar + OnOrOff;
DataResult.toCharArray(PublishData,100);
}
else {
DataResult="All relays off";
DataResult.toCharArray(PublishData,100);
}
clientr.publish("RelayControlReport",PublishData);
}
}
}
/////////////////// setup ///////////////////
void setup()
{
pinMode(datapin,OUTPUT);
pinMode(clockpin,OUTPUT);
pinMode(latchpin,OUTPUT);
digitalWrite(latchpin,LOW);
shiftOut(datapin,clockpin,MSBFIRST,-1);
shiftOut(datapin,clockpin,MSBFIRST,-1);
digitalWrite(latchpin,HIGH);
delay(500);
Serial.begin(9600);
Serial.println(F("Scouris - MQTT Control, booting up."));
Serial.print(F("Eth start .."));
Ethernet.begin(mac,ip);
// below is for when running with DHCP
Serial.print(F("up, IP: "));
for (byte thisByte = 0; thisByte < 4; thisByte++) {
// print the value of each byte of the IP address:
Serial.print(Ethernet.localIP()[thisByte], DEC);
Serial.print(F("."));
}
Serial.println("");
if(clientr.connect("arduinoClient")) {
clientr.publish("checkInTopic","Relay Controller Online");
clientr.publish("RelayControlReport","Relay Controller Online");
clientr.subscribe("RelayControl");
}
doWork(0);
// delay(500);
}
/////////////////// loop ///////////////////
void loop()
{
clientr.loop();
}