Created
June 12, 2016 15:05
-
-
Save tomasbasham/660c84c97bda9d8acb116062c2f56ae2 to your computer and use it in GitHub Desktop.
Netflic Switch code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Netflix | |
* | |
* A program that emits an IR singal to startup | |
* Netflix on a smart TV, lights up an array of | |
* LED lights and signals a control unit that a | |
* button press has occurred using MQTT. | |
* | |
* Hardware: Particle Photon | |
* Concept Usage: Netflix and Chill Button | |
*/ | |
SYSTEM_THREAD(ENABLED); // Run the application loop and the system loop on separate threads. | |
#include "MQTT/MQTT.h" | |
#include "Remote.h" | |
#define SWITCH_PIN A0 | |
#define IR_PIN A4 | |
#define LOGO_PIN A5 | |
#define LED_PIN D7 | |
#ifdef digitalPinToInterrupt | |
#define SWITCH_INTERRUPT digitalPinToInterrupt(SWITCH_PIN) | |
#else | |
#define SWITCH_INTERRUPT 10 | |
#endif | |
// Indicators pin numbers. | |
const byte indicators[] = { D0, D1, D2, D3, D4 }; | |
// MQTT Broker username, password and topic. | |
const char *username = "rylkuomv:rylkuomv"; | |
const char *password = "apZ_wxgdsJuSFKzzthG5scLfF9W3X5C6"; | |
const char *topic = "home/netflix"; | |
// MQTT RAW data. | |
const char *raw = "18274ef5761c95629376"; // This is to identify this button on the meassage queue. Just a random HEX string. | |
// MQTT server and port. | |
char *server = "chicken.rmq.cloudamqp.com"; | |
short port = 1883; | |
// Raw infrared data can be sniffed using an IR-receiver and e.g. https://github.com/z3t0/Arduino-IRremote/blob/master/examples/IRrecvDumpV2/IRrecvDumpV2.ino | |
unsigned int data[67] = { 4650, 4600, 450, 1800, 450, 1800, 450, 1800, 450, 650, 450, 650, 450, 700, 450, 650, 450, 700, | |
450, 1800, 450, 1800, 450, 1800, 450, 650, 450, 700, 450, 650, 450, 700, 400, 700, 450, 650, | |
450, 1800, 450, 700, 450, 650, 450, 650, 500, 650, 450, 650, 500, 650, 450, 1800, 450, 650, | |
450, 1800, 450, 1800, 450, 1800, 450, 1800, 450,1800, 450, 1800, 450 }; // UNKNOWN F4BA2988 | |
// Infrared transmitter. | |
Remote irSend(IR_PIN, LED_PIN); | |
// MQTT client. | |
MQTT client(server, port, NULL); | |
/** | |
* Initialize all the pins and their | |
* impedance. Also attach interrupts | |
* to transmit power over IR. | |
* | |
* @method setup | |
*/ | |
void setup() { | |
// Indicator pin modes. | |
for (int i = 0; i < sizeof(indicators) / sizeof(byte); i++) { | |
pinMode(indicators[i], OUTPUT ); | |
} | |
// Set the internal pullup resistor on | |
// the input switch pin. | |
pinMode(SWITCH_PIN, INPUT_PULLUP); | |
// Set the logo pin to output. | |
pinMode(LOGO_PIN, OUTPUT); | |
// Attach an interrupt to the switch | |
// pin to trigger off the IR pulse. For | |
// backwards compatibility we check the | |
// digitalPinToInterrupt function is | |
// present. | |
attachInterrupt(SWITCH_INTERRUPT, transmitPower, FALLING); | |
} | |
/** | |
* Main loop function for the program. | |
* Watch for changes on the switch pin | |
* and when the switch is pressed begin | |
* the light show. | |
* | |
* @method loop | |
*/ | |
void loop() { | |
if (digitalRead(SWITCH_PIN)) { | |
setLogoOn(); | |
setIndicatorState(HIGH); | |
// Make the connection to the | |
// messaging queue if not | |
// currently connected. | |
if (!client.isConnected()) { | |
client.connect(server, username, password); | |
} | |
// Push an MQTT message to the | |
// appropriate topic. | |
if (client.isConnected()) { | |
client.publish(topic, raw); | |
client.disconnect(); | |
} | |
delay(1500); | |
setIndicatorState(LOW); | |
setLogoOff(); | |
delay(500); | |
} else { | |
delay(100); | |
} | |
} | |
/** | |
* Transmit the pulse width sequence | |
* through the IR bulb. | |
* | |
* @method transmitPower | |
*/ | |
void transmitPower() { | |
for (int i = 0; i < 3; i++) { | |
irSend.transmit(data, sizeof(data) / sizeof(data[0])); | |
} | |
} | |
/** | |
* Fade in the logo using simple delay | |
* and PWM pins. | |
* | |
* @method setLogoOn | |
*/ | |
void setLogoOn() { | |
for (int i = 0; i <= 255; i++) { | |
analogWrite(LOGO_PIN, i); | |
delay(5); | |
} | |
} | |
/** | |
* Fade out the logo using simple delay | |
* and PWM pins. | |
* | |
* @method setLogoOn | |
*/ | |
void setLogoOff() { | |
for (int i = 255; i >= 0; i--) { | |
analogWrite(LOGO_PIN, i); | |
delay(5); | |
} | |
} | |
/** | |
* Sequentially turn on the indicator | |
* lights representing the dot below | |
* the netflix logo. | |
* | |
* @method setIndicatorState | |
* | |
* @param {bool} state | |
* The impedance of each indicator. | |
*/ | |
void setIndicatorState(bool state) { | |
for (int i = 0; i < sizeof(indicators) / sizeof(byte); i++) { | |
digitalWrite(indicators[i], state); | |
delay(500); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "application.h" | |
#include "Remote.h" | |
const int Remote::dutyCycle = 50; | |
const int Remote::carrierFrequency = 38000; | |
const int Remote::period = (1000000 + carrierFrequency / 2) / carrierFrequency; | |
const int Remote::highTime = period * dutyCycle / 100; | |
const int Remote::lowTime = period - highTime; | |
Remote::Remote(unsigned int irOutputPin, unsigned int ledPin) { | |
this->irOutputPin = irOutputPin; | |
this->ledPin = ledPin; | |
pinMode(this->ledPin, OUTPUT); | |
pinMode(this->irOutputPin, OUTPUT); | |
this->signalTime = 0; | |
} | |
void Remote::mark(unsigned int length) { | |
this->signalTime += length; // Mark ends at new signal time. | |
unsigned long now = micros(); | |
unsigned long dur = this->signalTime - now; // Allows for rolling time adjustment due to code execution delays. | |
if (dur == 0) return; | |
while ((micros() - now) < dur) { // Just wait here until time is up. | |
digitalWriteFast(this->irOutputPin, HIGH); | |
delayMicroseconds(this->highTime - 3); | |
digitalWriteFast(this->irOutputPin, LOW); | |
delayMicroseconds(this->lowTime - 4); | |
} | |
} | |
void Remote::space(unsigned int length) { | |
this->signalTime += length; // Space ends at new signal time. | |
unsigned long now = micros(); | |
unsigned long dur = this->signalTime - now; // Allows for rolling time adjustment due to code execution delays. | |
if (dur == 0) return; | |
while ((micros() - now) < dur); // Just wait here until time is up. | |
} | |
void Remote::transmit(unsigned int *data, size_t length) { | |
// Indicate we are sending the signal | |
digitalWriteFast(this->ledPin, HIGH); | |
this->signalTime = micros(); // Keeps rolling track of signal time to avoid impact of loop & code execution delays. | |
for (int i = 0; i < length; i++) { | |
this->mark(data[i++]); // Also move pointer to next position. | |
if (i < length) { | |
this->space(data[i]); // Pointer will be moved by for loop. | |
} | |
} | |
// Indicate we are finished sending the signal. | |
digitalWriteFast(this->ledPin, LOW); | |
// Wait 40 miliseconds seconds between each signal. | |
// Here was cannot simply use delay when in an ISR | |
// as it relies on interrupts iteslef casuing the | |
// applicatio to crash. Since delayMicroseconds | |
// instead relies on ASM NOP commands this is not | |
// an issue. | |
delayMicroseconds(40000); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef REMOTE_H | |
#define REMOTE_H | |
class Remote { | |
private: | |
int irOutputPin; | |
int ledPin; | |
unsigned long signalTime; | |
const static int dutyCycle; | |
const static int carrierFrequency; | |
const static int period; | |
const static int highTime; | |
const static int lowTime; | |
/** | |
* Pule the Infrared LED for a | |
* specific amount of time. | |
* | |
* @param {unsigned int} length | |
* The number of miliseconds to pulse the Infrared LED. | |
*/ | |
void mark(unsigned int length); | |
/** | |
* Turn off the Infrared LED for a | |
* specific amount of time | |
* | |
* @param {unsigned int} length | |
* The number of milliseconds to turn the Infrared LED off. | |
*/ | |
void space(unsigned int length); | |
public: | |
/** | |
* Instantiate a new remote object | |
* that will be used to send a NEC | |
* RAW signal. | |
* | |
* @param {unsigned int} irOutputPin | |
* The pin the Infrered LED is on. | |
* | |
* @param {unsigned int} ledPin | |
* The pin the indicator LED is on. Defaults to the built=in LED on pin D7. | |
*/ | |
Remote(unsigned int irOutputPin, unsigned int ledPin = D7); | |
/** | |
* Send the NEC RAW signal. | |
* | |
* @param {unsigned int*} data | |
* NEC RAW signal data to send. | |
* | |
* @para, {size_t} length | |
* Number of bytes in the NEC RAW signal data. | |
*/ | |
void transmit(unsigned int *data, size_t length); | |
}; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment