Add support for IRBlaster, i.e. no PWM needed, the blaster generates the 38 kHz carrier frequency
This commit is contained in:
parent
8ec4be322f
commit
a04a96b2a2
168
IRSender.cpp
168
IRSender.cpp
|
@ -1,76 +1,13 @@
|
|||
#include <Arduino.h>
|
||||
#include <IRSender.h>
|
||||
|
||||
// Heavily based on Ken Shirriff's IRRemote library:
|
||||
// https://github.com/shirriff/Arduino-IRremote
|
||||
//
|
||||
// For PWM on Arduino, see http://playground.arduino.cc/Main/TimerPWMCheatsheet
|
||||
// The generic functions of the abstract IRSender class
|
||||
|
||||
IRSender::IRSender(uint8_t pin)
|
||||
{
|
||||
_pin = pin;
|
||||
}
|
||||
|
||||
// Set the PWM frequency. The selected pin determines which timer to use
|
||||
void IRSender::setFrequency(int frequency)
|
||||
{
|
||||
uint8_t pwmval8 = F_CPU / 2000 / (frequency);
|
||||
uint16_t pwmval16 = F_CPU / 2000 / (frequency);
|
||||
|
||||
pinMode(_pin, OUTPUT);
|
||||
digitalWrite(_pin, LOW); // When not sending PWM, we want it low
|
||||
|
||||
switch (_pin)
|
||||
{
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Arduino Mega
|
||||
case 9:
|
||||
// Fall-through to 10, timer2 controls both 9 and 10
|
||||
case 10:
|
||||
TCCR2A = _BV(WGM20);
|
||||
TCCR2B = _BV(WGM22) | _BV(CS20);
|
||||
OCR2A = pwmval8;
|
||||
OCR2B = pwmval8 / 3;
|
||||
break;
|
||||
case 11:
|
||||
// Fall-through to 12, timer1 controls both 11 and 12
|
||||
case 12:
|
||||
TCCR1A = _BV(WGM11);
|
||||
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||
ICR1 = pwmval16;
|
||||
OCR1A = pwmval16 / 3;
|
||||
OCR1B = pwmval16 / 3;
|
||||
break;
|
||||
case 44:
|
||||
// Fall-through to 46, timer 5 controls pins 44, 45 and 46 on Arduino Mega
|
||||
case 45:
|
||||
case 46:
|
||||
TCCR5A = _BV(WGM51) | _BV(WGM50);
|
||||
TCCR5B = _BV(WGM53) | _BV(CS50);
|
||||
ICR5 = pwmval16;
|
||||
OCR5A = pwmval16 / 3;
|
||||
#else
|
||||
// Arduino Duemilanove etc
|
||||
case 3:
|
||||
// Fall-through to 11, timer2 controls both 3 and 11
|
||||
case 11:
|
||||
TCCR2A = _BV(WGM20);
|
||||
TCCR2B = _BV(WGM22) | _BV(CS20);
|
||||
OCR2A = pwmval8;
|
||||
OCR2B = pwmval8 / 3;
|
||||
break;
|
||||
case 9:
|
||||
// Fall-through to 10, timer1 controls both 9 and 10
|
||||
case 10:
|
||||
TCCR1A = _BV(WGM11);
|
||||
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||
ICR1 = pwmval16;
|
||||
OCR1A = pwmval16 / 3;
|
||||
OCR1B = pwmval16 / 3;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Send a uint8_t (8 bits) over IR
|
||||
void IRSender::sendIRbyte(uint8_t sendByte, int bitMarkLength, int zeroSpaceLength, int oneSpaceLength)
|
||||
|
@ -92,6 +29,7 @@ void IRSender::sendIRbyte(uint8_t sendByte, int bitMarkLength, int zeroSpaceLeng
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// The Carrier IR protocol has the bits in a reverse order (compared to the other heatpumps)
|
||||
// See http://www.nrtm.org/index.php/2013/07/25/reverse-bits-in-a-uint8_t/
|
||||
uint8_t IRSender::bitReverse(uint8_t x)
|
||||
|
@ -105,102 +43,8 @@ uint8_t IRSender::bitReverse(uint8_t x)
|
|||
return x;
|
||||
}
|
||||
|
||||
// Send an IR 'mark' symbol, i.e. transmitter ON
|
||||
void IRSender::mark(int markLength)
|
||||
{
|
||||
switch (_pin)
|
||||
{
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Arduino Mega
|
||||
case 9:
|
||||
(TCCR2A |= _BV(COM2B1)); // Enable pin 3 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR1A |= _BV(COM1A1)); // Enable pin 9 PWM output
|
||||
break;
|
||||
case 12:
|
||||
(TCCR1A |= _BV(COM1B1)); // Enable pin 10 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR2A |= _BV(COM2A1)); // Enable pin 11 PWM output
|
||||
break;
|
||||
case 44:
|
||||
(TCCR5A |= _BV(COM5C1)); // Enable pin 44 PWM output on Arduino Mega
|
||||
break;
|
||||
case 45:
|
||||
(TCCR5A |= _BV(COM5B1)); // Enable pin 45 PWM output on Arduino Mega
|
||||
break;
|
||||
case 46:
|
||||
(TCCR5A |= _BV(COM5A1)); // Enable pin 46 PWM output on Arduino Mega
|
||||
break;
|
||||
#else
|
||||
// Arduino Duemilanove etc
|
||||
case 3:
|
||||
(TCCR2A |= _BV(COM2B1)); // Enable pin 3 PWM output
|
||||
break;
|
||||
case 9:
|
||||
(TCCR1A |= _BV(COM1A1)); // Enable pin 9 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR1A |= _BV(COM1B1)); // Enable pin 10 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR2A |= _BV(COM2A1)); // Enable pin 11 PWM output
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
delayMicroseconds(markLength);
|
||||
}
|
||||
|
||||
// Send an IR 'space' symbol, i.e. transmitter OFF
|
||||
void IRSender::space(int spaceLength)
|
||||
{
|
||||
switch (_pin)
|
||||
{
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Arduino Mega
|
||||
case 9:
|
||||
(TCCR2A &= ~(_BV(COM2B1))); // Disable pin 3 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR1A &= ~(_BV(COM1A1))); // Disable pin 9 PWM output
|
||||
break;
|
||||
case 12:
|
||||
(TCCR1A &= ~(_BV(COM1B1))); // Disable pin 10 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR2A &= ~(_BV(COM2A1))); // Disable pin 11 PWM output
|
||||
break;
|
||||
case 44:
|
||||
(TCCR5A &= ~(_BV(COM5C1))); // Disable pin 44 PWM output on Arduino Mega
|
||||
case 45:
|
||||
(TCCR5A &= ~(_BV(COM5B1))); // Disable pin 45 PWM output on Arduino Mega
|
||||
case 46:
|
||||
(TCCR5A &= ~(_BV(COM5A1))); // Disable pin 46 PWM output on Arduino Mega
|
||||
#else
|
||||
// Arduino Duemilanove etc
|
||||
case 3:
|
||||
(TCCR2A &= ~(_BV(COM2B1))); // Disable pin 3 PWM output
|
||||
break;
|
||||
case 9:
|
||||
(TCCR1A &= ~(_BV(COM1A1))); // Disable pin 9 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR1A &= ~(_BV(COM1B1))); // Disable pin 10 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR2A &= ~(_BV(COM2A1))); // Disable pin 11 PWM output
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Mitsubishi heatpump uses > 16383us spaces, and delayMicroseconds only works up to 2^14 - 1 us
|
||||
// Use the less accurate milliseconds delay for longer delays
|
||||
|
||||
if (spaceLength < 16383) {
|
||||
delayMicroseconds(spaceLength);
|
||||
} else {
|
||||
delay(spaceLength/1000);
|
||||
}
|
||||
}
|
||||
// Definitions of virtual functions
|
||||
void IRSender::setFrequency(int) {};
|
||||
void IRSender::space(int) {};
|
||||
void IRSender::mark(int) {};
|
32
IRSender.h
32
IRSender.h
|
@ -8,16 +8,38 @@
|
|||
|
||||
class IRSender
|
||||
{
|
||||
protected:
|
||||
IRSender(uint8_t pin); // Cannot create generic IRSender instances
|
||||
|
||||
public:
|
||||
IRSender(uint8_t pin);
|
||||
void setFrequency(int frequency);
|
||||
virtual void setFrequency(int frequency);
|
||||
void sendIRbyte(uint8_t sendByte, int bitMarkLength, int zeroSpaceLength, int oneSpaceLength);
|
||||
uint8_t bitReverse(uint8_t x);
|
||||
void space(int spaceLength);
|
||||
void mark(int markLength);
|
||||
virtual void space(int spaceLength);
|
||||
virtual void mark(int markLength);
|
||||
|
||||
private:
|
||||
protected:
|
||||
uint8_t _pin;
|
||||
};
|
||||
|
||||
|
||||
class IRSenderPWM : public IRSender
|
||||
{
|
||||
public:
|
||||
IRSenderPWM(uint8_t pin);
|
||||
void setFrequency(int frequency);
|
||||
void space(int spaceLength);
|
||||
void mark(int markLength);
|
||||
};
|
||||
|
||||
|
||||
class IRSenderBlaster : public IRSender
|
||||
{
|
||||
public:
|
||||
IRSenderBlaster(uint8_t pin);
|
||||
void setFrequency(int frequency);
|
||||
void space(int spaceLength);
|
||||
void mark(int markLength);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#include <Arduino.h>
|
||||
#include <IRSender.h>
|
||||
|
||||
// Send IR using the IR Blaster. The IR Blaster generates the 38 kHz carrier frequency
|
||||
|
||||
|
||||
IRSenderBlaster::IRSenderBlaster(uint8_t pin) : IRSender(pin)
|
||||
{
|
||||
pinMode(_pin, OUTPUT);
|
||||
}
|
||||
|
||||
|
||||
void IRSenderBlaster::setFrequency(int frequency)
|
||||
{
|
||||
(void)frequency;
|
||||
}
|
||||
|
||||
|
||||
// Send an IR 'mark' symbol, i.e. transmitter ON
|
||||
void IRSenderBlaster::mark(int markLength)
|
||||
{
|
||||
digitalWrite(_pin, HIGH);
|
||||
|
||||
if (markLength < 16383) {
|
||||
delayMicroseconds(markLength);
|
||||
} else {
|
||||
delay(markLength/1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send an IR 'space' symbol, i.e. transmitter OFF
|
||||
void IRSenderBlaster::space(int spaceLength)
|
||||
{
|
||||
digitalWrite(_pin, LOW);
|
||||
|
||||
if (spaceLength < 16383) {
|
||||
delayMicroseconds(spaceLength);
|
||||
} else {
|
||||
delay(spaceLength/1000);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,175 @@
|
|||
#include <Arduino.h>
|
||||
#include <IRSender.h>
|
||||
|
||||
// Heavily based on Ken Shirriff's IRRemote library:
|
||||
// https://github.com/shirriff/Arduino-IRremote
|
||||
//
|
||||
// For PWM on Arduino, see http://playground.arduino.cc/Main/TimerPWMCheatsheet
|
||||
|
||||
|
||||
IRSenderPWM::IRSenderPWM(uint8_t pin) : IRSender(pin)
|
||||
{
|
||||
pinMode(_pin, OUTPUT);
|
||||
digitalWrite(_pin, LOW); // When not sending PWM, we want it low
|
||||
}
|
||||
|
||||
|
||||
// Set the PWM frequency. The selected pin determines which timer to use
|
||||
void IRSenderPWM::setFrequency(int frequency)
|
||||
{
|
||||
uint8_t pwmval8 = F_CPU / 2000 / (frequency);
|
||||
uint16_t pwmval16 = F_CPU / 2000 / (frequency);
|
||||
|
||||
switch (_pin)
|
||||
{
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Arduino Mega
|
||||
case 9:
|
||||
// Fall-through to 10, timer2 controls both 9 and 10
|
||||
case 10:
|
||||
TCCR2A = _BV(WGM20);
|
||||
TCCR2B = _BV(WGM22) | _BV(CS20);
|
||||
OCR2A = pwmval8;
|
||||
OCR2B = pwmval8 / 3;
|
||||
break;
|
||||
case 11:
|
||||
// Fall-through to 12, timer1 controls both 11 and 12
|
||||
case 12:
|
||||
TCCR1A = _BV(WGM11);
|
||||
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||
ICR1 = pwmval16;
|
||||
OCR1A = pwmval16 / 3;
|
||||
OCR1B = pwmval16 / 3;
|
||||
break;
|
||||
case 44:
|
||||
// Fall-through to 46, timer 5 controls pins 44, 45 and 46 on Arduino Mega
|
||||
case 45:
|
||||
case 46:
|
||||
TCCR5A = _BV(WGM51) | _BV(WGM50);
|
||||
TCCR5B = _BV(WGM53) | _BV(CS50);
|
||||
ICR5 = pwmval16;
|
||||
OCR5A = pwmval16 / 3;
|
||||
#else
|
||||
// Arduino Duemilanove etc
|
||||
case 3:
|
||||
// Fall-through to 11, timer2 controls both 3 and 11
|
||||
case 11:
|
||||
TCCR2A = _BV(WGM20);
|
||||
TCCR2B = _BV(WGM22) | _BV(CS20);
|
||||
OCR2A = pwmval8;
|
||||
OCR2B = pwmval8 / 3;
|
||||
break;
|
||||
case 9:
|
||||
// Fall-through to 10, timer1 controls both 9 and 10
|
||||
case 10:
|
||||
TCCR1A = _BV(WGM11);
|
||||
TCCR1B = _BV(WGM13) | _BV(CS10);
|
||||
ICR1 = pwmval16;
|
||||
OCR1A = pwmval16 / 3;
|
||||
OCR1B = pwmval16 / 3;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Send an IR 'mark' symbol, i.e. transmitter ON
|
||||
void IRSenderPWM::mark(int markLength)
|
||||
{
|
||||
switch (_pin)
|
||||
{
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Arduino Mega
|
||||
case 9:
|
||||
(TCCR2A |= _BV(COM2B1)); // Enable pin 3 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR1A |= _BV(COM1A1)); // Enable pin 9 PWM output
|
||||
break;
|
||||
case 12:
|
||||
(TCCR1A |= _BV(COM1B1)); // Enable pin 10 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR2A |= _BV(COM2A1)); // Enable pin 11 PWM output
|
||||
break;
|
||||
case 44:
|
||||
(TCCR5A |= _BV(COM5C1)); // Enable pin 44 PWM output on Arduino Mega
|
||||
break;
|
||||
case 45:
|
||||
(TCCR5A |= _BV(COM5B1)); // Enable pin 45 PWM output on Arduino Mega
|
||||
break;
|
||||
case 46:
|
||||
(TCCR5A |= _BV(COM5A1)); // Enable pin 46 PWM output on Arduino Mega
|
||||
break;
|
||||
#else
|
||||
// Arduino Duemilanove etc
|
||||
case 3:
|
||||
(TCCR2A |= _BV(COM2B1)); // Enable pin 3 PWM output
|
||||
break;
|
||||
case 9:
|
||||
(TCCR1A |= _BV(COM1A1)); // Enable pin 9 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR1A |= _BV(COM1B1)); // Enable pin 10 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR2A |= _BV(COM2A1)); // Enable pin 11 PWM output
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
delayMicroseconds(markLength);
|
||||
}
|
||||
|
||||
|
||||
// Send an IR 'space' symbol, i.e. transmitter OFF
|
||||
void IRSenderPWM::space(int spaceLength)
|
||||
{
|
||||
switch (_pin)
|
||||
{
|
||||
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
// Arduino Mega
|
||||
case 9:
|
||||
(TCCR2A &= ~(_BV(COM2B1))); // Disable pin 3 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR1A &= ~(_BV(COM1A1))); // Disable pin 9 PWM output
|
||||
break;
|
||||
case 12:
|
||||
(TCCR1A &= ~(_BV(COM1B1))); // Disable pin 10 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR2A &= ~(_BV(COM2A1))); // Disable pin 11 PWM output
|
||||
break;
|
||||
case 44:
|
||||
(TCCR5A &= ~(_BV(COM5C1))); // Disable pin 44 PWM output on Arduino Mega
|
||||
case 45:
|
||||
(TCCR5A &= ~(_BV(COM5B1))); // Disable pin 45 PWM output on Arduino Mega
|
||||
case 46:
|
||||
(TCCR5A &= ~(_BV(COM5A1))); // Disable pin 46 PWM output on Arduino Mega
|
||||
#else
|
||||
// Arduino Duemilanove etc
|
||||
case 3:
|
||||
(TCCR2A &= ~(_BV(COM2B1))); // Disable pin 3 PWM output
|
||||
break;
|
||||
case 9:
|
||||
(TCCR1A &= ~(_BV(COM1A1))); // Disable pin 9 PWM output
|
||||
break;
|
||||
case 10:
|
||||
(TCCR1A &= ~(_BV(COM1B1))); // Disable pin 10 PWM output
|
||||
break;
|
||||
case 11:
|
||||
(TCCR2A &= ~(_BV(COM2A1))); // Disable pin 11 PWM output
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Mitsubishi heatpump uses > 16383us spaces, and delayMicroseconds only works up to 2^14 - 1 us
|
||||
// Use the less accurate milliseconds delay for longer delays
|
||||
|
||||
if (spaceLength < 16383) {
|
||||
delayMicroseconds(spaceLength);
|
||||
} else {
|
||||
delay(spaceLength/1000);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
#include <Arduino.h>
|
||||
#include <HisenseHeatpumpIR.h>
|
||||
|
||||
IRSender irSender(3); // IR led on Duemilanove digital pin 3
|
||||
IRSenderPWM irSender(3); // IR led on Duemilanove digital pin 3, using Arduino PWM
|
||||
//IRSenderBlaster irSender(3); // IR led on Duemilanove digital pin 3, using IR Blaster (generates the 38 kHz carrier)
|
||||
|
||||
HisenseHeatpumpIR *heatpumpIR;
|
||||
|
||||
|
|
|
@ -38,7 +38,8 @@ const byte heatpumpMaintenance = 2;
|
|||
Button relay1 = Button(11, INPUT_PULLUP); // Heatpump ON-OFF state
|
||||
Button relay2 = Button(12, INPUT_PULLUP); // FP mode (maintenance heating at 8 degrees C) ON-OFF state
|
||||
|
||||
IRSender irSender(9); // IR led on Duemilanove digital pin 9
|
||||
IRSenderPWM irSender(9); // IR led on Duemilanove digital pin 9, using Arduino PWM
|
||||
//IRSenderBlaster irSender(9); // IR led on Duemilanove digital pin 9, using IR Blaster (generates the 38 kHz carrier)
|
||||
|
||||
byte heatpumpState = heatpumpOff;
|
||||
|
||||
|
|
|
@ -1,205 +0,0 @@
|
|||
#include <Arduino.h>
|
||||
|
||||
// HeatpumpIR libraries
|
||||
#include <FujitsuHeatpumpIR.h>
|
||||
#include <PanasonicCKPHeatpumpIR.h>
|
||||
#include <PanasonicHeatpumpIR.h>
|
||||
#include <CarrierHeatpumpIR.h>
|
||||
#include <MideaHeatpumpIR.h>
|
||||
#include <MitsubishiHeatpumpIR.h>
|
||||
#include <SamsungHeatpumpIR.h>
|
||||
|
||||
// Timer library, https://github.com/ToniA/Timer
|
||||
#include <Timer.h>
|
||||
|
||||
// MySensors libraries
|
||||
#include <MySensor.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// This MySensors node has three childs, with ID's 1, 2 & 3
|
||||
#define CHILD_1 1
|
||||
#define CHILD_2 2
|
||||
#define CHILD_3 3
|
||||
|
||||
// MySensors definitions
|
||||
MySensor gw;
|
||||
MyMessage irMsg(CHILD_1, V_IR_RECEIVE);
|
||||
// Domoticz does not yet properly support the S_IR sensor type
|
||||
MyMessage textMsg(CHILD_2, V_TEXT);
|
||||
MyMessage sendMsg(CHILD_3, V_LIGHT);
|
||||
|
||||
// Array with all supported heatpump models
|
||||
HeatpumpIR *heatpumpIR[] = { new PanasonicCKPHeatpumpIR(), // 0, keep this if you don't remove the timer for cancelling Panasonic CKP messages
|
||||
new PanasonicDKEHeatpumpIR(), // 1
|
||||
new PanasonicJKEHeatpumpIR(), // 2
|
||||
new PanasonicNKEHeatpumpIR(), // 3
|
||||
new CarrierHeatpumpIR(), // 4
|
||||
new MideaHeatpumpIR(), // 5
|
||||
new FujitsuHeatpumpIR(), // 6
|
||||
new MitsubishiFDHeatpumpIR(), // 7
|
||||
new MitsubishiFEHeatpumpIR(), // 8
|
||||
new SamsungHeatpumpIR() // 9
|
||||
};
|
||||
|
||||
// IR led on PWM output-capable digital pin 3
|
||||
IRSender irSender(3);
|
||||
|
||||
// Timer for sending Panasonic CKP series timer cancellation commands
|
||||
Timer timer;
|
||||
int8_t panasonicCKPTimer = 0;
|
||||
|
||||
// Number of supported models
|
||||
byte models = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
delay(1000);
|
||||
Serial.println(F("HeatpumpIR sensor starting up..."));
|
||||
|
||||
models = sizeof(heatpumpIR) / sizeof(HeatpumpIR*);
|
||||
Serial.print(F("Number of supported models: ")); Serial.println(models);
|
||||
|
||||
// Auto-assign the node ID, do not forward messages
|
||||
gw.begin(incomingMessage, AUTO, false);
|
||||
|
||||
// Send the sketch version information to the gateway and Controller
|
||||
gw.sendSketchInfo("Heatpump Sensor", "1.0");
|
||||
|
||||
// Register a sensors to the MySensors Gateway
|
||||
gw.present(CHILD_1, S_IR, "IR sender");
|
||||
|
||||
// For Domoticz
|
||||
gw.present(CHILD_2, S_INFO, "IR data");
|
||||
gw.present(CHILD_3, S_LIGHT, "IR send");
|
||||
// The TEXT sensor is not created in Domoticz before data is sent
|
||||
gw.send(textMsg.setSensor(CHILD_2).set("00000000"));
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
gw.process();
|
||||
timer.update();
|
||||
}
|
||||
|
||||
|
||||
// Handle incoming messages from the MySensors Gateway
|
||||
void incomingMessage(const MyMessage &message) {
|
||||
|
||||
const char *irData;
|
||||
|
||||
// V_IR type message
|
||||
if (message.type==V_IR_SEND) {
|
||||
Serial.println(F("Received IR send command..."));
|
||||
irData = message.getString();
|
||||
Serial.print(F("Code: 0x"));
|
||||
Serial.println(irData);
|
||||
sendHeatpumpIRCommand(irData);
|
||||
}
|
||||
// Domoticz
|
||||
else if (message.type==V_LIGHT) {
|
||||
// When the button is pressed on Domoticz, request the value of the TEXT sensor
|
||||
Serial.println(F("Requesting IR code from Domoticz..."));
|
||||
gw.request(CHILD_2, V_TEXT, 0);
|
||||
} else if (message.type==V_TEXT) {
|
||||
// TEXT sensor value is received as a result of the previous step
|
||||
Serial.println(F("IR code received from Domoticz..."));
|
||||
Serial.print(F("Code: 0x"));
|
||||
|
||||
irData = message.getString();
|
||||
Serial.println(irData);
|
||||
|
||||
sendHeatpumpIRCommand(irData);
|
||||
|
||||
// Set the Domoticz switch back to 'OFF' state
|
||||
gw.send(sendMsg.setSensor(CHILD_3).set(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Decode the IR command and send the IR command to the heatpump
|
||||
void sendHeatpumpIRCommand(const char *irCommandString) {
|
||||
|
||||
// irCommandString is an 8-digit hex digit
|
||||
long irCommand = 0;
|
||||
int sscanfStatus = sscanf(irCommandString, "%lx", &irCommand);
|
||||
|
||||
if (sscanfStatus == 1) {
|
||||
Serial.print(F("IR code conversion OK: 0x"));
|
||||
Serial.println(irCommand, HEX);
|
||||
} else {
|
||||
Serial.println(F("Failed to convert IR hex code to number"));
|
||||
}
|
||||
|
||||
/*
|
||||
The heatpump command is packed into a 32-bit hex number, see
|
||||
libraries\HeatpumpIR\HeatpumpIR.h for the constants
|
||||
|
||||
12345678
|
||||
3 MODEL
|
||||
4 POWER
|
||||
5 OPERATING MODE
|
||||
6 FAN SPEED
|
||||
78 TEMPERATURE IN HEX
|
||||
|
||||
00213416 (as an example of a valid code)
|
||||
2 = PanasonicJKE
|
||||
1 = Power ON
|
||||
3 = COOL
|
||||
4 = FAN 4
|
||||
16 = Temperature 22 degrees (0x16 = 22)
|
||||
*/
|
||||
|
||||
byte model = (irCommand & 0x00F00000) >> 20;
|
||||
byte power = (irCommand & 0x00010000) >> 16;
|
||||
byte mode = (irCommand & 0x0000F000) >> 12;
|
||||
byte fan = (irCommand & 0x00000F00) >> 8;
|
||||
byte temp = (irCommand & 0x000000FF);
|
||||
|
||||
const char* buf;
|
||||
Serial.print(F("Model: "));
|
||||
|
||||
buf = heatpumpIR[model]->model();
|
||||
// 'model' is a PROGMEM pointer, so need to write a byte at a time
|
||||
while (char modelChar = pgm_read_byte(buf++))
|
||||
{
|
||||
Serial.print(modelChar);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("Model #: ")); Serial.println(model);
|
||||
Serial.print(F("Power: ")); Serial.println(power);
|
||||
Serial.print(F("Mode: ")); Serial.println(mode);
|
||||
Serial.print(F("Fan: ")); Serial.println(fan);
|
||||
Serial.print(F("Temp: ")); Serial.println(temp);
|
||||
|
||||
// Heatpump models start from 0, i.e. model number is always less than the number of different models
|
||||
if (model < models) {
|
||||
// This is a supported model
|
||||
|
||||
// Cancel the timer on Panasonic CKP heatpump
|
||||
if (model == 0) {
|
||||
Serial.println(F("Cancelling timer on Panasonic CKP heatpump..."));
|
||||
timer.stop(panasonicCKPTimer);
|
||||
}
|
||||
|
||||
Serial.println(F("All OK - sending IR command to heatpump..."));
|
||||
heatpumpIR[model]->send(irSender, power, mode, fan, temp, VDIR_UP, HDIR_AUTO);
|
||||
|
||||
if (model == 0) {
|
||||
Serial.println(F("Scheduling timer cancellation on Panasonic CKP heatpump..."));
|
||||
panasonicCKPTimer = timer.after(120000, panasonicCancelTimer); // Called after 2 minutes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Cancel the timer on the Panasonic CKP heatpump
|
||||
void panasonicCancelTimer()
|
||||
{
|
||||
PanasonicCKPHeatpumpIR *panasonicCKPHeatpumpIR = new PanasonicCKPHeatpumpIR();
|
||||
|
||||
panasonicCKPHeatpumpIR->sendPanasonicCKPCancelTimer(irSender);
|
||||
Serial.println(F("The TIMER led should now be OFF"));
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
# MySensors example
|
||||
|
||||
This example shows how HeatpumpIR could be integrated with the MySensors sensor network. As this sensor sends infrared signals,
|
||||
the natural sensor type is 'S_IR'. The heatpump/air conditioner signals are really long, so the signals need to be encoded somehow.
|
||||
|
||||
In this example the idea is to encode just this information, using 24 bits of data
|
||||
* model code (see the index of the array heatpumpIR in the code)
|
||||
* power state (for the rest, see the HeatpumpIR.h file for the constants)
|
||||
* operating mode
|
||||
* fan speed
|
||||
* temperature (the temperature is directly the temperature in HEX)
|
||||
|
||||
```
|
||||
An example:
|
||||
00213416 (as an example of a valid code)
|
||||
2 = PanasonicJKE
|
||||
1 = Power ON
|
||||
3 = COOL
|
||||
4 = FAN 4
|
||||
16 = Temperature 22 degrees (0x16 = 22)
|
||||
```
|
||||
|
||||
This sketch creates three sensors:
|
||||
* S_IR
|
||||
* S_INFO
|
||||
* S_LIGHT
|
||||
|
||||
The S_INFO and S_LIGHT sensors are for Domoticz, as it does not currently (as of V2.3093) support infrared code sending through the S_IR sensor type.
|
||||
|
||||
## Sending the code
|
||||
### MYSController
|
||||
|
||||
* Select the IR sensor on the 'Heatpump Sensor 1.0' node
|
||||
* Select 'IR_SEND' as the subtype
|
||||
* Enter for example '00213416' as the payload
|
||||
|
||||
### Domoticz
|
||||
|
||||
As Domoticz does not really support sending IR code yet, the workaround is to use two sensors. When the node is connected, Domoticz should find two new devices
|
||||
* A 'Lighting 2 / AC' type sensor with name 'IR send'
|
||||
* A 'General / Text' type sensor with name 'Unknown' and Data '00000000'
|
||||
|
||||
To send a command, first add the sensors. Then update the data of the text sensor to contain the IR code to be sent, and then flip the switch to trigger the sending.
|
||||
The data can be updated through the JSON REST API, or through the Lua event scripts.
|
||||
|
||||
REST API example (assuming that the idx of the text sensor is 105 and the switch is 104, and Domoticz is at 192.168.0.4:8080):
|
||||
```
|
||||
http://192.168.0.4:8080/json.htm?type=command¶m=udevice&idx=105&nvalue=0&svalue=00213416
|
||||
http://192.168.0.4:8080/json.htm?type=command¶m=switchlight&idx=104&switchcmd=On
|
||||
```
|
||||
|
||||
Lua example:
|
||||
* Seems that the text sensor can't be updated through the commandArray...
|
||||
* So now when a device called 'trigger' changes, the text sensor value is first updated to '00213416', and then the IR signal is sent
|
||||
|
||||
```
|
||||
commandArray = {}
|
||||
|
||||
for key, value in pairs(devicechanged) do
|
||||
if (key == 'trigger') then
|
||||
|
||||
print("Heatpump script")
|
||||
commandArray['OpenURL']='http://192.168.0.4:8080/json.htm?type=command¶m=udevice&idx=105&nvalue=0&svalue=00213416'
|
||||
commandArray['IR send']='On'
|
||||
end
|
||||
end
|
||||
|
||||
return commandArray
|
||||
```
|
||||
|
||||
## Hardware
|
||||
|
||||
Use any ATMega328-based Arduino, connect the radio, and finally connect an infrared led (in series with a resistor, like 100 Ohm) between digital pin 3 and GND.
|
|
@ -19,7 +19,8 @@
|
|||
*/
|
||||
|
||||
|
||||
IRSender irSender(3); // IR led on Duemilanove digital pin 3
|
||||
IRSenderPWM irSender(3); // IR led on Duemilanove digital pin 3, using Arduino PWM
|
||||
//IRSenderBlaster irSender(3); // IR led on Duemilanove digital pin 3, using IR Blaster (generates the 38 kHz carrier)
|
||||
|
||||
PanasonicCKPHeatpumpIR *heatpumpIR;
|
||||
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include <DaikinHeatpumpIR.h>
|
||||
|
||||
|
||||
IRSender irSender(3); // IR led on Duemilanove digital pin 3
|
||||
IRSenderPWM irSender(3); // IR led on Duemilanove digital pin 3, using Arduino PWM
|
||||
//IRSenderBlaster irSender(3); // IR led on Duemilanove digital pin 3, using IR Blaster (generates the 38 kHz carrier)
|
||||
|
||||
|
||||
// Array with all supported heatpumps
|
||||
HeatpumpIR *heatpumpIR[] = {new PanasonicCKPHeatpumpIR(), new PanasonicDKEHeatpumpIR(), new PanasonicJKEHeatpumpIR(),
|
||||
|
|
|
@ -15,6 +15,8 @@ SharpHeatpumpIR KEYWORD1
|
|||
DaikinHeatpumpIR KEYWORD1
|
||||
|
||||
IRSender KEYWORD1
|
||||
IRSenderPWM KEYWORD1
|
||||
IRSenderBlaster KEYWORD1
|
||||
|
||||
setFrequency KEYWORD2
|
||||
sendIRByte KEYWORD2
|
||||
|
|
Loading…
Reference in New Issue