Problem with SWITCH-CASE

Hello all. I'm getting a compiler error while using switch-case, and I can't figure out why. Have been experimenting a few hours now... time for help.

Short: I'm running a "Homey", a Dutch home automation hub. They have a neat arduino-library, Homeyduino. With it you can add a network-connected Arduino to your home-automation, to send commands and get states. I have a pool, and I want to control several devices for it with an 8-relay-board controlled by an Arduino with Ethernet Shield V2.

The Homeyduino-library creates 'actions' that are presented to / can be called by your Homey, that correspond to different functions in your Arduino-code. Homey can send arguments along, for example you can have an action "pump", that can be called by Homey with an argument, that makes that function "pump()" in your code will be called, and within that function the argument can be read to know how lung it should pump.
The library is a bit old though, and build for Homey v1. We are a few Homey-iterations further: it onky works now as long as you keep it to one or two actions.

So, as work-around I made one 'action', called Start - and am making use of the argument sent along to let the Arduino know what I want to do.
E.hg. if Homey sends "Start 1", the function "onStart()" is called, and from therein the argument '1' is read into INT "command". That var is then used to run the correct action (in this case: start the pump, "2" is to set the pump to low speed, etc etc).

At first I used IF-statements. This looked messy, and weirdly enough the IF-statement for command==12 would never run (checked with serial monitor to see if something within that IF even would run):

    if (command == 1) {
      Pump.high();
    };
    if (command == 2) {
      PumpLow.pulse(500);
    };
    if (command == 3) {
      PumpMid.pulse(500);
    };
    if (command == 4) {
      PumpHigh.pulse(500);
    };
    if (command == 5) {
      Pump.low();
    };
    if (command == 6) {
      PoolLight.high();
    };
    if (command == 7) {
      PoolLight.pulse(500);
    };
    if (command == 8) {
      PoolLight.low();
    };
    if (command == 9) {
      Covopen.pulse(500);
    };
    if (command == 10) {
      Covclose.pulse(500);
    };
    if (command == 11) {
      TechLight.high();
    };
    if (command == 12) {
      TechLight.low();
    };

    if (command == 13) {
    for (int thisPin = 0; thisPin < relayCount; thisPin++) { // Set the pins to which the relays for the horns are attached to OUTPUT
      digitalWrite(Relays[thisPin], LOW);
    }

So then I switched to an array of pointers - but that can't work since some om the functions being called have different arguments (the functions are created by ezOutput, so sometimes I need "pump.high()" to turn on the pump, but for selecting a different pump-speed I just need a pulse, bij calling "pump.low(500)")

So then I switched to SWITCH-CASE. And that, somehow, keeps throwing errors, now matter how I format it...

The error:

Arduino:1.8.19 (Windows Store 1.8.57.0) (Windows 10), Board:"Arduino Uno"

Zwembad_beta3.ino: In function 'void onStart()':

Zwembad_beta3:177:9: error: expected primary-expression before ':' token

     case: 8

         ^

Zwembad_beta3:178:9: error: expected ';' before 'PoolLight'

         PoolLight.low();

         ^~~~~~~~~

Zwembad_beta3:180:9: error: expected primary-expression before ':' token

     case: 9

         ^

Zwembad_beta3:181:9: error: expected ';' before 'Covopen'

         Covopen.pulse(500);

         ^~~~~~~

Zwembad_beta3:183:9: error: expected primary-expression before ':' token

     case: 10

         ^

Zwembad_beta3:184:9: error: expected ';' before 'Covclose'

         Covclose.pulse(500);

         ^~~~~~~~

Zwembad_beta3:186:9: error: expected primary-expression before ':' token

     case: 11

         ^

Zwembad_beta3:187:9: error: expected ';' before 'TechLight'

         TechLight.high();

         ^~~~~~~~~

Zwembad_beta3:189:9: error: expected primary-expression before ':' token

     case: 12

         ^

Zwembad_beta3:190:9: error: expected ';' before 'TechLight'

         TechLight.low();      break;

         ^~~~~~~~~

Zwembad_beta3:191:9: error: expected primary-expression before ':' token

     case: 13

         ^

Zwembad_beta3:193:9: error: expected ';' before 'for'

         for (int thisPin = 0; thisPin < relayCount; thisPin++) {

         ^~~

Zwembad_beta3:193:62: error: expected ';' before ')' token

         for (int thisPin = 0; thisPin < relayCount; thisPin++) {

                                                              ^

exit status 1

expected primary-expression before ':' token

The complete code:

/*
  Poolmaster
  ----------
  Control a relayboard from Homey. The Homey-library seems to be buggy - it does not work correctly with more than 2 actions presented to Homey.
  This program works around the problem, by only presenting two actions to Homey, while using the parameter that Homey can send through as a specificator
  for which action really should be taken.
*/

#include <SPI.h>
#include <Ethernet2.h>
#include <EthernetUdp2.h>
#include <Homey.h>
#include <ezOutput.h> // ezOutput library

byte mac[] = { 0x48, 0x6F, 0x6D, 0x65, 0x79, 0x00 };
const char* name = "Poolmaster";

// Set up the strings containing the command-descriptions to store

const char PROGMEM comm_0[] = "0 - No action";
const char PROGMEM comm_1[] = "1 - Start the pump";
const char PROGMEM comm_2[] = "2 - Set pump to LOW speed";
const char PROGMEM comm_3[] = "3 - Set pump to MID speed";
const char PROGMEM comm_4[] = "4 - Set pump to MAX speed";
const char PROGMEM comm_5[] = "5 - Stop the pump";
const char PROGMEM comm_6[] = "6 - Switch on pool light";
const char PROGMEM comm_7[] = "7 - Switch to next color";
const char PROGMEM comm_8[] = "8 - Switch off pool light";
const char PROGMEM comm_9[] = "9 - Open cover";
const char PROGMEM comm_10[] = "10 - Close cover";
const char PROGMEM comm_11[] = "11 - Switch on Techroom Light";
const char PROGMEM comm_12[] = "12 - Switch off Techroom Light";
const char PROGMEM comm_13[] = "13 - Set all relays to LOW";

// Then set up a table to refer to the strings.

const char *const comm_table[14] PROGMEM = {comm_0, comm_1, comm_2, comm_3, comm_4, comm_5, comm_6, comm_7, comm_8, comm_9, comm_10, comm_11, comm_12, comm_13};

char buffer[30];  // make sure this is large enough for the largest string it must hold

// Setting the relays

int const Relays[] = {13, 2, 3, 5, 6, 7, 8, 9, 14};   // array of pins to which relays are attached. Relays[0] is the builtin led, used for debugging / testing

int const relayCount = 9;                      // number of relays, inlcuding the builtin led

//Create array-pointers for the different attached systems/devices
int const TestPos = 0; // Testpin position in Relays[]
int const PumpPos = 1; // Pumppin position in Relays[]
int const PumpLowPos = 2; // Set pump to low speed
int const PumpMidPos = 3; // Set pump to mid speed
int const PumpHighPos = 4; // Set pump to high speed
int const PoollightPos = 5; // Relay to trigger the 2 pool-ledlights
int const CoveropenPos = 6; // Relay to send pulse for open-cover signal
int const CoverclosePos = 7; // Relay to send pulse for close-cover signal
int const TechLightPos = 8; // Light in technical room

//Create ezOutput instances for the different relay-pins
ezOutput Pump(Relays[PumpPos]);
ezOutput PumpLow(Relays[PumpLowPos]);
ezOutput PumpMid(Relays[PumpMidPos]);
ezOutput PumpHigh(Relays[PumpHighPos]);
ezOutput PoolLight(Relays[PoollightPos]);
ezOutput Covopen(Relays[CoveropenPos]);
ezOutput Covclose(Relays[CoverclosePos]);
ezOutput TechLight(Relays[TechLightPos]);


//Global variables used for the blink without delay example
unsigned long previousMillis = 0; // Regular use

uint8_t thisPin = 0;
uint8_t command = 0;
uint8_t coveropenTimer = 0;
uint8_t covercloseTimer = 0;

bool pumpStatus = false;
bool coverStatus = false;


//Arduino functions
void setup() {
  //Enable serial port
  Serial.begin(115200);

  //Connect to network
  Serial.println("Starting ethernet...");
  Ethernet.begin(mac);

  //Print IP address
  Serial.print("IP address: ");
  Serial.println(Ethernet.localIP());


  //Start Homey library
  Homey.begin(name); // The name of each Arduino on the network needs to be unique

  Homey.addAction("Start", onStart);

  Homey.addCondition("pomp_aan", onPumpCondition);
  Homey.addCondition("cover_open", onCoverCondition);

  for (int thisPin = 0; thisPin < relayCount; thisPin++) { // Set the pins to which the relays for the horns are attached to OUTPUT
    pinMode(Relays[thisPin], OUTPUT);
    digitalWrite(Relays[thisPin], LOW);
  }
  Serial.println("All pins set.");
  Serial.println("Poolmaster Started.");
}

void loop() {
  Homey.loop();
  Covopen.loop();
  Covclose.loop();
  PoolLight.loop();
  PumpLow.loop();
  PumpMid.loop();
  PumpHigh.loop();
  TechLight.loop();
  Pump.loop();
}



void onStart() {
  command = Homey.value.toInt(); //Read the argument sent by Homey to 'command' variable

  /* COMMANDS AVAILABLE:
     1 - Start the pump
     2 - Set pump to LOW speed
     3 - Set pump to MID speed
     4 - Set pump to MAX speed
     5 - Stop the pump
     6 - Switch on pool light
     7 - Switch to next color
     8 - Switch off pool light
     9 - Open cover
     10 - Close cover
     11 - Switch on Techroom Light
     12 - Switch off Techroom Light
     13 - Set all relays to LOW
  */

  // Check to see if the command is within valid range
  if ( (command < 1) || (command > 13) ) {
    return Homey.returnError("Invalid command joh!");
  } // End of IF-statement

  // Print the received command to serial monitor for debugging purposes
  Serial.print("Commando received: ");
  strcpy_P(buffer, (char *)pgm_read_word(&(comm_table[command])));  // Necessary casts and dereferencing.
  Serial.println(buffer);


  switch (command) {
    case 1:
      Pump.high();
      break;
    case 2:
      PumpLow.pulse(500);
      break;
    case 3:
      PumpMid.pulse(500);
      break;
    case 4:
      PumpHigh.pulse(500);
      break;
    case 5:
      Pump.low();
      break;
    case 6:
      PoolLight.high();
      break;
    case 7:
      PoolLight.pulse(500);
      break;
    case: 8
        PoolLight.low();
      break;
    case: 9
        Covopen.pulse(500);
      break;
    case: 10
        Covclose.pulse(500);
      break;
    case: 11
        TechLight.high();
      break;
    case: 12
        TechLight.low();      break;
    case: 13
        // Set the pins to which the relays are attached to OUTPUT
        for (int thisPin = 0; thisPin < relayCount; thisPin++) {
          digitalWrite(Relays[thisPin], LOW);
        } // End of FOR-loop
      break;
  } // End of SWITCH-CASE

} // End of FUNCTION


void onPumpCondition() {
  return Homey.returnResult(pumpStatus);
}

void onCoverCondition() {
  return Homey.returnResult(coverStatus);
}

void allOff() {
  for (int thisPin = 0; thisPin < relayCount; thisPin++) { // Set the pins to which the relays for the horns are attached to OUTPUT
    digitalWrite(Relays[thisPin], LOW);
  }
}

Move the colon:

case 8:
1 Like

Hahaha, really, I've read, re-read, re-re-read the code, triple-checked al my semicolons etc.
Selective blindness - thanks!

I can never remember the structure of switch...case, I have a total mental block about it. So I have a template in my text file of Arduino odds and ends, copy/paste it into the IDE.

Do you also have a problem with case 13 ?.
Ensure that you have compiler warnings switched on in preferences.

No problems there...
If I run the code for command 11, 12 and 13 succesively:

My serial monitor tells me it received code 11, and the relay switches (pin set HIGH)
My serial monitor tells me it received code 12, and nothing happens
My serial monitor tells me it received code 13, and the relay switches (pin set LOW)

All warnings on - just one when compiling:

                 from G:\Mijn Drive\Arduino\Zwembad\Zwembad_beta3\Zwembad_beta3.ino:12:
C:\Users\dscha\Documents\Arduino\libraries\Homeyduino\src/chip.h:12:22: warning: 'arduino_arch' defined but not used [-Wunused-variable]
   static const char* arduino_arch = "avr";

That unused variable warning is harmless. I looked again at case 13 and I see I made a mistake. Normally any variable definition within a case statement has to be in a block enclosed by { }. However, the scope of the variable thisPin is anyway limited to the "for" statement so it is not a problem here.

I found the culprit...
Somehow this part overwrites some memorybit:

strcpy_P(buffer, (char *)pgm_read_word(&(comm_table[command])));  // Necessary casts and dereferencing.

Before this part command still holds value '12', afterwards it's '0'.

This only happens with 12 and upwards, except the last number in the comm_table...
Weird - but solved :slight_smile:

this is too long for buffer: ```
const char PROGMEM comm_12[ ] = "12 - Switch off Techroom Light";

buffer has to be at least 31 characters to hold also the end of string terminator /0
1 Like

Thanks. I did my character count (and made the buffer a bit larger to leave some room to change the text), before I thought of adding option 11 and 12... By pure accident option 11 fitted exactly, and option 12 is one character too long. SOLVED, all is working now.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.