I think I need a matrix to make my code less repetitive

I think I need something along the lines of…

someDataType matrix [3][2] = {
{office, 0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A},
{bedroom, 0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A},
{kitchen, 0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A}
}

And then I need to essentially be able sort of foreach (probably in C, for) through this data. I find myself typing the word “office” over and over again in my code and I think there has to be a better way. Here’s my sketch (which has lots of ‘I am trying to figure this out lint in it’).

Thoughts on how I would accomplish this?

Thanks for everyone’s kindness and graciousness.

#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <stdlib.h>



#define ONE_WIRE_BUS 11
int resolution = 10; //.5 celcius
#define DEVICE "OfficeArduino"
#define DEVICEHELLO "OfficeArduino Connected"
//String campus = "campus";
//String building = "building";
//String room = "office";
//String subscription = campus+'/'+building+'/'+room+'/'+'#';
String test;
char *campus = "mycampus";
char *building = "mybuilding";
char *room = "office";
char *slash = "/";
char subscription[80];

strcpy(subscription, campus);
strcat(subscription, slash);
strcat(subscription, building);
strcat(subscription, slash);
strcat(subscription, room);
strcat(subscription, slash);

float setpoint = 45.00;
float actual = 44.44;
int state = 0;
int request = 0;
long lastMsg = 0;
float temp = 0;

char *cstring;
byte mac[]    = {  0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED };
IPAddress ip(192, 168, 0, 221);
IPAddress server(192, 168, 0, 222);

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

DeviceAddress office = { 0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A };

void callback(char* topic, byte* payload, unsigned int length) {
  for (int i=0;i<length;i++) {
    payload[length] = '\0';
    
    cstring = (char *) payload;
  }
  Serial.println(topic);
  Serial.println(cstring);
  setpoint = atof(cstring);
  Serial.println("The setpoint is...");
  
}

EthernetClient ethClient;
PubSubClient client(ethClient);

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Attempt to connect
    if (client.connect(DEVICE)) {
      Serial.println("connected");
      // Once connected, publish an announcement...
      client.publish("outTopic",DEVICEHELLO);
      // ... and resubscribe
      client.subscribe(subscription.c_str());
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup()
{
  
  // disable SD card if one in the slot
  pinMode(4,OUTPUT);
  digitalWrite(4,HIGH);
  Serial.begin(57600);
    sensors.begin();
    sensors.setResolution(office, resolution);
  
  client.setServer(server, 1883);
  client.setCallback(callback);
  
  Ethernet.begin(mac, ip);
  // Allow the hardware to sort itself out
  delay(1500);
  
}

void loop()
{
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
long now = millis();
  if (now - lastMsg > 60000) {
    lastMsg = now;
    sensors.requestTemperatures(); // Send the command to get temperatures
    temp = sensors.getTempF(office);
    Serial.println(temp);
    if (temp == -127.00) {
    Serial.println("error");
 } else {
      //client.publish("mytopic", String(temp).c_str(),TRUE);
      client.subscribe(subscription);
      }
  }
}
someDataType matrix [3][2] = {
{office, 0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A},
{bedroom, 0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A},
{kitchen, 0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A}
}

Perhaps you mean something like:

enum {office, bedroom, kitchen};
DeviceAddress addresses[] = {
/* office */      {0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A},
/* bedroom */ {0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A},
/* kitchen */    {0x28, 0xFF, 0x46, 0x82, 0x58, 0x16, 0x04, 0x9A} 
}


// Now you can use addresses[kitchen] for the kitchen DeviceAddress

I think you might need a struct type for each room, and an array of structs. Check out structs...

johnwasser: Perhaps you mean something like:

enum {office, bedroom, kitchen};

// Now you can use addresses[kitchen] for the kitchen DeviceAddress

Wow. That's really interesting. I've never stumbled across enum in all my googling of C data types.

Is there a way to sort of foreach through those so where I call them as a set. I'm guessing that enum is indexed so I should be able to have it go through and give me office, bedroom, kitchen back. Then that same index should be matched to the device address.

I just don't know how to "use" this. It looks like exactly what I need though.

The ‘enum’ (enumeration) is a shorthand way of declaring a bunch of integer constants. By default they start at 0 and increment by 1 which is perfect for naming the indexes of an array. In this example it’s roughly equivalent to:

const int office = 0;
const int bedroom = 1;
const int kitchen = 2;[

I don’t think you can get the names back out but you can use the values to index into an array:

const char *Names[] = {"Office","Bedroom","Kitchen"};

I would use “for (int i = 0; i <= 2; i++)” to go through the list, but I’m old-school. You could add a DS18B20_COUNT as element 3 of the enum and use: “for (int i = 0; i < DS18B20_COUNT; i++)”. That would allow you to add elements more easily.

According to someone the other day told me we can now use for each Java / C# style.

for (element : array){

But if that fails you can use sizeof creatively to do the same thing

for(int i = 0; i < sizeof(array)/sizeof(array[0]); i++){

Delta_G: According to someone the other day told me we can now use for each Java / C# style.

for (element : array){

If 'array' is 'addresses' then wouldn't each 'element' be a DeviceAddress? You can't use a DeviceAddress to index into the 'Names' array. Similarly, if 'array' is 'Names' then wouldn't each 'element' be a 'char *'? You can't use a 'char *' to index into the 'addresses' array.

johnwasser: If 'array' is 'addresses' then wouldn't each 'element' be a DeviceAddress? You can't use a DeviceAddress to index into the 'Names' array. Similarly, if 'array' is 'Names' then wouldn't each 'element' be a 'char *'? You can't use a 'char *' to index into the 'addresses' array.

Like I said, I just heard this so I'm not 100% that it works. But if it does I would expect it to work like it does in Java etc. You wouldn't index anything. element would just be an object of whatever type the array holds. You just use it as is.

String strings[4] = {"First", "Second", "Third", "Fourth"}

for (s : strings){
  Serial.print(s);
}

Hmm. I will definitely be experimenting. I'm going to be away from my pc for two days, but I definitely appreciate pointing me in the right direction.

struct SomeType {
  char *name;
  byte data[2][4];
};

SomeType matrix[]= {
{"office", {{0x28, 0xFF, 0x46, 0x82}, {0x58, 0x16, 0x04, 0x9A}}},
{"bedroom", {{0x28, 0xFF, 0x46, 0x82}, {0x58, 0x16, 0x04, 0x9A}}},
{"kitchen", {{0x28, 0xFF, 0x46, 0x82}, {0x58, 0x16, 0x04, 0x9A}}}
};


void foo() {
  for(int i = 0; i< sizeof(matrix)/sizeof(*matrix); i++) {
    Serial.println(matrix[i].name);
    // etc

  }
}

Can't use different data types in the same array.

Delta_G: Like I said, I just heard this so I'm not 100% that it works. But if it does I would expect it to work like it does in Java etc. You wouldn't index anything. element would just be an object of whatever type the array holds. You just use it as is.

That was my point. It works for a single array but not parallel arrays:

String strings[4] = {"First", "Second", "Third", "Fourth"}
int values[4] = {32, 17, 97, 14};

for (s : strings){
  Serial.print(s);
  Serial.print(" has the value ");
  Serial.println( ????? );  // No way to select the matching value
}

The solution would be to use structures, as shown by PaulMurrayCbr. Then you could:

struct SomeType {
  char *name;
  int value;
};

SomeType matrix[]= {
{"First", 32},
{"Second", 17},
{"Third", 97}
};

void foo() {
  for(record : matrix) {
    Serial.print(record.name);
    Serial.print(" has the value ");
    Serial.println( record.value);
  }
}

Oh I see your point. Yeah I was just answering the OP's other question about whether there was a for each construct. That's the reason I stayed away from his particular array names.

You guys helped me build this struct 6 months ago. I’m wondering if you could help me make it more dynamic by allowing my 1 wire address program to define these 0x28 addresses on boot?

I have a way of handling knowing where they’re at in the building that’s separate from the arduino itself, so essentially what I would want to do is to use the addr of the address finder to do something like

sensor_list[finder].addr = addr;

I’ve made some attempts with the code below, but the data types aren’t cooperating.

void discoverOneWireDevices(void) {
  byte i;
  byte present = 0;
  byte data[12];
  byte addr[8];

  Serial.print("Looking for 1-Wire devices...\n\r");
    while (ds.search(addr)) {
    //essentialy what I need to do is
    //sensor_list[finder].addr = addr;

  list = new Node{new Sensor{addr, "SensorName", NaN}, list};

    finder = finder + 1; 
    //Serial.print("\n\rFound \'1-Wire\' device with address:\n\r");
    for( i = 0; i < 8; i++) {
      Serial.print("0x");
      if (addr[i] < 16) {
        Serial.print('0');
      }
      Serial.print(addr[i], HEX);
      if (i < 7) {
        Serial.print(", ");
      }
    }
    if ( OneWire::crc8( addr, 7) != addr[7]) {
        Serial.print("CRC is not valid!\n");
        return;
    }
  }
  //Serial.print("\n\r\n\rThat's it.\r\n");
  ds.reset_search();
  return;
}

void loop(void) {
  // nothing to see here
}