Arduino Pin value gets stuck
Not sure if this is your problem, but setPinValues looks weird to me:

void setPinValues(String message) {
  for(int i = 1; i &lt;= sizeof(pins) / sizeof(pins[0]); i++ ) {
    String pinNumber = String(i);

    if( message == pinNumber + "H\n" ) {
      pinValues[i] = HIGH;
    }
    if( message == pinNumber + "L\n" ) {
      pinValues[i] = LOW;
    }
  }
}


Going out of bounds

Each time you call setPinValues, i will range from 1 to length(pins), so if pins was declared as pins[5], i will be 1, 2, 3, 4 and 5. Assuming length(pins) == length(pinValues) this is a problem in itself, because pinValues[5] would not even exist!

pinValues[5] only creates pinValues[0] to pinValues[4] (yes, I know it's weird, you're declaring 5 elements but, since C is 0-indexed, they're 0, 1, 2, 3, and 4), so i should NEVER reach 5 or you will be out of bounds which is undefined behavior (and might well be the source of your problems) because you're writing to the wrong memory location.

The correct way to do this is looping from 0 to i &lt; sizeof(pins) / sizeof(pins[0]) (notice the strict less-than &lt; operator) which ranges from 0 to length(pins) - 1 and then just String pinNumber = String(i + 1);. That way, 1H will change the value of pinValues[0], mapping you 1-indexed serial messages to 0-indexed C arrays.

Looping is unnecessary

I'm not sure why you're looping over pins. You're doing unnecessary work and probably hogging the uC (specially since, as Dave Tweed points out in the other answer, you're using expensive functions such as String and string comparison with ==).

message has a single instance, e.g., 1H\n so there's no loop needed. char pinNumber = message[0] - '0'; will store the integer value of the first character in pinNumber, with which you're then able to index the array.

How does that work?


message[0] would be a char type (e.g. '1')
'0' is also a char, which corresponds to the ASCII value of 0 (48 in decimal).
If message[0] contains the char '0', then the result is '0' - '0' == 48 - 48 == 0
Since numbers are contiguous and increasing in the ASCII set the result of the subtraction is the actual number as a single byte integer.
'1' - '0' == 49 - 48 == 1 and on and on.


You might also want to reject bogus input:

if (pinNumber &gt;= sizeof(pins) / sizeof(pins[0]))
  return;


More spurious work

At each loop() iteration you do this:

// Write to pins        
for (int i = 1; i &lt;= sizeof(pins) / sizeof(pins[0]); i++) {
  digitalWrite(pins[i], pinValues[i]);
}


Which has the same problem with the out-of-bounds as before.

It also does unnecessary work, since you're writing ALL pin values, whether they changed or not! Why don't you digitalWrite(pins[pinNumber], HIGH or LOW); directly in setPinValues and avoid this loop? You could even get rid of the pinValues array if you don't really need to store them (or you can keep it if you need it for some reason).

My alternative setPinValues

void setPinValue(char pin, char value) {
  char pinNumber = pin - '0';  // Get the integer value of the ASCII char

  if (pinNumber &gt;= sizeof(pins) / sizeof(pins[0]))  // Reject out-of-bounds input
    return;

  switch (value) {
    case 'H':
      pinValues[pinNumber] = HIGH;  // Not necessary if you don't want to store the pin values
      digitalWrite(pins[pinNumber], HIGH);
      break;
    case 'L':
      pinValues[pinNumber] = LOW;  // Not necessary if you don't want to store the pin values
      digitalWrite(pins[pinNumber], LOW);
  }
}


And then just call it from loop() as setPinValue(message[0], message[1]);

Let me know if this solves your problem.