Sending simple serial command on input state change

Thankyou

The debounce / delay I get

For sending the RC commands i don't understand how i send different commands for the different "channels" - anything i put in there will simply execute the same code no matter what button is pressed surely?

Should i be swapping the text in the "messages" array for the binary signal for each channel i want to send then inserting something along the lines of

myswitch.send(messages[switchPin][action]) so that it generates the RCSwitch command i need - myswitch.send("110101010011101010") or am i completely misunderstanding?

For sending the RC commands i don't understand how i send different commands for the different "channels" - anything i put in there will simply execute the same code no matter what button is pressed surely?

Why? Put the data to send in an array, too. Send the ith element of the array when the ith switch is turned on.

That's what i've done so far - It now feels wrong because it seems too simple though it is currently working roughly (switching too fast upsets RC-switch and makes it merge signals) but it seems like the switching / switch reading side of this is now working.

thankyou!

const byte inputs[] = {2, 3, 4};
const char * messages[][2] =
{
  {"100001010101101101110001", "100001010101101101110001"},
  {"100001010101101101110010", "100001010101101101110010"},
  {"100001010101101101110011", "100001010101101101110011"}
};

byte previousStates[3];
byte action;


#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();

void setup()
{
  Serial.begin(115200);
  
    // Transmitter is connected to Arduino Pin #10  
  mySwitch.enableTransmit(10);

  // Optional set pulse length.
 mySwitch.setPulseLength(357);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);}
void loop()
{
  for (int switchPin = 0; switchPin < 3; switchPin++)
  {
    byte currentState = digitalRead(inputs[switchPin]);
    if (currentState != previousStates[switchPin])
    {
      if (currentState == LOW)
      {  
        action = 0;
        mySwitch.send(messages[switchPin][action]);
      }
      else
      { 
        action = 1;
        mySwitch.send(messages[switchPin][action]);
      }
      Serial.println(messages[switchPin][action]);
    }
    previousStates[switchPin] = currentState;
  }
  delay(10);
}

is where i'm at so far.

It now feels wrong because it seems too simple

Amazing how simple usually works better.

but it seems like the switching / switch reading side of this is now working.

The delay() call is in the wrong place. It should be in the body of the

    if (currentState != previousStates[switchPin])
    {

statement, just before the closing bracket that lines up with that open bracket.

Like this?

void loop()
{
  for (int switchPin = 0; switchPin < 3; switchPin++)
  {
    byte currentState = digitalRead(inputs[switchPin]);
    if (currentState != previousStates[switchPin])
    {
      if (currentState == LOW)
      {  
        action = 0;
        mySwitch.send(messages[switchPin][action]);
      }
      else
      { 
        action = 1;
        mySwitch.send(messages[switchPin][action]);
      }
      Serial.println(messages[switchPin][action]);
    delay(10); //delay for debounce
    }
    previousStates[switchPin] = currentState;

  }

}

Like this?

Yes, but properly indented. 8)

//corrected//

When the board initialises it briefly transmits each of the binary codes (thus briefly switching the relays) which i assume is because it's comparing the input toggle to the non-existant previous states and because they don't match it's detecting the change and transmitting.

Presumably i have to set something in the initialisation sequence to tell it that when booting up it doesn't have to do the initial comparison in order to stop this blip?

It now feels wrong because it seems too simple though it is currently working roughly (switching too fast upsets RC-switch and makes it merge signals) but it seems like the switching / switch reading side of this is now working.

That's because it is simple
Read the inputs
If one has changed state determine which way it changed
Use the input number and direction of change to extract the appropriate message from the array
Send the message

which i assume is because it's comparing the input toggle to the non-existant previous states

Non-initialized, not non-existent.

You could read the current state in setup(), after setting the pin modes, and store the current state as the previous state, so that when loop() runs, there IS a defined previous state.

Ok so using the magic of cut-n-paste i come up with this which works but again, feels like a very blunt instrument

const byte inputs[] = {2, 3, 4};
const char * messages[][2] =
{
  {"100001010101101101110001", "100001010101101101110001"},
  {"100001010101101101110010", "100001010101101101110010"},
  {"100001010101101101110011", "100001010101101101110011"}
};

byte previousStates[3];
byte action;


#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();

void setup()
{
  Serial.begin(115200);
  
    // Transmitter is connected to Arduino Pin #10  
  mySwitch.enableTransmit(10);

  // Optional set pulse length.
 mySwitch.setPulseLength(400);
 
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
      for (int switchPin = 0; switchPin < 3; switchPin++)
      previousStates[switchPin] = digitalRead(inputs[switchPin]);
}
void loop()
{
  for (int switchPin = 0; switchPin < 3; switchPin++)
  {
    byte currentState = digitalRead(inputs[switchPin]);
    if (currentState != previousStates[switchPin])
    {
      if (currentState == HIGH)
      {  
        action = 1;
        mySwitch.send(messages[switchPin][action]);
      }
      else
      { 
        action = 0;
        mySwitch.send(messages[switchPin][action]);
      }
      Serial.println(messages[switchPin][action]);
      delay(10);
    }
    previousStates[switchPin] = currentState;

  }

}

So i understand what the code is doing in this section

byte previousStates[3];
byte action;

what does the 3 refer to, is it the 3 possible inputs and thus when scaling i need to change this to whatever number of inputs i'm using or does it refer to something else?

Same question for this section of code

  for (int switchPin = 0; switchPin < 3; switchPin++)

I read this as basically "when the numerical value of switchPin is 0 AND less than 3 then add 1 to it" but why is it less than 3 and not less than 2?

what does the 3 refer to, is it the 3 possible inputs

Yes.

It would be better written as

const byte inputs[] = {A1, A2, A3};
const byte NUMBER_OF_INPUTS = sizeof(inputs) / sizeof(inputs[0]);  //calculate number of elements in the array

Then everywhere in the code that you need to iterate through the arrays you do it like this

  for (int switchPin = 0; switchPin < NUMBER_OF_INPUTS; switchPin++)

You should also use it when declaring arrays that need the same number of elements as there are inputs

byte previousStates[NUMBER_OF_INPUTS];

I would have written it that way in the original code but wanted to keep it simple. Using this method you can simply add entries to the arrays without needing to change the for loop parameters.

why is it less than 3 and not less than 2

Because the array index for a 3 element array is from 0 to 2

Bingo

so switching to tags rather than actual numbers, expanding to 6 inputs and tweaking RC-Switch to tidy up the transmission i get this code which seems to be working and stable

const byte inputs[] = {1, 2, 3, 4, 5, 6};
const byte NUMBER_OF_INPUTS = sizeof(inputs) / sizeof(inputs[0]);  //calculate number of elements in the array
const char * messages[][2] =
{
  {"100001010101101101110001" , "100001010101101101110001" },
  {"100001010101101101110010" , "100001010101101101110010" },
  {"100001010101101101110011" , "100001010101101101110011" },
  {"100001010101101101110100" , "100001010101101101110100" }
  {"100001010101101101110101" , "100001010101101101110101" }
  {"100001010101101101110110" , "100001010101101101110110" }
};

byte previousStates[NUMBER_OF_INPUTS];
byte action;


#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();

void setup()
{
  Serial.begin(9600);
  
    // Transmitter is connected to Arduino Pin #10  
  mySwitch.enableTransmit(10);
  
  // Optional set protocol (default is 1, will work for most outlets)
  mySwitch.setProtocol(1);
  
  // Optional set pulse length.
  mySwitch.setPulseLength(357);

  // Optional set number of transmission repetitions.
  mySwitch.setRepeatTransmit(10);
 
  pinMode(1, INPUT_PULLUP);
  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, INPUT_PULLUP);
  pinMode(5, INPUT_PULLUP);
  pinMode(6, INPUT_PULLUP);
      for (int switchPin = 0; switchPin < NUMBER_OF_INPUTS; switchPin++)
      previousStates[switchPin] = digitalRead(inputs[switchPin]);
}
void loop()
{
  for (int switchPin = 0;switchPin < NUMBER_OF_INPUTS; switchPin++)
  {
    byte currentState = digitalRead(inputs[switchPin]);
    if (currentState != previousStates[switchPin])
    {
      if (currentState == HIGH)
      {  
        action = 1;
        mySwitch.send(messages[switchPin][action]);
      }
      else
      { 
        action = 0;
        mySwitch.send(messages[switchPin][action]);
      }
      Serial.println(messages[switchPin][action]);
      delay(400);
    }
    previousStates[switchPin] = currentState;

  }

}
const char * messages[][2] =
{
  {"100001010101101101110001" , "100001010101101101110001" },
  {"100001010101101101110010" , "100001010101101101110010" },
  {"100001010101101101110011" , "100001010101101101110011" },

It looks to me like all of your [n][0] messages are the same as the corresponding [n][1] messages. If that is the case, you are sending the same message when a switch becomes pressed as when the switch becomes released.

If that is the case, you don't need to distinguish when the switch becomes pressed vs. when the switch becomes released. You don't need a 2D array and you don't need the action variable.

The particular relays i'm playing with at the moment use the same command but i know many others use a different command for on and off so i figured it was better to design it with the option of sending different codes and under-use the facility than ask for help writing a single command version and have to come back later to ask about multi-code changes.

I am glad that you got it working. I told you that it was simple !

One minor suggested change would be to move this line

        mySwitch.send(messages[switchPin][action]);

to the same place as where the Serial.print occurs as you do the same thing whatever the action is.

Ok

so if i wanted different commands on the rise and fall then i'd keep the code where i have it now but use different commands (ie "Send code A" & "send code B")

If i want a command to go just when the state changes and the code isn't contextual then i put the code (ie "send code C") where serial.print occurs.

Presumably if i do both then it would send Code A followed by Code C on action 1 and Code B followed by Code C on action 0. So theoretically instead of "send code C" i could have it flash an LED / buzz / send a message to a screen to say that it's detected a change and transmitted the appropriate code?

I think so.

You can send different values/do different things when the switch becomes on/pressed from when it becomes off/released. You can send one value/do one thing (or block of things) when the state changes, regardless of what the state changes to/from.

So, you could send the code to turn the TV on when one switch is turned on, and send the code to turn the blender off when that switch is turned off. You can make a light flash for the blind person when the switch is moved, regardless of which position it is moved to.

What I was suggesting in post #34 was to change your program to this

    if (currentState != previousStates[switchPin])
    {
      if (currentState == HIGH)
      {
        action = 1;
      }
      else
      {
        action = 0;
      }
      mySwitch.send(messages[switchPin][action]);
      Serial.println(messages[switchPin][action]);
      delay(400);
    }

It is neater that way and does not duplicate code.

What is actually sent is, of course, determined by what you put in the messages[] array.