LowPowerLab Forum

Software support => Coding questions => Topic started by: aburfitt on February 08, 2018, 08:06:17 AM

Title: Help using Keypad with Moteino
Post by: aburfitt on February 08, 2018, 08:06:17 AM
Hi Guys,
I am using the standard Moteino to read a custom 17key keypad I made and then transmit the Key pressed to a receiver.  Once the receiver receives the code it will drive a relay output.  Sounds simple  :)
I have written the code for the Keypad and it works great, all buttons are Identified when pressed.
I am using the keypad.h library for this.

As a test to make sure it would transmit and be received before I went any further I used this simple code on a 1 second delay.  It worked great and the receiver board received the commands every second.  So I know all my other settings are correct.

Code: [Select]
   if (radio.sendWithRetry(RECEIVER, "H", 1)) //target node Id, message as string or byte array, message length
        {
          Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
          Serial.println("Marker C Sent Ack"); Serial.println("Command Transmitted");
        }

Here is my Loop function that is not working.  When I press the 'H' button it does not transmit.
Is there some rule to say I can not do this within the Switch Case?
If I remove the sendwithretry and put a simple Serial.println("Marker H Pressed"); then it works every time so the Switch condition is working.

But as soon as I put the sendwithretry back in it will not transmit.  I am sure I am missing something simple here.
Do I need to call a function from the Switch Condition?  I tried that but couldn't get the button pressed to transfer into the function I made correctly.
I also tried a seperate if condition at the end of the Switch Case looking for the Key pressed and then calling the sendwithretry but no luck.
I may not have written this properly as I am still learning.

Can someone please have a look and let me know what I am doing wrong.  I am sure it is something simple I have missed.


Code: [Select]
void loop()  {

  char key = kpd.getKey();
  if (key) // Check for a valid key.
  {
    switch (key)
    {
      case 'H':
        if (radio.sendWithRetry(RECEIVER, "H", 1)) //target node Id, message as string or byte array, message length
        {
          Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
          Serial.println("Marker C Sent Ack"); Serial.println("Command Transmitted");
        }
        break;

      case 'C':
        if (radio.sendWithRetry(RECEIVER, "C", 1)) //target node Id, message as string or byte array, message length
        {
          Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
          Serial.println("Marker C Sent Ack"); Serial.println("Command Transmitted");
        }
        break;

      default:
        Serial.println(key); Serial.println("   Transmitted");
    }

  }
 }
UPTDATED: TomWS: enclosed in code blocks
Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 08, 2018, 09:15:01 AM
First, I modified your post so that the code portion is in code blocks (use the button with the '#') so they're easier to read.

Secondly, the only thing I don't see is a delay between calls to sendWithRetry().  If the key is pressed for any length of time, does the getkey() method return immediately?  If so, you should add a delay at the bottom of the if (key)... block.

Tom
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 08, 2018, 04:44:06 PM
Thank you Tom,
I am new to this so didn't realise you could do that.  It makes it much easier.

Yes as soon as a button is pressed it shows instantly in the Serial monitor screen. 

With the switch Case commands if 'H' is pressed it will display the 'H' button then there is a break command that puts it back into the loop waiting for another button to be pressed.  It doesn't keep displaying 'H' continuously until another is pressed.
Although just to check I might clear the key pressed to make sure.
I will also add a delay at the bottom to give it a chance to transmit the first keypress.

The serial monitor shows everything as if it should work, maybe there is a key bounce that the serial monitor is not picking up causing an instant retransmit.
I know it works otherwise as if I make it really simple and don't put any getkey calls in just a loop with a 1 second delay it transmits without fail.
Code: [Select]
 if (radio.sendWithRetry(RECEIVER, "H", 1)) //target node Id, message as string or byte array, message length
        {
          Blink(LED, 40, 3); //blink LED 3 times, 40ms between blinks
          Serial.println("Marker C Sent Ack"); Serial.println("Command Transmitted");
delay(1000);
        }


Is there anything else I may have done wrong?
Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 08, 2018, 05:30:36 PM
I think you need to begin at the beginning by:
1. Posting your sketch for both the transmitter and for the receiving nodes. (Use 'attachments')
2. You need to be more precise in your language.  When you say "Yes as soon as a button is pressed it shows instantly in the Serial monitor screen." (emphasis mine) According to the code you posted, the 'H' should never appear in the transmitter's Serial monitor so 'it' may mean something other than the 'H' returned by the getkey() method or 'Serial monitor screen' refers to a serial monitor attached to the receiver. 

Make it easy for people to help you by being crisp and clear on everything you're referencing.

Tom

Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 09, 2018, 05:17:42 AM
Thanks Tom,
Really appreciate your replies.

Your are correct my Serialprint line was not printing 'H' but a 'C'  This wasn't the case in the code.  It was a typo when I cut and pasted it into this forum.
These things happen when you are half asleep scratching your head about what you have done wrong at 1.30am in the morning.  :)

I have attached the transmit and receive codes.
The Receive code is basically Felix's TxRxBlinky.ino file.  The only thing I have done to the receiver code is to Change it to look for 1 byte transmitted as a 'H'.
Please let me know what you think.
Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 09, 2018, 08:41:40 AM
...
These things happen when you are half asleep scratching your head about what you have done wrong at 1.30am in the morning.  :)
....
I know of many bugs that were found and fixed at 1:30AM (and beyond).  However, I know exponentially more that were created at that time of day!

I'll try to take a look later today.
Tom
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 09, 2018, 05:35:26 PM
Yes I have as well many times.   :) This time it didn't help.

Thanks for having a look for me.  It really has me stumped and I am sure it is something very easy. 

I am looking forward to see what you find.  I am also working on it as well but have the feeling you will work it out first  ;) 8)
Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 09, 2018, 05:44:12 PM
Ignoring your redundant and duplicate (but harmless) .ino.ino naming convention, I suspect that your problem is related to this:
Code: [Select]
byte rowPins[ROWS] = {11, 10, 9, 8, 7, 6, 5};
// Connect keypad COL0, COL1 and COL2 to these Arduino pins.
byte colPins[COLS] = {2, 3, 4};

Note that the Moteino radio uses pins: 2, 10, 11, 12, & 13.
Note that the Moteino flash memory uses pins: 8, 11, 12, 13
Note that the Moteino LED uses pin 9.

You can send H's all day long as long as you don't press a key...

Tom

Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 09, 2018, 07:26:12 PM
 8)
Thanks Tom I was wondering along those lines but hadn't invested that far yet.  I wasn't confident enough in my programming skills to be sure it was hardware or my programming that was the problem.  Was ruling out the programming first.   :)

That will explain it then  ;D

I need 10 pins to make the keypad work... so the standard Moteino is not going to have enough pins is it.
 
I did buy a Moteino Mega for the remote originally but wired up the standard one and started using it to test code while waiting for it to arrive.

I will get the Mega out and wire it up.

Is there any pins to look out for on the Mega that I shouldn't use?

Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 09, 2018, 08:41:22 PM
...
I need 10 pins to make the keypad work... so the standard Moteino is not going to have enough pins is it.
...
I counted 7 pins: 4 rows, 3 cols needed for the keypad.  Looking at Moteino, I see, as spare, digital pins: 3,4,5,6,7,14,15,16,17, 18, & 19.  By my count, that's 10, leaving you 3 pins as 'extras'.
And, if you don't have a flash memory chip installed, pin 8 is also available.

So, what's the problem?
Tom
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 09, 2018, 11:28:37 PM
Thanks Tom,
I have 7 Rows and 3 Columns so need 10 pins the way I have wired it.

I had a good look at the pinouts after my last post and you are correct, there are enough spare pins to do what I want.

I don't have a Flash memory but To play it safe I thought I will use D3 - D7, D14 - D18.

Just out of interested you mentioned the Flash was only used on pin 8?  The pinouts from the website say D8, D11-D13 for the flash? 
It doesn't matter for this project but just interested which pins it actually uses for future reference.

Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 10, 2018, 04:03:02 AM
Thanks again for your help Tom.
I have changed the Pins around and it works perfect.

I Appreciate you giving me your time to help. 
Have a great weekend.
Title: Re: Help using Keypad with Moteino
Post by: Uncle Buzz on February 10, 2018, 04:28:49 AM
Just out of interested you mentioned the Flash was only used on pin 8?  The pinouts from the website say D8, D11-D13 for the flash? 

D11-D13 pins are used for SPI communication, D8 is the dedicated Chip Select for the flash IC on moteino. Removing flash IC will free D8, but if you use radio module, you still need SPI communication, D11-D13 are still in use.
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 10, 2018, 08:22:20 AM
Thanks Uncle Buzz,
I avoided those pins.
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 10, 2018, 08:40:41 AM
Hi Everyone,
I have a problem now with the receiver.  Not sure if I need a new thread or I can use this one. 

There are 17 receivers boards that drive there own single outputs in total for my project, one for each button on the remote.
I have written the code so that after the 'if (radio.receiveDone())' statement I then do a check to see if this receiver board has an active output already and if it does turn it off.
So what I am trying to do is...  Only one receiver can be active at a time so when any button is pressed the remote the active one will turn off and the receiver specific to the button pressed will turn on.  Make sense?

I have the receiver code working some of the time.  Most of the time it thinks the board is active when it is not.  I have played around with different code options and are not getting very far.

There must be a better way to do this.  Has anyone got any ideas?  I have attached the transmit and receiver files.
Is there a better way to do this?

Code: [Select]
#include <RFM69.h>
#include <SPI.h>
#include <LowPower.h>

//*********************************************************************************************
// *********** IMPORTANT SETTINGS - YOU MUST CHANGE/ONFIGURE TO FIT YOUR HARDWARE *************
//*********************************************************************************************
#define NETWORKID     100  //the same on all nodes that talk to each other
#define RECEIVER      1    //unique ID of the gateway/receiver
#define SENDER        2
#define NODEID        RECEIVER  //change to "SENDER" if this is the sender node (the one with the button)

#define FREQUENCY     RF69_915MHZ
#define ENCRYPTKEY    "sampleEncryptKey" //exactly the same 16 characters/bytes on all nodes!
#define IS_RFM69HW    //uncomment only for RFM69HW! Remove/comment if you have RFM69W!
//*********************************************************************************************
#define SERIAL_BAUD   115200
#define LED           9 // Moteinos have LEDs on D9
#define BUTTON_INT    1 //user button on interrupt 1 (D3)
#define BUTTON_PIN    3 //user button on interrupt 1 (D3)


RFM69 radio;

int Announce = 8;           //Pin used for Relay Output

void setup() {
  Serial.begin(SERIAL_BAUD);
  radio.initialize(FREQUENCY, NODEID, NETWORKID);
#ifdef IS_RFM69HW
  radio.setHighPower(); //only for RFM69HW!
#endif
  radio.encrypt(ENCRYPTKEY);
  char buff[50];
  sprintf(buff, "\nListening at %d Mhz...", FREQUENCY == RF69_433MHZ ? 433 : FREQUENCY == RF69_868MHZ ? 868 : 915);
  Serial.println(buff);
  Serial.flush();
  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED, OUTPUT);

  // initialize digital pin 4 as an Output to drive the relay to control Turn the Flood Lights on/off
  pinMode(8, OUTPUT);
  digitalWrite(Announce, LOW);
}

byte LEDSTATE = LOW; //LOW=0
byte Delay = LOW;

void loop() {

  //Receive Signal
  //check if something was received (could be an interrupt from the radio)


  if (radio.receiveDone())    //if radio has received a signal check what it is
  {
    delay(200);
    //print message received to serial
    Serial.print('['); Serial.print(radio.SENDERID); Serial.print("] ");
    Serial.print((char*)radio.DATA);
    Serial.print("   [RX_RSSI:"); Serial.print(radio.RSSI); Serial.print("]");
    Serial.println();

    if (radio.DATALEN == 1 && radio.DATA[0] =='Q' && LEDSTATE == HIGH);   // If any button is pressed on the remote and this marker is already calling than stop it calling and turn outputsoff
    {
      Serial.println("Receiver Output is Activated so Turning off Outputs");
      LEDSTATE = LOW;
      digitalWrite(LED, LEDSTATE);
      Serial.print("LED State =    ");Serial.print(LEDSTATE);
      Serial.println();
      digitalWrite(Announce, LEDSTATE);           // Set Output Low
      radio.DATA[0] = 'U';                                 //Set the DATA to a random letter like U to make sure of no false triggers
      Delay = LOW;
    }
  }
  //Exit out of if routine
  else
  {

  }

  //This section to looks for the Marker Letter for this Marker.
  //check if received message is 2 bytes long, and check if the message is specifically "H"

  if (radio.DATALEN == 1 && radio.DATA[0] == 'S' && LEDSTATE == LOW)
  {
    Serial.println("Receiver output is not Activated yet so turning on Outputs");
    LEDSTATE = HIGH;
    Delay = HIGH;                                                 //Activate Delay sequence until a button is pressed
    digitalWrite(Announce, HIGH);
    digitalWrite(LED, LEDSTATE);
    Serial.print("LEDSTATE Value:"); Serial.print(LEDSTATE);
    Serial.println();
    radio.DATALEN = 0;
    radio.DATA == 'Q';
 
  }

  //check if sender wanted an ACK
  if (radio.ACKRequested())
  {
    radio.sendACK();
    Serial.println(" - ACK sent");

  }


  radio.receiveDone(); //put radio in RX mode
  Serial.flush(); //make sure all serial data is clocked out before sleeping the MCU


/*  if (Delay == HIGH)
  {
    Serial.println(" entering Delay of 0.1 seconds");
    digitalWrite(Announce, LOW);
    delay(250);
    digitalWrite(Announce, HIGH);
  }
*/
}

Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 10, 2018, 05:09:56 PM
I haven't looked at your code, but there are lots of ways of doing what I think you want to do. The way to do it depends on how reliable vs how easy it is to do.

The simplest, by far, is to have your keypad transmitter simply broadcast the key code that was just pressed.  All the receivers will get the key code and, if it matches theirs, turn on.  If it doesn't, turn off.

It you want reliable with interlocks, then it gets tricky. 

Tom
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 10, 2018, 05:43:30 PM
Thanks Tom,
Yes that is pretty much what I have done.
The Transmitter is sending the code out to all receivers and if the code matches their code then they turn on.
I have tried to take it to the next level of checking which is where it is getting tricky.
If you are able to have a quick look it would be much appreciated.
Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 10, 2018, 06:23:58 PM
Thanks Tom,
Yes that is pretty much what I have done.
The Transmitter is sending the code out to all receivers and if the code matches their code then they turn on.
...
No, it isn't what you've done.  According to your code, you have set ALL of your receivers to the same ID, rendering sendWithRetry() useless.  Probably some of your receivers are getting the message, but the ACKs will collide with each other.

When I say 'broadcast' to all receivers, all receivers have a unique id and the sender sends (without retry) to RF69_BROADCAST_ADDR allowing all the receivers to see the same message.

Tom


Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 10, 2018, 08:15:08 PM
Quote
No, it isn't what you've done.  According to your code, you have set ALL of your receivers to the same ID, rendering sendWithRetry() useless.  Probably some of your receivers are getting the message, but the ACKs will collide with each other.
Oh... yes I see what you mean.  I did notice that on the serial monitor. 

Quote
When I say 'broadcast' to all receivers, all receivers have a unique id and the sender sends (without retry) to RF69_BROADCAST_ADDR allowing all the receivers to see the same message.

Ok cool, so I can get this correct in my head... each receiver should have its own ID like Receiver1, Receiver2, Receiver 3 etc but all part of the same network. (of course)

Can you please give me an idea of how to write the code for the command that does the broadcast to all receivers and then how the receiver receives the broadcast and looks to see if it the code is for it.
I see there is a promiscuous mode as well, although from what you have said Broadcost mode would be a better fit for me?

I had a look through the files and on the moteino website for where all this info is about the different functions and I couldn't see it.  Only examples with the different options in there.
There doesn't seem to be a document explaining all the code options, just info in the .cpp files. 
Have I missed something?
I am trying to learn at the same time myself without asking to many obvious questions.   :)
Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 10, 2018, 08:25:41 PM
...
Can you please give me an idea of how to write the code for the command that does the broadcast to all receivers and then how the receiver receives the broadcast and looks to see if it the code is for it.
I see there is a promiscuous mode as well, although from what you have said Broadcost mode would be a better fit for me?
...
Other than giving each receiver a unique ID (as a good practice), no changes are needed in the receivers - each will receive the transmitted messages although the TARGET value will be the RF69_BROADCAST_ADDR id rather than the receiver's id. 
The transmitter uses radio.send() instead of radio.sendWithRetry(), the node id is set to the RF69_BROADCAST_ADDR id, and don't bother to check for ACK, cuz there won't be one.

Tom
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 10, 2018, 09:21:11 PM
Ok Cool,
So what I need to do on the transmitter code is
Code: [Select]
#define RF69_BROADCAST_ADDR 255;

Then in place of:
Code: [Select]
if (radio.sendWithRetry(RECEIVER, "S", 1));

I use:
Code: [Select]
radio.send(RECEIVER, "S",1);

This will send to all Nodes on the network and will not ask for an ACK to be sent.

On the Receivers is there any point setting up the #define RF69_BROADCAST_ADDR 255; ?  I would guess probably not as they are just receiving?

The Command on the receiver will be the same:
Code: [Select]
if (radio.receiveDone());
And I can look for the radio data sent the same way as I did before?

Code: [Select]
if (radio.DATALEN == 1 && radio.DATA[0] == 'S')
Title: Re: Help using Keypad with Moteino
Post by: TomWS on February 10, 2018, 11:38:21 PM
Ok Cool,
So what I need to do on the transmitter code is
Code: [Select]
#define RF69_BROADCAST_ADDR 255;
No.  It is already a predefined constant.  Have you read the RFM69.h file at all?
Quote

Then in place of:
Code: [Select]
if (radio.sendWithRetry(RECEIVER, "S", 1));

I use:
Code: [Select]
radio.send(RECEIVER, "S",1);
sigh... no, you would use
Code: [Select]
radio.send(RF69_BROADCAST_ADDR,"S",1);
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 11, 2018, 01:29:06 AM
Thanks Tom,
That makes sense I will go it a try.
I appreciate your help and patience.  I am only fairly new to Arduino and so are learning all these things as I go along.
Title: Re: Help using Keypad with Moteino
Post by: HeneryH on February 16, 2018, 04:22:39 PM
This thread spurred me to take one of my stagnating projects to the next level.  Thanks aburfitt and Tom.  I will be using a standard 12-key number pad and queue keystrokes until the # key is detected then send the string to the gateway.  I won't pollute your thread but want to say thanks for the discussion here.
Title: Re: Help using Keypad with Moteino
Post by: aburfitt on February 16, 2018, 07:49:50 PM
Hi Henry,
Thanks for the post mate.
Glad I have inspired you  ;) 8)