I have my desktop PC meter away from my bed so naturally I like to watch YouTube and movies from the comfort of my bed. Every time I lay down, however, I find myself needing to adjust volume, pause video for some reason, or simply skip video entirely. I could just lean forward and hit a button on the keyboard but I'm too lazy to do that so instead I decided to spend dozens of hours designing and building this remote control for my PC. It's really just wireless keyboard.
I have actually had wireless keyboard already but it's a keyboard. When the lights are off it's basically impossible to find the key I'm looking for. On top of that with it's tiny size I'm more likely to press three buttons at once than the one I want even with my tiny fingers. But really it's just an excuse to build something cool.
It's using Arduino Micro which has ATmega32u4 capable of acting as HID to a computer. Since it works like regular keyboard I even managed to control my android phone with it. For the wireless communication I'm using nRF24L01 and the rotary encoder for volume is custom made with mechanical microswitches. Build instructions can be found here.
#include <SPI.h>
#include <NRFLite.h>
#include "HID-Project.h"
const static uint8_t RADIO_ID = 7; // Our radio's id. The transmitter will send to this id.
const static uint8_t PIN_RADIO_CE = 9;
const static uint8_t PIN_RADIO_CSN = 10;
struct RadioPacket // Any packet up to 32 bytes can be sent.
{
uint8_t FromRadioId;
uint32_t OnTimeMillis;
uint32_t FailedTxCount;
};
NRFLite _radio;
RadioPacket _radioData;
void setup()
{
if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN)) //Checks if radio is connected
{
while (1); // Wait here forever.
}
Consumer.begin(); //initialization of keyboard. Arduino will act as HID
pinMode(LED_BUILTIN, OUTPUT);
}
void loop()
{
while (_radio.hasData()) //when data is received over radio
{
digitalWrite(LED_BUILTIN,HIGH);
_radio.readData(&_radioData);
int msg = _radioData.OnTimeMillis; //saves received data in msg
bool YTflag = true; //Determines youtube or media mode
if (msg > 100) { //checks if the remote is in youtube or media mode
YTflag = false;
msg -= 100;
}
switch(msg){ //Outputs appropriate key presses as keyboard
case 4:
Consumer.write(MEDIA_VOLUME_DOWN);
break;
case 5:
Consumer.write(MEDIA_VOLUME_UP);
break;
case 6:
if (YTflag){
Keyboard.print("f");
}
else Consumer.write(MEDIA_PREVIOUS);
break;
case 7:
if (YTflag ){
Keyboard.press(KEY_LEFT_SHIFT);
Keyboard.press('n');
delay(50);
Keyboard.releaseAll();
}
else Consumer.write(MEDIA_NEXT);
break;
case 8:
if (YTflag) Keyboard.print("k");
else {
//Consumer.write(MEDIA_PLAY_PAUSE);
Keyboard.print(" ");
}
break;
case 14:
if (YTflag) Keyboard.print("j");
else Consumer.write(MEDIA_REWIND);
break;
case 15:
if (YTflag) Keyboard.print("l");
else Consumer.write(MEDIA_FAST_FORWARD);
break;
}
digitalWrite(LED_BUILTIN,LOW);
}
}
#include <SPI.h>
#include <NRFLite.h>
#include "Arduino.h"
#include <avr/sleep.h>
#include <avr/power.h>
#include "RF24.h"
volatile bool input = true;
bool YTmode = true;
long startTime;
int lowBattery = 740; //Low battery level (740 = 3.65V)
const static uint8_t RADIO_ID = 21; // Our radio's id.
const static uint8_t DESTINATION_RADIO_ID = 7; // Id of the radio we will transmit to.
const static uint8_t PIN_RADIO_CE = 9;
const static uint8_t PIN_RADIO_CSN = 10;
struct RadioPacket // Any packet up to 32 bytes can be sent.
{
uint8_t FromRadioId;
uint32_t OnTimeMillis;
uint32_t FailedTxCount;
};
RF24 radio(9,10);
NRFLite _radio;
RadioPacket _radioData;
void setup()
{
//Serial.begin(115200);
pinMode(2, INPUT); //interrupt
pinMode(3, INPUT); //mode Button
pinMode(4, INPUT); //volume down button
pinMode(5, INPUT); //volume up button
pinMode(6, INPUT); //previous button
pinMode(7, INPUT); //next button
pinMode(8, INPUT); //play button
/*
Radio Arduino
CE -> 9
CSN -> 10 (Hardware SPI SS)
MOSI -> 11 (Hardware SPI MOSI)
MISO -> 12 (Hardware SPI MISO)
SCK -> 13 (Hardware SPI SCK)
IRQ -> No connection
VCC -> No more than 3.6 volts
GND -> GND
*/
pinMode(14, INPUT); //rewind button
pinMode(15, INPUT); //skip button
pinMode(16,OUTPUT); //backlight LED
pinMode(17,OUTPUT); //blue LED
pinMode(18,OUTPUT); //red LED
checkBattery(); //checks battery status
initRadio(); //initialization of radio
_radioData.FromRadioId = RADIO_ID;
sendButton(0);
modeStatus();
attachInterrupt(digitalPinToInterrupt(2), isr, FALLING); //Interrupt setup
}
void loop() {
if(input){ //only occurs during isr method which is interrupt
checkButtons();
delay(10);
}
enterSleep(); //puts arduino to sleep to save power
}
void checkButtons(){ //Scans which button is pressed and sends message
startTime = millis();
digitalWrite(16,HIGH); //backlight on
checkBattery(); //makes sure battery isn't low
modeStatus(); //Lights up the mode LEDs(youtube / media)
radio.powerUp(); //wakes up radio from sleep
int message = 0; //message will be send at the of the method
while(millis()-startTime < 3000){ //runs for 3 seconds
message = 0;
if(digitalRead(4)) {
delay(3); //debouncing
while(digitalRead(4)){} //debouncing
delay(3); //debouncing
message = 4; //sets message that is going to be send
startTime = millis(); //resets timer
} else if
(digitalRead(5)) {
delay(3);
while(digitalRead(5)){}
delay(3);
message = 5;
startTime = millis();
}else if (digitalRead(6)) {
delay(10);
while(digitalRead(6)){}
delay(10);
message = 6;
startTime = millis();
}else if (digitalRead(7)) {
delay(10);
while(digitalRead(7)){}
delay(10);
message = 7;
startTime = millis();
}
else if (digitalRead(8)) {
delay(10);
while(digitalRead(8)){}
delay(10);
message = 8;
startTime = millis();
}else if (digitalRead(14)) {
delay(10);
while(digitalRead(14)){}
delay(10);
message = 14;
startTime = millis();
}else if (digitalRead(15)) {
delay(10);
while(digitalRead(15)){}
delay(10);
message = 15;
startTime = millis();
}else if (digitalRead(3)) {
delay(10);
while(digitalRead(3)){}
delay(10);
changeMode(); //changes between youtube and media mode
startTime = millis();
}
if(message == 0){} //checks if there is any message
else if(YTmode)sendButton(message); //in youtube mode message gets send normally
else sendButton(message + 100); //in media mode message is incremented by 100
delay(10);
}
digitalWrite(16,LOW); //turns off backlight
radio.powerDown(); //Puts radio to sleep
input =false; //prevents from looping
}
void sendButton(int buttonIndex){ //send data over radio
_radioData.OnTimeMillis = buttonIndex;
if (_radio.send(DESTINATION_RADIO_ID, &_radioData, sizeof(_radioData))) // Note how '&' must be placed in front of the variable name.
{
// Serial.println("...Success");
}
else
{
// Serial.println("...Failed");
_radioData.FailedTxCount++;
}
}
void isr(){ //called when interrupt happens which wakes up arduino from sleep
input = true;
}
void enterSleep(){ //Puts arduino to sleep to save power
digitalWrite(16,LOW); //Turns off all LEDs
digitalWrite(17,LOW);
digitalWrite(18,LOW);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_mode();
//waits until woken up
sleep_disable();
power_all_enable();
}
void changeMode(){ //Changes between youtube and media mode
delay(10);
while (digitalRead(3)){}
delay(10);
YTmode = !YTmode;
if(YTmode) {
digitalWrite(17,LOW);
digitalWrite(18,HIGH);
}else{
digitalWrite(17,HIGH);
digitalWrite(18,LOW);
}
}
void initRadio(){ //initialization of radio
if (!_radio.init(RADIO_ID, PIN_RADIO_CE, PIN_RADIO_CSN)) //if radio can't be found turn on all LEDs and do nothing.
{
digitalWrite(16,HIGH);
digitalWrite(17,HIGH);
digitalWrite(18,HIGH);
while (1); // Wait here forever.
}
}
void modeStatus(){
if(YTmode) { //setting the mode LED
digitalWrite(17,LOW);
digitalWrite(18,HIGH);
}else{
digitalWrite(17,HIGH);
digitalWrite(18,LOW);
}
}
void checkBattery(){ //makes sure battery isn't too low
if (analogRead(A5) < lowBattery){ //if battery is too low blink couple of times
for(int i=0; i<=4; i++){
digitalWrite(16,LOW);
delay(200);
digitalWrite(16,HIGH);
delay(200);
}
detachInterrupt(0); // detach interrupt and go to sleep. Arduino cannot be woken after this point. only reset will make it work
enterSleep();
}
}
Comments
Please log in or sign up to comment.