2017-02-14 13:27:08 +00:00
|
|
|
/*
|
2018-05-28 10:35:23 +01:00
|
|
|
xdrv_05_irremote.ino - infra red support for Sonoff-Tasmota
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2019-01-01 12:55:01 +00:00
|
|
|
Copyright (C) 2019 Heiko Krupp, Lazar Obradovic and Theo Arends
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2017-05-13 12:02:10 +01:00
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2017-05-13 12:02:10 +01:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2017-05-13 12:02:10 +01:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2017-02-14 13:27:08 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef USE_IR_REMOTE
|
|
|
|
/*********************************************************************************************\
|
2017-10-06 16:28:00 +01:00
|
|
|
* IR Remote send and receive using IRremoteESP8266 library
|
2017-02-14 13:27:08 +00:00
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2018-11-07 09:30:03 +00:00
|
|
|
#define XDRV_05 5
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
#include <IRremoteESP8266.h>
|
2017-11-19 17:02:03 +00:00
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
enum IrErrors { IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND, IE_SYNTAX_IRHVAC };
|
|
|
|
|
2018-11-22 16:58:07 +00:00
|
|
|
enum IrRemoteCommands { CMND_IRSEND, CMND_IRHVAC };
|
|
|
|
const char kIrRemoteCommands[] PROGMEM = D_CMND_IRSEND "|" D_CMND_IRHVAC ;
|
|
|
|
|
2017-11-19 17:02:03 +00:00
|
|
|
// Based on IRremoteESP8266.h enum decode_type_t
|
2019-07-22 18:27:03 +01:00
|
|
|
static const uint8_t MAX_STANDARD_IR = SHARP; // this is the last code mapped to decode_type_t
|
|
|
|
enum IrVendors { IR_BASE = MAX_STANDARD_IR,
|
|
|
|
#ifdef USE_IR_SEND_PIONEER
|
|
|
|
IR_PIONEER,
|
|
|
|
#endif // USE_IR_SEND_PIONEER
|
|
|
|
};
|
2017-11-19 17:02:03 +00:00
|
|
|
const char kIrRemoteProtocols[] PROGMEM =
|
2019-07-22 18:27:03 +01:00
|
|
|
"UNKNOWN|RC5|RC6|NEC|SONY|PANASONIC|JVC|SAMSUNG|WHYNTER|AIWA_RC_T501|LG|SANYO|MITSUBISHI|DISH|SHARP"
|
|
|
|
// now allow for other codes beyond the first series;
|
|
|
|
#ifdef USE_IR_SEND_PIONEER
|
|
|
|
"|PIONEER"
|
|
|
|
#endif // USE_IR_SEND_PIONEER
|
|
|
|
;
|
2017-11-19 17:02:03 +00:00
|
|
|
|
|
|
|
#ifdef USE_IR_HVAC
|
|
|
|
|
|
|
|
#include <ir_Mitsubishi.h>
|
2018-11-19 18:39:44 +00:00
|
|
|
#include <ir_Fujitsu.h>
|
2017-10-08 15:51:05 +01:00
|
|
|
|
2019-07-21 17:06:13 +01:00
|
|
|
enum IrHvacVendors {
|
|
|
|
VNDR_TOSHIBA, VNDR_MITSUBISHI, VNDR_LG, VNDR_FUJITSU, VNDR_MIDEA };
|
|
|
|
const char kIrHvacVendors[] PROGMEM =
|
|
|
|
"Toshiba|Mitsubishi|LG|Fujitsu|Midea" ;
|
2018-11-18 09:35:53 +00:00
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
IRMitsubishiAC *mitsubir = nullptr;
|
2017-10-08 15:51:05 +01:00
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
const char kFanSpeedOptions[] = "A12345S";
|
|
|
|
const char kHvacModeOptions[] = "HDCA";
|
2019-02-03 17:45:20 +00:00
|
|
|
#endif // USE_IR_HVAC
|
2017-02-14 13:27:08 +00:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* IR Send
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2017-11-19 17:02:03 +00:00
|
|
|
#include <IRsend.h>
|
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
IRsend *irsend = nullptr;
|
2019-02-03 17:45:20 +00:00
|
|
|
bool irsend_active = false;
|
2017-02-14 13:27:08 +00:00
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
void IrSendInit(void)
|
2017-02-14 13:27:08 +00:00
|
|
|
{
|
2017-10-08 15:51:05 +01:00
|
|
|
irsend = new IRsend(pin[GPIO_IRSEND]); // an IR led is at GPIO_IRSEND
|
2017-02-14 13:27:08 +00:00
|
|
|
irsend->begin();
|
2017-03-29 17:42:05 +01:00
|
|
|
|
|
|
|
#ifdef USE_IR_HVAC
|
|
|
|
mitsubir = new IRMitsubishiAC(pin[GPIO_IRSEND]);
|
|
|
|
#endif //USE_IR_HVAC
|
2017-02-14 13:27:08 +00:00
|
|
|
}
|
|
|
|
|
2019-04-01 15:39:13 +01:00
|
|
|
char* IrUint64toHex(uint64_t value, char *str, uint16_t bits)
|
|
|
|
{
|
|
|
|
ulltoa(value, str, 16); // Get 64bit value
|
|
|
|
|
|
|
|
int fill = 8;
|
|
|
|
if ((bits > 3) && (bits < 65)) {
|
|
|
|
fill = bits / 4; // Max 16
|
|
|
|
if (bits % 4) { fill++; }
|
|
|
|
}
|
|
|
|
int len = strlen(str);
|
|
|
|
fill -= len;
|
|
|
|
if (fill > 0) {
|
|
|
|
memmove(str + fill, str, len +1);
|
|
|
|
memset(str, '0', fill);
|
|
|
|
}
|
|
|
|
memmove(str + 2, str, strlen(str) +1);
|
|
|
|
str[0] = '0';
|
|
|
|
str[1] = 'x';
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2017-10-06 16:28:00 +01:00
|
|
|
#ifdef USE_IR_RECEIVE
|
2017-10-08 15:51:05 +01:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* IR Receive
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-03-31 10:59:04 +01:00
|
|
|
const bool IR_RCV_SAVE_BUFFER = false; // false = do not use buffer, true = use buffer for decoding
|
|
|
|
const uint32_t IR_TIME_AVOID_DUPLICATE = 500; // Milliseconds
|
2017-10-06 16:28:00 +01:00
|
|
|
|
2018-11-21 15:36:10 +00:00
|
|
|
#include <IRrecv.h>
|
2017-10-25 13:27:30 +01:00
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
IRrecv *irrecv = nullptr;
|
2018-11-21 15:36:10 +00:00
|
|
|
|
2017-10-06 16:28:00 +01:00
|
|
|
unsigned long ir_lasttime = 0;
|
|
|
|
|
2019-05-27 10:56:14 +01:00
|
|
|
void IrReceiveUpdateThreshold()
|
|
|
|
{
|
2019-07-08 11:24:31 +01:00
|
|
|
if (irrecv != nullptr) {
|
|
|
|
if (Settings.param[P_IR_UNKNOW_THRESHOLD] < 6) { Settings.param[P_IR_UNKNOW_THRESHOLD] = 6; }
|
|
|
|
irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]);
|
|
|
|
}
|
2019-05-27 10:56:14 +01:00
|
|
|
}
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
void IrReceiveInit(void)
|
2017-10-06 16:28:00 +01:00
|
|
|
{
|
2018-11-21 15:36:10 +00:00
|
|
|
// an IR led is at GPIO_IRRECV
|
|
|
|
irrecv = new IRrecv(pin[GPIO_IRRECV], IR_RCV_BUFFER_SIZE, IR_RCV_TIMEOUT, IR_RCV_SAVE_BUFFER);
|
2019-05-27 10:56:14 +01:00
|
|
|
irrecv->setUnknownThreshold(Settings.param[P_IR_UNKNOW_THRESHOLD]);
|
2017-10-08 15:51:05 +01:00
|
|
|
irrecv->enableIRIn(); // Start the receiver
|
|
|
|
|
2017-10-18 17:22:34 +01:00
|
|
|
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("IrReceive initialized"));
|
2017-10-06 16:28:00 +01:00
|
|
|
}
|
|
|
|
|
2018-11-14 13:32:09 +00:00
|
|
|
void IrReceiveCheck(void)
|
2017-10-08 15:51:05 +01:00
|
|
|
{
|
2017-10-29 17:18:46 +00:00
|
|
|
char sirtype[14]; // Max is AIWA_RC_T501
|
2017-10-08 15:51:05 +01:00
|
|
|
int8_t iridx = 0;
|
2017-02-14 13:27:08 +00:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
decode_results results;
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
if (irrecv->decode(&results)) {
|
2019-04-01 14:15:16 +01:00
|
|
|
char hvalue[64];
|
|
|
|
IrUint64toHex(results.value, hvalue, results.bits); // Get 64bit value as hex 0x00123456
|
2017-02-17 16:18:41 +00:00
|
|
|
|
2019-04-01 14:15:16 +01:00
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_IRR "Echo %d, RawLen %d, Overflow %d, Bits %d, Value %s, Decode %d"),
|
|
|
|
irsend_active, results.rawlen, results.overflow, results.bits, hvalue, results.decode_type);
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
unsigned long now = millis();
|
2018-11-21 15:36:10 +00:00
|
|
|
// if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) {
|
2019-02-03 17:45:20 +00:00
|
|
|
if (!irsend_active && (now - ir_lasttime > IR_TIME_AVOID_DUPLICATE)) {
|
2017-10-08 15:51:05 +01:00
|
|
|
ir_lasttime = now;
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
iridx = results.decode_type;
|
2019-04-01 14:15:16 +01:00
|
|
|
if ((iridx < 0) || (iridx > 14)) { iridx = 0; } // UNKNOWN
|
|
|
|
char svalue[64];
|
2018-06-25 11:33:23 +01:00
|
|
|
if (Settings.flag.ir_receive_decimal) {
|
2019-04-01 14:15:16 +01:00
|
|
|
ulltoa(results.value, svalue, 10);
|
2018-06-25 11:33:23 +01:00
|
|
|
} else {
|
2019-04-01 14:15:16 +01:00
|
|
|
snprintf_P(svalue, sizeof(svalue), PSTR("\"%s\""), hvalue);
|
2018-06-25 11:33:23 +01:00
|
|
|
}
|
2019-03-23 16:00:59 +00:00
|
|
|
Response_P(PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s"),
|
2019-04-01 14:15:16 +01:00
|
|
|
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, svalue);
|
2018-06-25 11:33:23 +01:00
|
|
|
|
2018-11-21 15:36:10 +00:00
|
|
|
if (Settings.flag3.receive_raw) {
|
2019-03-23 16:00:59 +00:00
|
|
|
ResponseAppend_P(PSTR(",\"" D_JSON_IR_RAWDATA "\":["));
|
2018-11-21 15:36:10 +00:00
|
|
|
uint16_t i;
|
|
|
|
for (i = 1; i < results.rawlen; i++) {
|
2019-03-23 16:00:59 +00:00
|
|
|
if (i > 1) { ResponseAppend_P(PSTR(",")); }
|
2018-11-21 15:36:10 +00:00
|
|
|
uint32_t usecs;
|
|
|
|
for (usecs = results.rawbuf[i] * kRawTick; usecs > UINT16_MAX; usecs -= UINT16_MAX) {
|
2019-03-23 16:00:59 +00:00
|
|
|
ResponseAppend_P(PSTR("%d,0,"), UINT16_MAX);
|
2018-11-21 15:36:10 +00:00
|
|
|
}
|
2019-03-23 16:00:59 +00:00
|
|
|
ResponseAppend_P(PSTR("%d"), usecs);
|
2018-11-21 15:36:10 +00:00
|
|
|
if (strlen(mqtt_data) > sizeof(mqtt_data) - 40) { break; } // Quit if char string becomes too long
|
|
|
|
}
|
|
|
|
uint16_t extended_length = results.rawlen - 1;
|
2019-06-30 15:44:36 +01:00
|
|
|
for (uint32_t j = 0; j < results.rawlen - 1; j++) {
|
2018-11-21 15:36:10 +00:00
|
|
|
uint32_t usecs = results.rawbuf[j] * kRawTick;
|
|
|
|
// Add two extra entries for multiple larger than UINT16_MAX it is.
|
|
|
|
extended_length += (usecs / (UINT16_MAX + 1)) * 2;
|
|
|
|
}
|
2019-03-23 16:00:59 +00:00
|
|
|
ResponseAppend_P(PSTR("],\"" D_JSON_IR_RAWDATA "Info\":[%d,%d,%d]"), extended_length, i -1, results.overflow);
|
2018-11-21 15:36:10 +00:00
|
|
|
}
|
|
|
|
|
2019-03-23 16:00:59 +00:00
|
|
|
ResponseAppend_P(PSTR("}}"));
|
2018-01-18 15:19:28 +00:00
|
|
|
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED));
|
2018-11-21 15:36:10 +00:00
|
|
|
|
|
|
|
if (iridx) {
|
|
|
|
XdrvRulesProcess();
|
2017-10-08 15:51:05 +01:00
|
|
|
#ifdef USE_DOMOTICZ
|
2018-11-21 15:36:10 +00:00
|
|
|
unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28]
|
|
|
|
DomoticzSensor(DZ_COUNT, value); // Send data as Domoticz Counter value
|
|
|
|
#endif // USE_DOMOTICZ
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
|
|
|
|
irrecv->resume();
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
2017-02-14 13:27:08 +00:00
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
#endif // USE_IR_RECEIVE
|
2017-03-29 17:42:05 +01:00
|
|
|
|
|
|
|
#ifdef USE_IR_HVAC
|
2018-11-19 18:39:44 +00:00
|
|
|
/********************************************************************************************* \
|
2017-10-08 15:51:05 +01:00
|
|
|
* IR Heating, Ventilation and Air Conditioning using IRMitsubishiAC library
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-07-21 15:03:20 +01:00
|
|
|
#ifdef USE_IR_HVAC_TOSHIBA
|
2018-11-20 13:10:32 +00:00
|
|
|
/*******************
|
2018-11-18 09:35:53 +00:00
|
|
|
TOSHIBA
|
|
|
|
********************/
|
|
|
|
|
2019-07-21 17:06:13 +01:00
|
|
|
const uint16_t HVAC_TOSHIBA_HDR_MARK = 4400;
|
|
|
|
const uint16_t HVAC_TOSHIBA_HDR_SPACE = 4300;
|
|
|
|
const uint16_t HVAC_TOSHIBA_BIT_MARK = 543;
|
|
|
|
const uint16_t HVAC_TOSHIBA_ONE_SPACE = 1623;
|
|
|
|
const uint16_t HVAC_MISTUBISHI_ZERO_SPACE = 472;
|
|
|
|
const uint16_t HVAC_TOSHIBA_RPT_MARK = 440;
|
|
|
|
const uint16_t HVAC_TOSHIBA_RPT_SPACE = 7048; // Above original iremote limit
|
|
|
|
const uint8_t HVAC_TOSHIBA_DATALEN = 9;
|
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
uint8_t IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
|
2017-03-29 17:42:05 +01:00
|
|
|
{
|
2017-11-19 17:02:03 +00:00
|
|
|
uint16_t rawdata[2 + 2 * 8 * HVAC_TOSHIBA_DATALEN + 2];
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t data[HVAC_TOSHIBA_DATALEN] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00};
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
char *p;
|
2017-04-03 15:38:15 +01:00
|
|
|
uint8_t mode;
|
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
if (HVAC_Mode == nullptr) {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = (char *)kHvacModeOptions; // default HVAC_HOT
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0]));
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-10-18 17:22:34 +01:00
|
|
|
data[6] = (p - kHvacModeOptions) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!HVAC_Power) {
|
2019-01-28 13:08:33 +00:00
|
|
|
data[6] = (uint8_t)0x07; // Turn OFF HVAC
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
if (HVAC_FanMode == nullptr) {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-10-18 17:22:34 +01:00
|
|
|
mode = p - kFanSpeedOptions + 1;
|
2017-04-25 17:24:42 +01:00
|
|
|
if ((1 == mode) || (7 == mode)) {
|
|
|
|
mode = 0;
|
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
mode = mode << 5; // AUTO = 0x00, SPEED = 0x40, 0x60, 0x80, 0xA0, 0xC0, SILENT = 0x00
|
2017-04-03 15:38:15 +01:00
|
|
|
data[6] = data[6] | mode;
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t Temp;
|
2017-03-29 17:42:05 +01:00
|
|
|
if (HVAC_Temp > 30) {
|
|
|
|
Temp = 30;
|
|
|
|
}
|
|
|
|
else if (HVAC_Temp < 17) {
|
|
|
|
Temp = 17;
|
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
else {
|
|
|
|
Temp = HVAC_Temp;
|
|
|
|
}
|
2019-01-28 13:08:33 +00:00
|
|
|
data[5] = (uint8_t)(Temp - 17) << 4;
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
data[HVAC_TOSHIBA_DATALEN - 1] = 0;
|
2019-06-30 15:44:36 +01:00
|
|
|
for (uint32_t x = 0; x < HVAC_TOSHIBA_DATALEN - 1; x++) {
|
2019-01-28 13:08:33 +00:00
|
|
|
data[HVAC_TOSHIBA_DATALEN - 1] = (uint8_t)data[x] ^ data[HVAC_TOSHIBA_DATALEN - 1]; // CRC is a simple bits addition
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int i = 0;
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t mask = 1;
|
2017-03-29 17:42:05 +01:00
|
|
|
|
|
|
|
//header
|
|
|
|
rawdata[i++] = HVAC_TOSHIBA_HDR_MARK;
|
|
|
|
rawdata[i++] = HVAC_TOSHIBA_HDR_SPACE;
|
|
|
|
|
|
|
|
//data
|
2019-06-30 15:44:36 +01:00
|
|
|
for (uint32_t b = 0; b < HVAC_TOSHIBA_DATALEN; b++) {
|
2017-03-29 17:42:05 +01:00
|
|
|
for (mask = B10000000; mask > 0; mask >>= 1) { //iterate through bit mask
|
|
|
|
if (data[b] & mask) { // Bit ONE
|
|
|
|
rawdata[i++] = HVAC_TOSHIBA_BIT_MARK;
|
|
|
|
rawdata[i++] = HVAC_TOSHIBA_ONE_SPACE;
|
|
|
|
}
|
|
|
|
else { // Bit ZERO
|
|
|
|
rawdata[i++] = HVAC_TOSHIBA_BIT_MARK;
|
|
|
|
rawdata[i++] = HVAC_MISTUBISHI_ZERO_SPACE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//trailer
|
|
|
|
rawdata[i++] = HVAC_TOSHIBA_RPT_MARK;
|
|
|
|
rawdata[i++] = HVAC_TOSHIBA_RPT_SPACE;
|
|
|
|
|
2019-02-03 17:45:20 +00:00
|
|
|
// noInterrupts();
|
|
|
|
irsend_active = true;
|
2017-10-08 15:51:05 +01:00
|
|
|
irsend->sendRaw(rawdata, i, 38);
|
|
|
|
irsend->sendRaw(rawdata, i, 38);
|
2019-02-03 17:45:20 +00:00
|
|
|
// interrupts();
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_NO_ERROR;
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif // USE_IR_HVAC_TOSHIBA
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2019-07-21 17:06:13 +01:00
|
|
|
#ifdef USE_IR_HVAC_MIDEA
|
|
|
|
/*******************
|
|
|
|
MIDEA / KOMECO
|
|
|
|
********************/
|
|
|
|
|
|
|
|
// http://veillard.com/embedded/midea.html
|
|
|
|
// https://github.com/sheinz/esp-midea-ir/blob/master/midea-ir.c
|
|
|
|
|
|
|
|
const uint16_t HVAC_MIDEA_HDR_MARK = 4420; // 8T high
|
|
|
|
const uint16_t HVAC_MIDEA_HDR_SPACE = 4420; // 8T low
|
|
|
|
const uint16_t HVAC_MIDEA_BIT_MARK = 553; // 1T
|
|
|
|
const uint16_t HVAC_MIDEA_ONE_SPACE = 1660; // 3T low
|
|
|
|
const uint16_t HVAC_MIDEA_ZERO_SPACE = 553; // 1T high
|
|
|
|
const uint16_t HVAC_MIDEA_RPT_MARK = 553; // 1T
|
|
|
|
const uint16_t HVAC_MIDEA_RPT_SPACE = 5530; // 10T
|
|
|
|
const uint8_t HVAC_MIDEA_DATALEN = 3;
|
|
|
|
|
|
|
|
uint8_t IrHvacMidea(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
|
|
|
|
{
|
|
|
|
uint16_t rawdata[2 + 2 * 2 * 8 * HVAC_MIDEA_DATALEN + 2]; // START + 2* (2 * 3 BYTES) + STOP
|
|
|
|
uint8_t data[HVAC_MIDEA_DATALEN] = {0xB2, 0x00, 0x00};
|
|
|
|
|
|
|
|
char *p;
|
|
|
|
uint8_t mode;
|
|
|
|
|
|
|
|
if (!HVAC_Power) { // Turn OFF HVAC
|
|
|
|
data[1] = 0x7B;
|
|
|
|
data[2] = 0xE0;
|
|
|
|
} else {
|
|
|
|
// FAN
|
|
|
|
if (HVAC_FanMode == nullptr) {
|
|
|
|
p = (char*)kFanSpeedOptions; // default auto
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p = (char*)HVAC_FanMode;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch(p[0]) {
|
|
|
|
case '1': data[1] = 0xBF; break; // off
|
|
|
|
case '2': data[1] = 0x9F; break; // low
|
|
|
|
case '3': data[1] = 0x5F; break; // med
|
|
|
|
case '4': data[1] = 0x3F; break; // high
|
|
|
|
case '5': data[1] = 0x1F; break; // auto
|
|
|
|
case 'A': data[1] = 0x1F; break; // auto
|
|
|
|
default: return IE_SYNTAX_IRHVAC;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TEMPERATURE
|
|
|
|
uint8_t Temp;
|
|
|
|
if (HVAC_Temp > 30) {
|
|
|
|
Temp = 30;
|
|
|
|
}
|
|
|
|
else if (HVAC_Temp < 17) {
|
|
|
|
Temp = 17;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Temp = HVAC_Temp-17;
|
|
|
|
}
|
|
|
|
if (10 == Temp) { // Temp is encoded as gray code; except 27 and 28. Go figure...
|
|
|
|
data[2] = 0x90;
|
|
|
|
} else if (11 == Temp) {
|
|
|
|
data[2] = 0x80;
|
|
|
|
} else {
|
|
|
|
Temp = (Temp >> 1) ^Temp;
|
|
|
|
data[2] = (Temp << 4);
|
|
|
|
}
|
|
|
|
|
|
|
|
// MODE
|
|
|
|
if (HVAC_Mode == nullptr) {
|
|
|
|
p = (char*)kHvacModeOptions + 3; // default to auto
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p = (char*)HVAC_Mode;
|
|
|
|
}
|
|
|
|
switch(toupper(p[0])) {
|
|
|
|
case 'D': data[2] = 0xE4; break; // for fan Temp must be 0XE
|
|
|
|
case 'C': data[2] = 0x0 | data[2]; break;
|
|
|
|
case 'A': data[2] = 0x8 | data[2]; data[1] = 0x1F; break; // for auto Fan must be 0x1
|
|
|
|
case 'H': data[2] = 0xC | data[2]; break;
|
|
|
|
default: return IE_SYNTAX_IRHVAC;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
uint8_t mask = 1;
|
|
|
|
|
|
|
|
//header
|
|
|
|
rawdata[i++] = HVAC_MIDEA_HDR_MARK;
|
|
|
|
rawdata[i++] = HVAC_MIDEA_HDR_SPACE;
|
|
|
|
|
|
|
|
//data
|
|
|
|
for (int b = 0; b < HVAC_MIDEA_DATALEN; b++) { // Send value
|
|
|
|
for (mask = B10000000; mask > 0; mask >>= 1) {
|
|
|
|
if (data[b] & mask) { // Bit ONE
|
|
|
|
rawdata[i++] = HVAC_MIDEA_BIT_MARK;
|
|
|
|
rawdata[i++] = HVAC_MIDEA_ONE_SPACE;
|
|
|
|
}
|
|
|
|
else { // Bit ZERO
|
|
|
|
rawdata[i++] = HVAC_MIDEA_BIT_MARK;
|
|
|
|
rawdata[i++] = HVAC_MIDEA_ZERO_SPACE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (mask = B10000000; mask > 0; mask >>= 1) { // Send complement
|
|
|
|
if (data[b] & mask) { // Bit ONE
|
|
|
|
rawdata[i++] = HVAC_MIDEA_BIT_MARK;
|
|
|
|
rawdata[i++] = HVAC_MIDEA_ZERO_SPACE;
|
|
|
|
}
|
|
|
|
else { // Bit ZERO
|
|
|
|
rawdata[i++] = HVAC_MIDEA_BIT_MARK;
|
|
|
|
rawdata[i++] = HVAC_MIDEA_ONE_SPACE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//trailer
|
|
|
|
rawdata[i++] = HVAC_MIDEA_RPT_MARK;
|
|
|
|
rawdata[i++] = HVAC_MIDEA_RPT_SPACE;
|
|
|
|
|
|
|
|
// noInterrupts();
|
|
|
|
// this takes ~180 ms :
|
|
|
|
irsend->sendRaw(rawdata, i, 38);
|
|
|
|
irsend->sendRaw(rawdata, i, 38);
|
|
|
|
// interrupts();
|
|
|
|
|
|
|
|
return IE_NO_ERROR;
|
|
|
|
}
|
|
|
|
#endif // USE_IR_HVAC_MIDEA
|
|
|
|
|
2019-07-21 15:03:20 +01:00
|
|
|
#ifdef USE_IR_HVAC_MITSUBISHI
|
2018-11-20 13:10:32 +00:00
|
|
|
/*******************
|
2018-11-18 09:35:53 +00:00
|
|
|
MITSUBISHI
|
|
|
|
********************/
|
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
uint8_t IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
|
2017-03-29 17:42:05 +01:00
|
|
|
{
|
2017-04-25 17:24:42 +01:00
|
|
|
char *p;
|
2017-04-03 15:38:15 +01:00
|
|
|
uint8_t mode;
|
2017-09-02 13:37:02 +01:00
|
|
|
|
2017-03-29 17:42:05 +01:00
|
|
|
mitsubir->stateReset();
|
2017-04-03 15:38:15 +01:00
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
if (HVAC_Mode == nullptr) {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = (char *)kHvacModeOptions; // default HVAC_HOT
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0]));
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-10-18 17:22:34 +01:00
|
|
|
mode = (p - kHvacModeOptions + 1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20
|
2017-04-03 15:38:15 +01:00
|
|
|
mitsubir->setMode(mode);
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2017-08-16 16:05:36 +01:00
|
|
|
mitsubir->setPower(HVAC_Power);
|
2017-03-29 17:42:05 +01:00
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
if (HVAC_FanMode == nullptr) {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
else {
|
2017-10-18 17:22:34 +01:00
|
|
|
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
2017-04-25 17:24:42 +01:00
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2017-04-25 17:24:42 +01:00
|
|
|
}
|
2017-10-18 17:22:34 +01:00
|
|
|
mode = p - kFanSpeedOptions; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6
|
2017-04-03 15:38:15 +01:00
|
|
|
mitsubir->setFan(mode);
|
2017-03-29 17:42:05 +01:00
|
|
|
|
|
|
|
mitsubir->setTemp(HVAC_Temp);
|
|
|
|
mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO);
|
|
|
|
mitsubir->send();
|
2017-09-02 13:37:02 +01:00
|
|
|
|
2019-03-08 14:15:42 +00:00
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"),
|
2018-11-21 15:36:10 +00:00
|
|
|
// mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane());
|
2017-09-02 13:37:02 +01:00
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_NO_ERROR;
|
2017-03-29 17:42:05 +01:00
|
|
|
}
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif // USE_IR_HVAC_MITSUBISHI
|
2018-11-18 09:35:53 +00:00
|
|
|
|
2019-07-21 15:03:20 +01:00
|
|
|
#ifdef USE_IR_HVAC_LG
|
2018-11-20 13:10:32 +00:00
|
|
|
/*******************
|
2018-11-18 09:35:53 +00:00
|
|
|
LG
|
|
|
|
********************/
|
|
|
|
|
2019-07-21 17:06:13 +01:00
|
|
|
const uint8_t HVAC_LG_DATALEN = 7;
|
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
uint8_t IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
|
2018-11-18 09:35:53 +00:00
|
|
|
{
|
|
|
|
uint32_t LG_Code;
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t data[HVAC_LG_DATALEN];
|
|
|
|
static bool hvacOn = false;
|
2018-11-18 09:35:53 +00:00
|
|
|
char *p;
|
|
|
|
uint8_t mode;
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t Temp;
|
2018-11-18 09:35:53 +00:00
|
|
|
|
|
|
|
// Constant data
|
|
|
|
data[0] = 0x08;
|
|
|
|
data[1] = 0x08;
|
|
|
|
data[2] = 0x00;
|
|
|
|
|
|
|
|
if (!HVAC_Power) {
|
2019-01-28 13:08:33 +00:00
|
|
|
data[2] = (uint8_t)0x0C; // Turn OFF HVAC, code 0x88C0051
|
|
|
|
data[3] = (uint8_t)0x00;
|
|
|
|
data[4] = (uint8_t)0x00;
|
|
|
|
data[5] = (uint8_t)0x05;
|
|
|
|
data[6] = (uint8_t)0x01;
|
2018-11-18 09:35:53 +00:00
|
|
|
hvacOn = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
else {
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2018-11-18 09:35:53 +00:00
|
|
|
// Set code for HVAC Mode - data[3]
|
2019-03-26 17:26:50 +00:00
|
|
|
if (HVAC_Mode == nullptr) {
|
2018-11-18 09:35:53 +00:00
|
|
|
p = (char *)kHvacModeOptions; // default HVAC_HOT
|
|
|
|
}
|
|
|
|
else {
|
2018-11-20 13:10:32 +00:00
|
|
|
p = strchr(kHvacModeOptions, toupper(HVAC_Mode[0]));
|
2018-11-18 09:35:53 +00:00
|
|
|
}
|
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2018-11-18 09:35:53 +00:00
|
|
|
}
|
|
|
|
mode = (p - kHvacModeOptions) ^ 0x03; // HOT = 0x03, DRY = 0x02, COOL = 0x01, AUTO = 0x00
|
|
|
|
switch (mode) {
|
|
|
|
case 0: // AUTO
|
|
|
|
data[3] = 11;
|
|
|
|
break;
|
|
|
|
case 1: // COOL
|
|
|
|
data[3] = 8;
|
|
|
|
break;
|
|
|
|
case 2: // DRY
|
|
|
|
data[3] = 9;
|
|
|
|
break;
|
|
|
|
case 3: // HOT
|
|
|
|
data[3] = 12;
|
2018-11-20 13:10:32 +00:00
|
|
|
break;
|
2018-11-18 09:35:53 +00:00
|
|
|
}
|
|
|
|
if (!hvacOn) {
|
|
|
|
data[3] = data[3] & 7; // reset bit3
|
|
|
|
hvacOn = true;
|
|
|
|
}
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2019-03-08 14:15:42 +00:00
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: HvacMode %s, ModeVal %d, Code %d"), p, mode, data[3]);
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2018-11-18 09:35:53 +00:00
|
|
|
// Set code for HVAC temperature - data[4]
|
|
|
|
if (HVAC_Temp > 30) {
|
|
|
|
Temp = 30;
|
|
|
|
}
|
|
|
|
else if (HVAC_Temp < 18) {
|
|
|
|
Temp = 18;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Temp = HVAC_Temp;
|
|
|
|
}
|
2019-01-28 13:08:33 +00:00
|
|
|
data[4] = (uint8_t)(Temp - 15);
|
2018-11-18 09:35:53 +00:00
|
|
|
|
|
|
|
// Set code for HVAC fan mode - data[5]
|
2019-03-26 17:26:50 +00:00
|
|
|
if (HVAC_FanMode == nullptr) {
|
2018-11-18 09:35:53 +00:00
|
|
|
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
|
|
|
|
}
|
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2018-11-18 09:35:53 +00:00
|
|
|
}
|
|
|
|
mode = p - kFanSpeedOptions;
|
|
|
|
if ((mode == 0) || (mode > 3)) {
|
|
|
|
data[5] = 5; // Auto = 0x05
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
data[5] = (mode * 2) - 2; // Low = 0x00, Mid = 0x02, High = 0x04
|
|
|
|
}
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2019-03-08 14:15:42 +00:00
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: FanMode %s, ModeVal %d, Code %d"), p, mode, data[5]);
|
2018-11-18 09:35:53 +00:00
|
|
|
|
|
|
|
// Set CRC code - data[6]
|
|
|
|
data[6] = (data[3] + data[4] + data[5]) & 0x0f; // CRC
|
|
|
|
|
2018-11-20 13:10:32 +00:00
|
|
|
}
|
2018-11-18 09:35:53 +00:00
|
|
|
// Build LG IR code
|
|
|
|
LG_Code = data[0] << 4;
|
2019-06-30 15:44:36 +01:00
|
|
|
for (uint32_t i = 1; i < 6; i++) {
|
2018-11-18 09:35:53 +00:00
|
|
|
LG_Code = (LG_Code + data[i]) << 4;
|
|
|
|
}
|
|
|
|
LG_Code = LG_Code + data[6];
|
|
|
|
|
2019-03-08 14:15:42 +00:00
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: LG_Code %d"), LG_Code);
|
2018-11-18 09:35:53 +00:00
|
|
|
|
2018-11-20 13:10:32 +00:00
|
|
|
// Send LG IR Code
|
2019-02-03 17:45:20 +00:00
|
|
|
// noInterrupts();
|
|
|
|
irsend_active = true;
|
2018-11-18 09:35:53 +00:00
|
|
|
irsend->sendLG(LG_Code, 28);
|
2019-02-03 17:45:20 +00:00
|
|
|
// interrupts();
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_NO_ERROR;
|
2018-11-18 09:35:53 +00:00
|
|
|
}
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif // USE_IR_HVAC_LG
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2019-07-21 15:03:20 +01:00
|
|
|
#ifdef USE_IR_HVAC_FUJITSU
|
2018-11-20 13:10:32 +00:00
|
|
|
/*******************
|
|
|
|
Fujitsu
|
|
|
|
********************/
|
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
uint8_t IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
|
2018-11-20 13:10:32 +00:00
|
|
|
{
|
|
|
|
const char kFujitsuHvacModeOptions[] = "HDCAF";
|
|
|
|
|
2019-03-08 14:15:42 +00:00
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("FUJITSU: mode:%s, fan:%s, power:%u, temp:%u"), HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
|
2018-11-20 13:10:32 +00:00
|
|
|
|
|
|
|
IRFujitsuAC ac(pin[GPIO_IRSEND]);
|
|
|
|
|
2019-02-03 17:45:20 +00:00
|
|
|
irsend_active = true;
|
|
|
|
|
2018-11-20 13:10:32 +00:00
|
|
|
if (0 == HVAC_Power) {
|
|
|
|
ac.off();
|
|
|
|
ac.send();
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_NO_ERROR;
|
2018-11-20 13:10:32 +00:00
|
|
|
}
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
uint8_t modes[5] = {FUJITSU_AC_MODE_HEAT, FUJITSU_AC_MODE_DRY, FUJITSU_AC_MODE_COOL, FUJITSU_AC_MODE_AUTO, FUJITSU_AC_MODE_FAN};
|
|
|
|
uint8_t fanModes[7] = {FUJITSU_AC_FAN_AUTO, FUJITSU_AC_FAN_LOW, FUJITSU_AC_FAN_MED, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_HIGH, FUJITSU_AC_FAN_QUIET};
|
2018-11-20 13:10:32 +00:00
|
|
|
ac.setCmd(FUJITSU_AC_CMD_TURN_ON);
|
|
|
|
ac.setSwing(FUJITSU_AC_SWING_VERT);
|
|
|
|
|
|
|
|
char *p;
|
2019-03-26 17:26:50 +00:00
|
|
|
if (nullptr == HVAC_Mode) {
|
2018-11-20 13:10:32 +00:00
|
|
|
p = (char *)kFujitsuHvacModeOptions;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p = strchr(kFujitsuHvacModeOptions, toupper(HVAC_Mode[0]));
|
|
|
|
}
|
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2018-11-20 13:10:32 +00:00
|
|
|
}
|
|
|
|
ac.setMode(modes[p - kFujitsuHvacModeOptions]);
|
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
if (HVAC_FanMode == nullptr) {
|
2018-11-20 13:10:32 +00:00
|
|
|
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
p = strchr(kFanSpeedOptions, toupper(HVAC_FanMode[0]));
|
|
|
|
}
|
|
|
|
if (!p) {
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_SYNTAX_IRHVAC;
|
2018-11-20 13:10:32 +00:00
|
|
|
}
|
|
|
|
ac.setFanSpeed(fanModes[p - kFanSpeedOptions]);
|
|
|
|
|
|
|
|
ac.setTemp(HVAC_Temp);
|
|
|
|
ac.send();
|
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
return IE_NO_ERROR;
|
2018-11-20 13:10:32 +00:00
|
|
|
}
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif // USE_IR_HVAC_FUJITSU
|
2018-11-20 13:10:32 +00:00
|
|
|
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif // USE_IR_HVAC
|
2017-10-06 16:28:00 +01:00
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
/*********************************************************************************************\
|
|
|
|
* Commands
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
|
|
|
|
IRsend:
|
2019-04-11 10:38:07 +01:00
|
|
|
{ "protocol": "RC5", "bits": 12, "data":"0xC86" }
|
2017-10-08 15:51:05 +01:00
|
|
|
{ "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
|
|
|
IRhvac:
|
|
|
|
{ "Vendor": "<Toshiba|Mitsubishi>", "Power": <0|1>, "Mode": "<Hot|Cold|Dry|Auto>", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> }
|
|
|
|
*/
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
bool IrSendCommand(void)
|
2017-10-06 16:28:00 +01:00
|
|
|
{
|
2018-11-22 16:58:07 +00:00
|
|
|
char command [CMDSZ];
|
2019-01-28 13:08:33 +00:00
|
|
|
bool serviced = true;
|
2019-03-31 12:06:42 +01:00
|
|
|
uint8_t error = IE_NO_ERROR;
|
2018-11-22 16:58:07 +00:00
|
|
|
|
|
|
|
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kIrRemoteCommands);
|
|
|
|
if (-1 == command_code) {
|
|
|
|
serviced = false; // Unknown command
|
|
|
|
}
|
|
|
|
else if (CMND_IRSEND == command_code) {
|
2018-01-05 11:26:19 +00:00
|
|
|
if (XdrvMailbox.data_len) {
|
2019-03-23 16:00:59 +00:00
|
|
|
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
|
2018-11-21 15:36:10 +00:00
|
|
|
|
2019-03-26 17:26:50 +00:00
|
|
|
if (strstr(XdrvMailbox.data, "{") == nullptr) { // If no JSON it must be rawdata
|
2019-04-11 10:38:07 +01:00
|
|
|
// IRsend <freq>,<rawdata>,<rawdata> ...
|
2019-04-10 17:28:46 +01:00
|
|
|
// or
|
2019-04-11 10:38:07 +01:00
|
|
|
// IRsend raw,<freq>,<zero space>,<bit stream> (one space = zero space *2)
|
|
|
|
// IRsend raw,<freq>,<zero space>,<zero space multiplier becoming one space>,<bit stream>
|
2019-04-10 17:28:46 +01:00
|
|
|
// IRsend raw,<freq>,<zero space>,<one space>,<bit stream>
|
2019-04-11 10:38:07 +01:00
|
|
|
// IRsend raw,<freq>,<header mark>,<header space>,<bit mark>,<zero space>,<one space>,<bit stream>
|
2018-11-21 15:36:10 +00:00
|
|
|
char *p;
|
|
|
|
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
2019-03-31 12:06:42 +01:00
|
|
|
if (p == nullptr) {
|
|
|
|
error = IE_INVALID_RAWDATA;
|
|
|
|
} else {
|
|
|
|
uint16_t freq = atoi(str);
|
2019-04-10 17:28:46 +01:00
|
|
|
if (!freq && (*str != '0')) { // First parameter is any string
|
Alternative to IRSend RAW command.
It is not practical to send long streams of data using the existing IRSend RAW command as it is limited by the size of the mqtt buffer.
The format for this command is:
IRSend raw,<freq>,<hdr_mrk>,<hdr_spc>,<bit_mrk>,<zer_spc>,<one_spc>,<bit_str>
where,
<freq> = carrier freq (default 0, 38kHz)
<hdr_mrk> = header mark (ms)
<hdr_spc> = header space (ms)
<bit_mrk> = bit mark (ms)
<zer_spc> = zero space (ms)
<one_spc> = one space (ms)
<bit_str> = bit stream data (stream of ones and zeroes)
This command makes use of the output of the raw IR decoder from https://github.com/ToniA/Raw-IR-decoder-for-Arduino
USAGE:
Example rawirdecode output:
Number of symbols: 75
Symbols:
Hh010101101000111011001110000000001100110000000001100000000000000010001100
Bytes:
00: 0101|0110 | 6A | 01101010
01: 1000|1110 | 71 | 01110001
02: 1100|1110 | 73 | 01110011
03: 0000|0000 | 00 | 00000000
04: 1100|1100 | 33 | 00110011
05: 0000|0001 | 80 | 10000000
06: 1000|0000 | 01 | 00000001
07: 0000|0000 | 00 | 00000000
08: 1000|1100 | 31 | 00110001
6A,71,73,00,33,80,01,00,31
Timings (in us):
PAUSE SPACE: 0
HEADER MARK: 8620
HEADER SPACE: 4260
BIT MARK: 544
ZERO SPACE: 411
ONE SPACE: 1496
Decoding known protocols...
Unknown protocol
Bytecount: 9
Corresponding command:
IRSend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
2019-04-09 10:41:32 +01:00
|
|
|
uint16_t count = 0;
|
|
|
|
char *q = p;
|
|
|
|
for (; *q; count += (*q++ == ','));
|
2019-04-10 17:28:46 +01:00
|
|
|
if (count < 2) { // Parameters must be at least 3
|
Alternative to IRSend RAW command.
It is not practical to send long streams of data using the existing IRSend RAW command as it is limited by the size of the mqtt buffer.
The format for this command is:
IRSend raw,<freq>,<hdr_mrk>,<hdr_spc>,<bit_mrk>,<zer_spc>,<one_spc>,<bit_str>
where,
<freq> = carrier freq (default 0, 38kHz)
<hdr_mrk> = header mark (ms)
<hdr_spc> = header space (ms)
<bit_mrk> = bit mark (ms)
<zer_spc> = zero space (ms)
<one_spc> = one space (ms)
<bit_str> = bit stream data (stream of ones and zeroes)
This command makes use of the output of the raw IR decoder from https://github.com/ToniA/Raw-IR-decoder-for-Arduino
USAGE:
Example rawirdecode output:
Number of symbols: 75
Symbols:
Hh010101101000111011001110000000001100110000000001100000000000000010001100
Bytes:
00: 0101|0110 | 6A | 01101010
01: 1000|1110 | 71 | 01110001
02: 1100|1110 | 73 | 01110011
03: 0000|0000 | 00 | 00000000
04: 1100|1100 | 33 | 00110011
05: 0000|0001 | 80 | 10000000
06: 1000|0000 | 01 | 00000001
07: 0000|0000 | 00 | 00000000
08: 1000|1100 | 31 | 00110001
6A,71,73,00,33,80,01,00,31
Timings (in us):
PAUSE SPACE: 0
HEADER MARK: 8620
HEADER SPACE: 4260
BIT MARK: 544
ZERO SPACE: 411
ONE SPACE: 1496
Decoding known protocols...
Unknown protocol
Bytecount: 9
Corresponding command:
IRSend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
2019-04-09 10:41:32 +01:00
|
|
|
error = IE_INVALID_RAWDATA;
|
|
|
|
} else {
|
2019-04-10 17:28:46 +01:00
|
|
|
uint16_t parm[count];
|
2019-06-30 15:44:36 +01:00
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
2019-04-11 10:38:07 +01:00
|
|
|
parm[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0);
|
2019-04-09 14:41:01 +01:00
|
|
|
if (!parm[i]) {
|
|
|
|
if (!i) {
|
|
|
|
parm[0] = 38000; // Frequency default to 38kHz
|
|
|
|
} else {
|
2019-04-10 17:28:46 +01:00
|
|
|
error = IE_INVALID_RAWDATA; // Other parameters may not be 0
|
2019-04-09 14:41:01 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (IE_NO_ERROR == error) {
|
|
|
|
uint16_t i = 0;
|
2019-04-11 10:38:07 +01:00
|
|
|
if (count < 4) {
|
|
|
|
// IRsend raw,0,889,000000100110000001001
|
|
|
|
uint16_t mark = parm[1] *2; // Protocol where 0 = t, 1 = 2t (RC5)
|
|
|
|
if (3 == count) {
|
|
|
|
if (parm[2] < parm[1]) {
|
|
|
|
// IRsend raw,0,889,2,000000100110000001001
|
|
|
|
mark = parm[1] * parm[2]; // Protocol where 0 = t1, 1 = t1*t2 (Could be RC5)
|
|
|
|
} else {
|
|
|
|
// IRsend raw,0,889,1778,000000100110000001001
|
|
|
|
mark = parm[2]; // Protocol where 0 = t1, 1 = t2 (Could be RC5)
|
|
|
|
}
|
2019-04-09 14:41:01 +01:00
|
|
|
}
|
2019-04-11 10:38:07 +01:00
|
|
|
uint16_t raw_array[strlen(p)]; // Bits
|
2019-04-10 17:28:46 +01:00
|
|
|
for (; *p; *p++) {
|
|
|
|
if (*p == '0') {
|
|
|
|
raw_array[i++] = parm[1]; // Space
|
|
|
|
}
|
|
|
|
else if (*p == '1') {
|
|
|
|
raw_array[i++] = mark; // Mark
|
|
|
|
}
|
2019-04-09 14:41:01 +01:00
|
|
|
}
|
2019-04-11 10:38:07 +01:00
|
|
|
irsend_active = true;
|
|
|
|
irsend->sendRaw(raw_array, i, parm[0]);
|
2019-04-09 14:41:01 +01:00
|
|
|
}
|
2019-04-10 17:28:46 +01:00
|
|
|
else if (6 == count) { // NEC Protocol
|
2019-04-11 10:38:07 +01:00
|
|
|
// IRsend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
|
|
|
|
uint16_t raw_array[strlen(p)*2+3]; // Header + bits + end
|
2019-04-10 17:28:46 +01:00
|
|
|
raw_array[i++] = parm[1]; // Header mark
|
|
|
|
raw_array[i++] = parm[2]; // Header space
|
|
|
|
for (; *p; *p++) {
|
|
|
|
if (*p == '0') {
|
|
|
|
raw_array[i++] = parm[3]; // Bit mark
|
|
|
|
raw_array[i++] = parm[4]; // Zero space
|
|
|
|
}
|
|
|
|
else if (*p == '1') {
|
|
|
|
raw_array[i++] = parm[3]; // Bit mark
|
|
|
|
raw_array[i++] = parm[5]; // One space
|
|
|
|
}
|
|
|
|
}
|
|
|
|
raw_array[i++] = parm[3]; // Trailing mark
|
2019-04-11 10:38:07 +01:00
|
|
|
irsend_active = true;
|
|
|
|
irsend->sendRaw(raw_array, i, parm[0]);
|
2019-04-10 17:28:46 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
error = IE_INVALID_RAWDATA; // Invalid number of parameters
|
|
|
|
}
|
2019-04-09 14:41:01 +01:00
|
|
|
}
|
2019-03-31 12:06:42 +01:00
|
|
|
}
|
Alternative to IRSend RAW command.
It is not practical to send long streams of data using the existing IRSend RAW command as it is limited by the size of the mqtt buffer.
The format for this command is:
IRSend raw,<freq>,<hdr_mrk>,<hdr_spc>,<bit_mrk>,<zer_spc>,<one_spc>,<bit_str>
where,
<freq> = carrier freq (default 0, 38kHz)
<hdr_mrk> = header mark (ms)
<hdr_spc> = header space (ms)
<bit_mrk> = bit mark (ms)
<zer_spc> = zero space (ms)
<one_spc> = one space (ms)
<bit_str> = bit stream data (stream of ones and zeroes)
This command makes use of the output of the raw IR decoder from https://github.com/ToniA/Raw-IR-decoder-for-Arduino
USAGE:
Example rawirdecode output:
Number of symbols: 75
Symbols:
Hh010101101000111011001110000000001100110000000001100000000000000010001100
Bytes:
00: 0101|0110 | 6A | 01101010
01: 1000|1110 | 71 | 01110001
02: 1100|1110 | 73 | 01110011
03: 0000|0000 | 00 | 00000000
04: 1100|1100 | 33 | 00110011
05: 0000|0001 | 80 | 10000000
06: 1000|0000 | 01 | 00000001
07: 0000|0000 | 00 | 00000000
08: 1000|1100 | 31 | 00110001
6A,71,73,00,33,80,01,00,31
Timings (in us):
PAUSE SPACE: 0
HEADER MARK: 8620
HEADER SPACE: 4260
BIT MARK: 544
ZERO SPACE: 411
ONE SPACE: 1496
Decoding known protocols...
Unknown protocol
Bytecount: 9
Corresponding command:
IRSend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
2019-04-09 10:41:32 +01:00
|
|
|
} else {
|
|
|
|
if (!freq) { freq = 38000; } // Default to 38kHz
|
|
|
|
uint16_t count = 0;
|
|
|
|
char *q = p;
|
|
|
|
for (; *q; count += (*q++ == ','));
|
|
|
|
if (0 == count) {
|
|
|
|
error = IE_INVALID_RAWDATA;
|
|
|
|
} else { // At least two raw data values
|
2019-04-11 10:38:07 +01:00
|
|
|
// IRsend 0,896,876,900,888,894,876,1790,874,872,1810,1736,948,872,880,872,936,872,1792,900,888,1734
|
Alternative to IRSend RAW command.
It is not practical to send long streams of data using the existing IRSend RAW command as it is limited by the size of the mqtt buffer.
The format for this command is:
IRSend raw,<freq>,<hdr_mrk>,<hdr_spc>,<bit_mrk>,<zer_spc>,<one_spc>,<bit_str>
where,
<freq> = carrier freq (default 0, 38kHz)
<hdr_mrk> = header mark (ms)
<hdr_spc> = header space (ms)
<bit_mrk> = bit mark (ms)
<zer_spc> = zero space (ms)
<one_spc> = one space (ms)
<bit_str> = bit stream data (stream of ones and zeroes)
This command makes use of the output of the raw IR decoder from https://github.com/ToniA/Raw-IR-decoder-for-Arduino
USAGE:
Example rawirdecode output:
Number of symbols: 75
Symbols:
Hh010101101000111011001110000000001100110000000001100000000000000010001100
Bytes:
00: 0101|0110 | 6A | 01101010
01: 1000|1110 | 71 | 01110001
02: 1100|1110 | 73 | 01110011
03: 0000|0000 | 00 | 00000000
04: 1100|1100 | 33 | 00110011
05: 0000|0001 | 80 | 10000000
06: 1000|0000 | 01 | 00000001
07: 0000|0000 | 00 | 00000000
08: 1000|1100 | 31 | 00110001
6A,71,73,00,33,80,01,00,31
Timings (in us):
PAUSE SPACE: 0
HEADER MARK: 8620
HEADER SPACE: 4260
BIT MARK: 544
ZERO SPACE: 411
ONE SPACE: 1496
Decoding known protocols...
Unknown protocol
Bytecount: 9
Corresponding command:
IRSend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
2019-04-09 10:41:32 +01:00
|
|
|
count++;
|
2019-06-12 18:11:21 +01:00
|
|
|
if (count < 200) {
|
|
|
|
uint16_t raw_array[count]; // It's safe to use stack for up to 200 packets (limited by mqtt_data length)
|
2019-06-30 15:44:36 +01:00
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
2019-06-12 18:11:21 +01:00
|
|
|
raw_array[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0); // Allow decimal (20496) and hexadecimal (0x5010) input
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: stack count %d"), count);
|
|
|
|
|
|
|
|
irsend_active = true;
|
|
|
|
irsend->sendRaw(raw_array, count, freq);
|
|
|
|
} else {
|
|
|
|
uint16_t *raw_array = reinterpret_cast<uint16_t*>(malloc(count * sizeof(uint16_t)));
|
|
|
|
if (raw_array == nullptr) {
|
|
|
|
error = IE_INVALID_RAWDATA;
|
|
|
|
} else {
|
2019-06-30 15:44:36 +01:00
|
|
|
for (uint32_t i = 0; i < count; i++) {
|
2019-06-12 18:11:21 +01:00
|
|
|
raw_array[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0); // Allow decimal (20496) and hexadecimal (0x5010) input
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("DBG: heap count %d"), count);
|
|
|
|
|
|
|
|
irsend_active = true;
|
|
|
|
irsend->sendRaw(raw_array, count, freq);
|
|
|
|
free(raw_array);
|
|
|
|
}
|
Alternative to IRSend RAW command.
It is not practical to send long streams of data using the existing IRSend RAW command as it is limited by the size of the mqtt buffer.
The format for this command is:
IRSend raw,<freq>,<hdr_mrk>,<hdr_spc>,<bit_mrk>,<zer_spc>,<one_spc>,<bit_str>
where,
<freq> = carrier freq (default 0, 38kHz)
<hdr_mrk> = header mark (ms)
<hdr_spc> = header space (ms)
<bit_mrk> = bit mark (ms)
<zer_spc> = zero space (ms)
<one_spc> = one space (ms)
<bit_str> = bit stream data (stream of ones and zeroes)
This command makes use of the output of the raw IR decoder from https://github.com/ToniA/Raw-IR-decoder-for-Arduino
USAGE:
Example rawirdecode output:
Number of symbols: 75
Symbols:
Hh010101101000111011001110000000001100110000000001100000000000000010001100
Bytes:
00: 0101|0110 | 6A | 01101010
01: 1000|1110 | 71 | 01110001
02: 1100|1110 | 73 | 01110011
03: 0000|0000 | 00 | 00000000
04: 1100|1100 | 33 | 00110011
05: 0000|0001 | 80 | 10000000
06: 1000|0000 | 01 | 00000001
07: 0000|0000 | 00 | 00000000
08: 1000|1100 | 31 | 00110001
6A,71,73,00,33,80,01,00,31
Timings (in us):
PAUSE SPACE: 0
HEADER MARK: 8620
HEADER SPACE: 4260
BIT MARK: 544
ZERO SPACE: 411
ONE SPACE: 1496
Decoding known protocols...
Unknown protocol
Bytecount: 9
Corresponding command:
IRSend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
2019-04-09 10:41:32 +01:00
|
|
|
}
|
2019-03-31 12:06:42 +01:00
|
|
|
}
|
2018-11-21 15:36:10 +00:00
|
|
|
}
|
|
|
|
}
|
2019-03-31 12:06:42 +01:00
|
|
|
} else {
|
2018-11-22 16:58:07 +00:00
|
|
|
char dataBufUc[XdrvMailbox.data_len];
|
|
|
|
UpperCase(dataBufUc, XdrvMailbox.data);
|
2019-03-31 12:06:42 +01:00
|
|
|
RemoveSpace(dataBufUc);
|
|
|
|
if (strlen(dataBufUc) < 8) {
|
|
|
|
error = IE_INVALID_JSON;
|
|
|
|
} else {
|
2019-07-23 09:22:14 +01:00
|
|
|
StaticJsonBuffer<140> jsonBuf;
|
2019-03-31 12:06:42 +01:00
|
|
|
JsonObject &root = jsonBuf.parseObject(dataBufUc);
|
|
|
|
if (!root.success()) {
|
|
|
|
error = IE_INVALID_JSON;
|
|
|
|
} else {
|
|
|
|
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
2019-07-15 08:22:07 +01:00
|
|
|
// IRsend { "protocol": "NEC", "bits": 32, "data":"0x02FDFE80", "repeat": 2 }
|
2019-03-31 12:06:42 +01:00
|
|
|
char parm_uc[10];
|
|
|
|
const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))];
|
2019-04-01 14:15:16 +01:00
|
|
|
uint16_t bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))];
|
|
|
|
uint64_t data = strtoull(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], nullptr, 0);
|
2019-07-15 08:22:07 +01:00
|
|
|
uint16_t repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT))];
|
2019-03-31 12:06:42 +01:00
|
|
|
if (protocol && bits) {
|
|
|
|
char protocol_text[20];
|
|
|
|
int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols);
|
|
|
|
|
2019-04-01 14:15:16 +01:00
|
|
|
char dvalue[64];
|
|
|
|
char hvalue[64];
|
2019-07-15 08:22:07 +01:00
|
|
|
AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRS: protocol_text %s, protocol %s, bits %d, data %s (%s), repeat %d, protocol_code %d"),
|
|
|
|
protocol_text, protocol, bits, ulltoa(data, dvalue, 10), IrUint64toHex(data, hvalue, bits), repeat, protocol_code);
|
2019-03-31 12:06:42 +01:00
|
|
|
|
|
|
|
irsend_active = true;
|
2019-07-21 15:03:20 +01:00
|
|
|
switch (protocol_code) { // Equals IRremoteESP8266.h enum decode_type_t
|
|
|
|
#ifdef USE_IR_SEND_RC5
|
2019-03-31 12:06:42 +01:00
|
|
|
case RC5:
|
2019-07-15 08:22:07 +01:00
|
|
|
irsend->sendRC5(data, bits, repeat); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_RC6
|
2019-03-31 12:06:42 +01:00
|
|
|
case RC6:
|
2019-07-15 08:22:07 +01:00
|
|
|
irsend->sendRC6(data, bits, repeat); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_NEC
|
|
|
|
case NEC:
|
|
|
|
irsend->sendNEC(data, (bits > NEC_BITS) ? NEC_BITS : bits, repeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_SONY
|
|
|
|
case SONY:
|
|
|
|
irsend->sendSony(data, (bits > SONY_20_BITS) ? SONY_20_BITS : bits, repeat > kSonyMinRepeat ? repeat : kSonyMinRepeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_PANASONIC
|
|
|
|
case PANASONIC:
|
|
|
|
irsend->sendPanasonic64(data, bits, repeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_JVC
|
2019-03-31 12:06:42 +01:00
|
|
|
case JVC:
|
2019-07-15 08:22:07 +01:00
|
|
|
irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, repeat > 1 ? repeat : 1); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_SAMSUNG
|
2019-03-31 12:06:42 +01:00
|
|
|
case SAMSUNG:
|
2019-07-15 08:22:07 +01:00
|
|
|
irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits, repeat); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_WHYNTER
|
|
|
|
case WHYNTER:
|
|
|
|
irsend->sendWhynter(data, bits, repeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_AIWA
|
|
|
|
case AIWA_RC_T501:
|
|
|
|
irsend->sendAiwaRCT501(data, bits, repeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_LG
|
|
|
|
case LG:
|
|
|
|
irsend->sendLG(data, bits, repeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_SANYO
|
|
|
|
case SANYO:
|
|
|
|
irsend->sendSanyoLC7461(data, bits, repeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_MITSUBISHI
|
|
|
|
case MITSUBISHI:
|
|
|
|
irsend->sendMitsubishi(data, bits, repeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_DISH
|
|
|
|
case DISH:
|
|
|
|
irsend->sendDISH(data, (bits > DISH_BITS) ? DISH_BITS : bits, repeat > kDishMinRepeat ? repeat : kDishMinRepeat); break;
|
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_SEND_SHARP
|
|
|
|
case SHARP:
|
|
|
|
irsend->sendSharpRaw(data, bits, repeat); break;
|
|
|
|
#endif
|
2019-07-22 18:27:03 +01:00
|
|
|
#ifdef USE_IR_SEND_PIONEER
|
|
|
|
case IR_PIONEER:
|
2019-07-29 08:28:40 +01:00
|
|
|
irsend->sendPioneer(data, bits, repeat); break;
|
2019-07-22 18:27:03 +01:00
|
|
|
#endif // USE_IR_SEND_PIONEER
|
2019-03-31 12:06:42 +01:00
|
|
|
default:
|
|
|
|
irsend_active = false;
|
|
|
|
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_PROTOCOL_NOT_SUPPORTED);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
error = IE_SYNTAX_IRSEND;
|
2018-11-22 16:58:07 +00:00
|
|
|
}
|
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
2017-10-06 16:28:00 +01:00
|
|
|
}
|
2019-03-31 12:06:42 +01:00
|
|
|
} else {
|
|
|
|
error = IE_SYNTAX_IRSEND;
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef USE_IR_HVAC
|
2018-11-22 16:58:07 +00:00
|
|
|
else if (CMND_IRHVAC == command_code) {
|
2018-02-03 22:25:05 +00:00
|
|
|
const char *HVAC_Mode;
|
|
|
|
const char *HVAC_FanMode;
|
|
|
|
const char *HVAC_Vendor;
|
|
|
|
int HVAC_Temp = 21;
|
2019-01-28 13:08:33 +00:00
|
|
|
bool HVAC_Power = true;
|
2018-02-03 22:25:05 +00:00
|
|
|
|
2018-01-05 11:26:19 +00:00
|
|
|
if (XdrvMailbox.data_len) {
|
2018-11-22 16:58:07 +00:00
|
|
|
char dataBufUc[XdrvMailbox.data_len];
|
|
|
|
UpperCase(dataBufUc, XdrvMailbox.data);
|
2019-03-31 12:06:42 +01:00
|
|
|
RemoveSpace(dataBufUc);
|
|
|
|
if (strlen(dataBufUc) < 8) {
|
|
|
|
error = IE_INVALID_JSON;
|
|
|
|
} else {
|
|
|
|
StaticJsonBuffer<164> jsonBufer;
|
|
|
|
JsonObject &root = jsonBufer.parseObject(dataBufUc);
|
|
|
|
if (!root.success()) {
|
|
|
|
error = IE_INVALID_JSON;
|
|
|
|
} else {
|
|
|
|
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
|
|
|
|
HVAC_Vendor = root[D_JSON_IRHVAC_VENDOR];
|
|
|
|
HVAC_Power = root[D_JSON_IRHVAC_POWER];
|
|
|
|
HVAC_Mode = root[D_JSON_IRHVAC_MODE];
|
|
|
|
HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED];
|
|
|
|
HVAC_Temp = root[D_JSON_IRHVAC_TEMP];
|
|
|
|
|
|
|
|
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"), HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp);
|
|
|
|
|
|
|
|
char vendor[20];
|
|
|
|
int vendor_code = GetCommandCode(vendor, sizeof(vendor), HVAC_Vendor, kIrHvacVendors);
|
|
|
|
switch (vendor_code) {
|
2019-07-21 15:03:20 +01:00
|
|
|
#ifdef USE_IR_HVAC_TOSHIBA
|
2019-03-31 12:06:42 +01:00
|
|
|
case VNDR_TOSHIBA:
|
|
|
|
error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_HVAC_MITSUBISHI
|
2019-03-31 12:06:42 +01:00
|
|
|
case VNDR_MITSUBISHI:
|
|
|
|
error = IrHvacMitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_HVAC_LG
|
2019-03-31 12:06:42 +01:00
|
|
|
case VNDR_LG:
|
|
|
|
error = IrHvacLG(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_HVAC_FUJITSU
|
2019-03-31 12:06:42 +01:00
|
|
|
case VNDR_FUJITSU:
|
|
|
|
error = IrHvacFujitsu(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
2019-07-21 17:06:13 +01:00
|
|
|
#endif
|
|
|
|
#ifdef USE_IR_HVAC_MIDEA
|
|
|
|
case VNDR_MIDEA:
|
|
|
|
error = IrHvacMidea(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
2019-07-21 15:03:20 +01:00
|
|
|
#endif
|
2019-03-31 12:06:42 +01:00
|
|
|
default:
|
|
|
|
error = IE_SYNTAX_IRHVAC;
|
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2019-03-31 12:06:42 +01:00
|
|
|
error = IE_SYNTAX_IRHVAC;
|
2017-10-08 15:51:05 +01:00
|
|
|
}
|
2017-10-06 16:28:00 +01:00
|
|
|
}
|
2017-10-08 15:51:05 +01:00
|
|
|
#endif // USE_IR_HVAC
|
2018-11-22 16:58:07 +00:00
|
|
|
else serviced = false; // Unknown command
|
2018-05-17 10:55:40 +01:00
|
|
|
|
2019-03-31 12:06:42 +01:00
|
|
|
switch (error) {
|
|
|
|
case IE_INVALID_RAWDATA:
|
|
|
|
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_RAWDATA);
|
|
|
|
break;
|
|
|
|
case IE_INVALID_JSON:
|
|
|
|
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON);
|
|
|
|
break;
|
|
|
|
case IE_SYNTAX_IRSEND:
|
|
|
|
Response_P(PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO " " D_JSON_IR_PROTOCOL ", " D_JSON_IR_BITS " " D_JSON_OR " " D_JSON_IR_DATA "\"}"));
|
|
|
|
break;
|
|
|
|
#ifdef USE_IR_HVAC
|
|
|
|
case IE_SYNTAX_IRHVAC:
|
|
|
|
Response_P(PSTR("{\"" D_CMND_IRHVAC "\":\"" D_JSON_WRONG " " D_JSON_IRHVAC_VENDOR ", " D_JSON_IRHVAC_MODE " " D_JSON_OR " " D_JSON_IRHVAC_FANSPEED "\"}"));
|
|
|
|
break;
|
|
|
|
#endif // USE_IR_HVAC
|
|
|
|
}
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
return serviced;
|
2017-10-06 16:28:00 +01:00
|
|
|
}
|
2018-01-05 11:26:19 +00:00
|
|
|
|
|
|
|
/*********************************************************************************************\
|
|
|
|
* Interface
|
|
|
|
\*********************************************************************************************/
|
|
|
|
|
2019-01-28 13:08:33 +00:00
|
|
|
bool Xdrv05(uint8_t function)
|
2018-01-05 11:26:19 +00:00
|
|
|
{
|
2019-01-28 13:08:33 +00:00
|
|
|
bool result = false;
|
2018-01-05 11:26:19 +00:00
|
|
|
|
|
|
|
if ((pin[GPIO_IRSEND] < 99) || (pin[GPIO_IRRECV] < 99)) {
|
|
|
|
switch (function) {
|
2018-06-04 17:10:38 +01:00
|
|
|
case FUNC_PRE_INIT:
|
2018-01-05 11:26:19 +00:00
|
|
|
if (pin[GPIO_IRSEND] < 99) {
|
|
|
|
IrSendInit();
|
|
|
|
}
|
|
|
|
#ifdef USE_IR_RECEIVE
|
|
|
|
if (pin[GPIO_IRRECV] < 99) {
|
|
|
|
IrReceiveInit();
|
|
|
|
}
|
|
|
|
#endif // USE_IR_RECEIVE
|
|
|
|
break;
|
|
|
|
case FUNC_EVERY_50_MSECOND:
|
|
|
|
#ifdef USE_IR_RECEIVE
|
|
|
|
if (pin[GPIO_IRRECV] < 99) {
|
|
|
|
IrReceiveCheck(); // check if there's anything on IR side
|
|
|
|
}
|
|
|
|
#endif // USE_IR_RECEIVE
|
2019-02-03 17:45:20 +00:00
|
|
|
irsend_active = false; // re-enable IR reception
|
2018-01-05 11:26:19 +00:00
|
|
|
break;
|
|
|
|
case FUNC_COMMAND:
|
|
|
|
if (pin[GPIO_IRSEND] < 99) {
|
|
|
|
result = IrSendCommand();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2017-10-08 15:51:05 +01:00
|
|
|
#endif // USE_IR_REMOTE
|