Arduino Radio Pager Project Log 0
Preface⌗
Before reading this post, it helps to know a little about internet of things devices like the Arduino and the many things that it can do. Once you are familiar with it, you will understand this article more. If you already have the knowledge on IoT, sit tight grab a drink and read on. It’s ok if you skip some parts that are too complicated to understand.
Table of content⌗
- What is it about?
- The parts
- The idea
- Features
- The Plan
- Experimentation
- What’s next
- The code
8.1. Sender
8.2. Reciever - Conclusion
- Comments
What is it about?⌗
My brother told me about a little gadget that would allow you to communicate without talking or others seeing you. It is a small device that works like a walkie-talkie but much smaller. It would be a pair of small lipstick size units that fit in one hand where if you press a button on one side, it produces a response on the other end like a buzz or vibration for example. All done wirelessly through radio. You could be casually strolling by with this device in your pocket and communicate secretly in plain sight to someone next to you without being heard. This reminds me of a certain hand-holding couple who would talk through morse by squeezing each other’s hands. So the idea started to flower in my mind and I set out to buy some parts.
That diagram just looks like 2 phones. Well, that’s kind of the idea here with one major difference. It does not depend on other network services as it works over simple radio. Read on!
The parts⌗
- 2 Arduino pro micros
- 2 OLED screens
- 2 Pairs(reciever and transmitter) of RF-433 modules
- 2 18650 Battery holders and the 18650 cells too
- 2 Buzzers (There were no small vibration motors)
- 2 Breadboards for prototyping all of the parts
- Some perfboard for making quick and dirty soldered prototypes
- Not enough buttons(tactile switches)
- Jumper cables
The idea⌗
So now that I have bought all of the parts, it came time for LUNCH BABY!!!!! WOOOO. I ate a kebab or something I don’t remember. Ok back on track. It was time to assemble the darn thing. So I wired it all up. I won’t go into too much detail on what is connected to what. That will be for later logs. Or I might just update this one if I feel less lazy. And then, came time for DINNER!!! Ok I’ll stop. So now, I have to write code for it..WAIT DON’T CLOSE THE TAB PLEASE!. I swear It’s pretty fun. I had a plan in mind. I wanted to get uni-directional communication functioning completely before I made the 2 arduinos be able to talk to each other. To an end user, It would simply act like a simple text messenger. That’s quite far from the original morse idea. So to avoid straying away from the intended features, here are the ones I plan to have in this device.
Features⌗
- Live morse communication
- Bi-directional morse communication
Ether side will be able to press a key and the other side will respond with either a tone or a vibration.
- Bi-directional morse communication
- Convert text and send via morse
- Convert morse and send via text
- Full custom input text messaging
- Bi-directional text messaging
- Message delivery confirmation
- End to End encrypted text messaging
- Physical key exchange
- Auto key exchange(through radio - less secure)
- Range of more than 30 Meters
- Ability to broadcast to other RF-433 devices/modems
- Standby mode
- Ringing/Alert for incoming notification when on standby
- Clock display when on standby(will require an RTC module)
- Ability to dock to stationary antenna for insane range
I don’t even know if the arduino pro-micro even has enough program memory for all those features. It sure does have plenty of RAM though.
The plan⌗
Ok this is going to get convoluted so I’ll try my best to keep it as comprehensible as I can.
So at the moment of me writing this post. Uni-directional communication works perfectly and with good range.
And that’s while using a basic monopole(I know there is a proper name for this. I can’t recall it right now) antenna made of a wire a quarter of the wavelength of 433Mhz. And for the final device, I might use an even smaller one or a di-pole since the range can be improved by adjusting the trim potentiometer on the receiver end.
So, until I can make a shortened di-pole antenna, I’ll use the regular one.
The oled screen will have a menu that allows you to choose from the various modes like:
- Live morse
- Text messages
- Broadcast messages
- Key Refresh
- Saved Messages
- …
The way to interface with the oled screen is still undetermined. I currently Mcgivered a 3x3 keypad to use to select hard-coded messages and to send morse but for the final version, I’ll need one with directional keys or at least a 4x3 matrix keypad that will allow me to program in typing in T-9 mode. For the young kids reading, T-9 means typing a letter by repeatedly pressing a number until the desired letter is obtained and so on.
I have already tested the battery life of the devices and they seem to last for more than 5 days with screen on and actively sending and receiving radio packets. If and when the standby feature is implemented, that will be prolonged even further; I estimate 2 to 3 weeks of normal usage on a single charge.
For encryption I am still thinking of a way to make that work. I don’t want to import anymore libraries to the projects since that will just consume more program memory on the Arduino. Instead I will have to study a bit on how cryptography works(I hope they had tough me that in UNI but alas.) And then properly implement some sort of key generation and sharing which I currently have no idea how to do.
I sort of have an idea for automatically generating cryptographic keys and sharing them. So the way that would work is by sending little bits of the next key to be used over the currently already encrypted way that uses the previous key. But I have a hunch that if someone is really dedicated to cracking the cipher, they will eventually be able to do so and if they captured all the packets for a long time, only one breach will be needed and all the messages will become readable to the attacker the only way to regain a secure communication is to physically refresh the keys over a wired connection. This is an extremely improbable scenario but possible nonetheless.
The user-interface on the oled screen will have 2 sections.
- Status
- Content
The status section will display the signal level to the other device as well as the number of loss packets over time.
This is important since live morse will not work properly if there is packet-loss.
The content section simply shows the content that is currently being sent or recieved.
Next is a closeup of the oled screen.
There is no automatic text wrapping. So I’ll have to implement that later. Words just get abruptly cut to the next line.
Experimentation⌗
When it came to range, there were lots of variables to play with for making it better. In the RH_ASK.h file, there was the speed in bytes per second which I currently have set to 2000 and it’s rather fast. The more the speed is increased, the lesser range you get. Then, there is the physical trim potentiometer on the RF433 module itself. I noticed that when I am adjusting the pot, the range suddenly becomes better and when I lift off the screwdriver after adjusting, the range drops again. So I think that the screwdriver is acting like the ground pole in a di-pole antenna.
What’s next⌗
So now I will be implementing the features step by step. The one I’m going to be working on for the time being is the live morse feature since it will accomplish the idea that my brother had.
The code⌗
skip
Ok so the code is some real spaghetti bologna right now. I am not responsible if your arduino explodes π when you run this code. Also as I am currently working on the morse functionality, The code sketches that follow will be focused towards that.
Sender⌗
//
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
// β β
// β m m mmmm ""# β
// β ## ## mmm m mm mmm mmm m" "m m mm # m m β
// β # ## # #" "# #" " # " #" # # # #" # # "m m" β
// β # "" # # # # """m #"""" # # # # # #m# β
// β # # "#m#" # "mmm" "#mm" #mm# # # "mm "# β
// β m" β
// β "" β
// ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
#include <RH_ASK.h>
#include <SPI.h> // Not actually used but needed to compile
RH_ASK driver;
// oled stuff
#include <Wire.h> // i2c
#include <Adafruit_GFX.h> // For shapes and fancy things
#include <Adafruit_SSD1306.h> // To drive the screen itself
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// declare an SSD1306 display object connected to I2C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Buttons
const int buttonPin = 10; // the number of the pushbutton pin
int buttonState = 0;
// Keypad
#include <Keypad.h>
// Allow multitasking with mills.
unsigned long time = millis();
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
{'1', '2', '3'},
{'4', '5', '6'},
{'7', '8', '9'},
};
byte rowPins[ROWS] = {9, 8, 7}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {4, 5, 6}; //connect to the column pinouts of the keypad
//initialize an instance of class NewKeypad
Keypad customKeypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);
// ____ _
// / ___| ___| |_ _ _ _ __
// \___ \ / _ \ __| | | | '_ \
// ___) | __/ |_| |_| | |_) |
// |____/ \___|\__|\__,_| .__/
// |_|
//
void setup() {
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while (true);
}
display.clearDisplay();
//display.display();
delay(4000);
// Serial.begin(19200); // Debugging only
if (!driver.init())
Serial.println("init failed");
display.setTextSize(8); // text size
display.setCursor(0, 0);
update_display('0');
}
int messageID = 0;
const int messagesSize = 7;
const char *messages[messagesSize] = {
"Hakuna\nMatata",
"Hello\nWorld",
"It's free realstate",
"Arch BTW\n<3",
"The ARP\nProject",
"A nice\nthree\nliner. =)",
"bob",
};
// _
//| | ___ ___ _ __
//| | / _ \ / _ \| '_ \
//| |__| (_) | (_) | |_) |
//|_____\___/ \___/| .__/
// |_|
void loop() {
char customKey = customKeypad.getKey();
if (customKey) {
//messageID = 9;
String prevChar = String(customKey);
messageID = prevChar.toInt();
update_display(customKey);
//String keystate = customKey.getState()
if (customKey=='6'){
customKeypad.setHoldTime(100);
if(customKeypad.getState()==PRESSED){
messageID = 9;
update_display('P');
}else if(customKeypad.getState()==HOLD){
messageID = 9;
update_display('H');
}
if(customKeypad.getState()==RELEASED){
messageID = 6;
update_display('R');
}else{
messageID = 6;
}
}
}
//delay(200);
//Serial.println(customKey);
// Send nothing if the customkey 6 is pressed again to trigger the reciever to beep.
// if (customKey == '6' && messageID == 6){
// messageID = 9;
// }
if (millis() - time > 3) //Has 20 millisecond passed?
{
driver.send((uint8_t *)messages[messageID], strlen(messages[messageID]));
driver.waitPacketSent();
time = millis(); //and reset time.
}
}
void update_display(char content) {
display.clearDisplay();
display.setCursor(44, 6);
display.setTextColor(WHITE, BLACK); // text color
display.println(content);
display.display();
}
Reciever⌗
// ____ _
// | __ ) _ _ ___________ _ __ ___ _ __ | |_ _
// | _ \| | | |_ /_ / _ \ '__| / _ \| '_ \| | | | |
// | |_) | |_| |/ / / / __/ | | (_) | | | | | |_| |
// |____/ \__,_/___/___\___|_| \___/|_| |_|_|\__, |
// |___/
#include <RH_ASK.h>
#include <SPI.h> // Not actualy used but needed to compile
RH_ASK driver;
// oled stuff
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// declare an SSD1306 display object connected to I2C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// Allow multitasking with mills.
unsigned long time = millis();
// ____ _
// / ___| ___| |_ _ _ _ __
// \___ \ / _ \ __| | | | '_ \
// ___) | __/ |_| |_| | |_) |
// |____/ \___|\__|\__,_| .__/
// |_|
//
void setup() {
pinMode(8, OUTPUT);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
while (true);
}
//delay(5000);
display.clearDisplay();
display.setTextSize(8);
for (int i = 0; i <= 5; i++) {
display.clearDisplay();
display.setCursor(44, 6);
display.setTextColor(WHITE, BLACK);
display.println(i);
display.display();
delay(1000);
}
// Serial.begin(9600); // Debugging only
if (!driver.init())
Serial.println("init failed");
display.setTextSize(2); // text size
display.setCursor(0, 0);
digitalWrite(8, HIGH);
delay(100);
digitalWrite(8, LOW);
}
// initialize OLED display with address 0x3C for 128x64
//GLOBALS
unsigned long j = 0UL;
// _
//| | ___ ___ _ __
//| | / _ \ / _ \| '_ \
//| |__| (_) | (_) | |_) |
//|_____\___/ \___/| .__/
// |_|
void loop(){
uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
uint8_t buflen = sizeof(buf);
if (driver.recv(buf, &buflen)) // Non-blocking
{
int i;
j++;
// Message with a good checksum received, dump it.
driver.printBuffer("Got:", buf, buflen);
Serial.print("Message: ");
Serial.println((char*)buf);
display.clearDisplay();
display.setTextSize(2);
display.setCursor(0, 0);
display.setTextColor(WHITE, BLACK); // text color
String str = ((char*)buf);
//display.println((char*)buf);
display.println(str.substring(0, buflen));
display.setTextSize(1);
display.setCursor(0, 49);
display.print("Packets: "); display.println(j);
display.print("Length: "); display.println(buflen);
display.drawLine(0, 47, display.width() - 1, 47, WHITE);
display.display();
// If message of length more than 2 chars recieved, then BUZZ!
if (buflen > 2){
digitalWrite(8, LOW);
}else if(buflen <= 2){
digitalWrite(8, HIGH);
}
}
}
void beep(){
}
If you skipped the code part,⌗
π₯ No problem but if you still wanna take a look here u go.
The Code
Conclusion⌗
Doing this kind of project is a simple idea. But It’s the execution that will be the ultimate deciding factor on whether it’s a good project or not. But even if it fails, I have learned a lot about antennas, how to calculate their lengths, how to optimize them, how to edit arduino code and upload it directly from the Linux terminal without using the bloated IDE. The best part about this kind of project is that when it’s complete, anyone can replicate it freely. Once I have a stable enough system for it, I will publish the source code in a git repo so that you can insult the level of crappiness of the code and probably make it better. It’s also like writing an entire OS around the components that I used like a menu for the screen(that can be carried to other projects). All in all, so far so good.
Let me know in the πcommentsπ what you think and anything else you want to say.
Thanks for the read! <3