Skip to content

Instantly share code, notes, and snippets.

@tomasbasham
Created June 12, 2016 15:05
Show Gist options
  • Save tomasbasham/660c84c97bda9d8acb116062c2f56ae2 to your computer and use it in GitHub Desktop.
Save tomasbasham/660c84c97bda9d8acb116062c2f56ae2 to your computer and use it in GitHub Desktop.
Netflic Switch code
/**
* 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);
}
}
#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);
}
#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