mirror of https://github.com/arendst/Tasmota.git
parent
bea3174ec8
commit
8875787935
|
@ -28,8 +28,17 @@
|
|||
|
||||
enum IrErrors { IE_NO_ERROR, IE_INVALID_RAWDATA, IE_INVALID_JSON, IE_SYNTAX_IRSEND, IE_SYNTAX_IRHVAC };
|
||||
|
||||
enum IrRemoteCommands { CMND_IRSEND, CMND_IRHVAC };
|
||||
const char kIrRemoteCommands[] PROGMEM = D_CMND_IRSEND "|" D_CMND_IRHVAC ;
|
||||
const char kIrRemoteCommands[] PROGMEM =
|
||||
#ifdef USE_IR_HVAC
|
||||
D_CMND_IRHVAC "|"
|
||||
#endif
|
||||
D_CMND_IRSEND ;
|
||||
|
||||
void (* const IrRemoteCommand[])(void) PROGMEM = {
|
||||
#ifdef USE_IR_HVAC
|
||||
&CmndIrHvac,
|
||||
#endif
|
||||
&CmndIrSend };
|
||||
|
||||
// Based on IRremoteESP8266.h enum decode_type_t
|
||||
static const uint8_t MAX_STANDARD_IR = SHARP; // this is the last code mapped to decode_type_t
|
||||
|
@ -46,22 +55,6 @@ const char kIrRemoteProtocols[] PROGMEM =
|
|||
#endif // USE_IR_SEND_PIONEER
|
||||
;
|
||||
|
||||
#ifdef USE_IR_HVAC
|
||||
|
||||
#include <ir_Mitsubishi.h>
|
||||
#include <ir_Fujitsu.h>
|
||||
|
||||
enum IrHvacVendors {
|
||||
VNDR_TOSHIBA, VNDR_MITSUBISHI, VNDR_LG, VNDR_FUJITSU, VNDR_MIDEA };
|
||||
const char kIrHvacVendors[] PROGMEM =
|
||||
"Toshiba|Mitsubishi|LG|Fujitsu|Midea" ;
|
||||
|
||||
IRMitsubishiAC *mitsubir = nullptr;
|
||||
|
||||
const char kFanSpeedOptions[] = "A12345S";
|
||||
const char kHvacModeOptions[] = "HDCA";
|
||||
#endif // USE_IR_HVAC
|
||||
|
||||
/*********************************************************************************************\
|
||||
* IR Send
|
||||
\*********************************************************************************************/
|
||||
|
@ -75,10 +68,6 @@ void IrSendInit(void)
|
|||
{
|
||||
irsend = new IRsend(pin[GPIO_IRSEND]); // an IR led is at GPIO_IRSEND
|
||||
irsend->begin();
|
||||
|
||||
#ifdef USE_IR_HVAC
|
||||
mitsubir = new IRMitsubishiAC(pin[GPIO_IRSEND]);
|
||||
#endif //USE_IR_HVAC
|
||||
}
|
||||
|
||||
char* IrUint64toHex(uint64_t value, char *str, uint16_t bits)
|
||||
|
@ -102,6 +91,7 @@ char* IrUint64toHex(uint64_t value, char *str, uint16_t bits)
|
|||
return str;
|
||||
}
|
||||
|
||||
|
||||
#ifdef USE_IR_RECEIVE
|
||||
/*********************************************************************************************\
|
||||
* IR Receive
|
||||
|
@ -202,15 +192,22 @@ void IrReceiveCheck(void)
|
|||
}
|
||||
#endif // USE_IR_RECEIVE
|
||||
|
||||
|
||||
#ifdef USE_IR_HVAC
|
||||
/********************************************************************************************* \
|
||||
* IR Heating, Ventilation and Air Conditioning using IRMitsubishiAC library
|
||||
/*********************************************************************************************\
|
||||
* IR Heating, Ventilation and Air Conditioning
|
||||
\*********************************************************************************************/
|
||||
|
||||
enum IrHvacVendors { VNDR_TOSHIBA, VNDR_MITSUBISHI, VNDR_LG, VNDR_FUJITSU, VNDR_MIDEA };
|
||||
const char kIrHvacVendors[] PROGMEM = "Toshiba|Mitsubishi|LG|Fujitsu|Midea" ;
|
||||
|
||||
const char kFanSpeedOptions[] = "A12345S";
|
||||
const char kHvacModeOptions[] = "HDCA";
|
||||
|
||||
#ifdef USE_IR_HVAC_TOSHIBA
|
||||
/*******************
|
||||
TOSHIBA
|
||||
********************/
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* Toshiba
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
const uint16_t HVAC_TOSHIBA_HDR_MARK = 4400;
|
||||
const uint16_t HVAC_TOSHIBA_HDR_SPACE = 4300;
|
||||
|
@ -303,7 +300,6 @@ uint8_t IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC
|
|||
rawdata[i++] = HVAC_TOSHIBA_RPT_SPACE;
|
||||
|
||||
// noInterrupts();
|
||||
irsend_active = true;
|
||||
irsend->sendRaw(rawdata, i, 38);
|
||||
irsend->sendRaw(rawdata, i, 38);
|
||||
// interrupts();
|
||||
|
@ -313,9 +309,9 @@ uint8_t IrHvacToshiba(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC
|
|||
#endif // USE_IR_HVAC_TOSHIBA
|
||||
|
||||
#ifdef USE_IR_HVAC_MIDEA
|
||||
/*******************
|
||||
MIDEA / KOMECO
|
||||
********************/
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* Midea / Komeco
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
// http://veillard.com/embedded/midea.html
|
||||
// https://github.com/sheinz/esp-midea-ir/blob/master/midea-ir.c
|
||||
|
@ -431,27 +427,29 @@ uint8_t IrHvacMidea(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_P
|
|||
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
|
||||
|
||||
#ifdef USE_IR_HVAC_MITSUBISHI
|
||||
/*******************
|
||||
MITSUBISHI
|
||||
********************/
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* Mitsubishi
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
#include <ir_Mitsubishi.h>
|
||||
|
||||
uint8_t IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
|
||||
{
|
||||
char *p;
|
||||
uint8_t mode;
|
||||
|
||||
mitsubir->stateReset();
|
||||
IRMitsubishiAC mitsubir(pin[GPIO_IRSEND]);
|
||||
|
||||
mitsubir.stateReset();
|
||||
|
||||
if (HVAC_Mode == nullptr) {
|
||||
p = (char *)kHvacModeOptions; // default HVAC_HOT
|
||||
|
@ -463,9 +461,9 @@ uint8_t IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool H
|
|||
return IE_SYNTAX_IRHVAC;
|
||||
}
|
||||
mode = (p - kHvacModeOptions + 1) << 3; // HOT = 0x08, DRY = 0x10, COOL = 0x18, AUTO = 0x20
|
||||
mitsubir->setMode(mode);
|
||||
mitsubir.setMode(mode);
|
||||
|
||||
mitsubir->setPower(HVAC_Power);
|
||||
mitsubir.setPower(HVAC_Power);
|
||||
|
||||
if (HVAC_FanMode == nullptr) {
|
||||
p = (char *)kFanSpeedOptions; // default FAN_SPEED_AUTO
|
||||
|
@ -477,11 +475,11 @@ uint8_t IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool H
|
|||
return IE_SYNTAX_IRHVAC;
|
||||
}
|
||||
mode = p - kFanSpeedOptions; // AUTO = 0, SPEED = 1 .. 5, SILENT = 6
|
||||
mitsubir->setFan(mode);
|
||||
mitsubir.setFan(mode);
|
||||
|
||||
mitsubir->setTemp(HVAC_Temp);
|
||||
mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO);
|
||||
mitsubir->send();
|
||||
mitsubir.setTemp(HVAC_Temp);
|
||||
mitsubir.setVane(MITSUBISHI_AC_VANE_AUTO);
|
||||
mitsubir.send();
|
||||
|
||||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"),
|
||||
// mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane());
|
||||
|
@ -491,9 +489,9 @@ uint8_t IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, bool H
|
|||
#endif // USE_IR_HVAC_MITSUBISHI
|
||||
|
||||
#ifdef USE_IR_HVAC_LG
|
||||
/*******************
|
||||
LG
|
||||
********************/
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* LG
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
const uint8_t HVAC_LG_DATALEN = 7;
|
||||
|
||||
|
@ -600,19 +598,18 @@ uint8_t IrHvacLG(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Powe
|
|||
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR("IRHVAC: LG_Code %d"), LG_Code);
|
||||
|
||||
// Send LG IR Code
|
||||
// noInterrupts();
|
||||
irsend_active = true;
|
||||
irsend->sendLG(LG_Code, 28);
|
||||
// interrupts();
|
||||
|
||||
return IE_NO_ERROR;
|
||||
}
|
||||
#endif // USE_IR_HVAC_LG
|
||||
|
||||
#ifdef USE_IR_HVAC_FUJITSU
|
||||
/*******************
|
||||
Fujitsu
|
||||
********************/
|
||||
/*-------------------------------------------------------------------------------------------*\
|
||||
* Fujitsu
|
||||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
#include <ir_Fujitsu.h>
|
||||
|
||||
uint8_t IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC_Power, int HVAC_Temp)
|
||||
{
|
||||
|
@ -622,8 +619,6 @@ uint8_t IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC
|
|||
|
||||
IRFujitsuAC ac(pin[GPIO_IRSEND]);
|
||||
|
||||
irsend_active = true;
|
||||
|
||||
if (0 == HVAC_Power) {
|
||||
ac.off();
|
||||
ac.send();
|
||||
|
@ -665,331 +660,341 @@ uint8_t IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, bool HVAC
|
|||
}
|
||||
#endif // USE_IR_HVAC_FUJITSU
|
||||
|
||||
/*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
uint32_t IrRemoteCmndIrHvacJson(void)
|
||||
{
|
||||
// IrHvac { "Vendor": "<Toshiba|Mitsubishi>", "Power": <0|1>, "Mode": "<Hot|Cold|Dry|Auto>", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> }
|
||||
const char *HVAC_Mode;
|
||||
const char *HVAC_FanMode;
|
||||
const char *HVAC_Vendor;
|
||||
int HVAC_Temp = 21;
|
||||
bool HVAC_Power = true;
|
||||
|
||||
char dataBufUc[XdrvMailbox.data_len];
|
||||
UpperCase(dataBufUc, XdrvMailbox.data);
|
||||
RemoveSpace(dataBufUc);
|
||||
if (strlen(dataBufUc) < 8) {
|
||||
return IE_INVALID_JSON;
|
||||
}
|
||||
|
||||
StaticJsonBuffer<164> jsonBufer;
|
||||
JsonObject &root = jsonBufer.parseObject(dataBufUc);
|
||||
if (!root.success()) {
|
||||
return IE_INVALID_JSON;
|
||||
}
|
||||
|
||||
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);
|
||||
irsend_active = true;
|
||||
switch (vendor_code) {
|
||||
#ifdef USE_IR_HVAC_TOSHIBA
|
||||
case VNDR_TOSHIBA:
|
||||
return IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_MITSUBISHI
|
||||
case VNDR_MITSUBISHI:
|
||||
return IrHvacMitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_LG
|
||||
case VNDR_LG:
|
||||
return IrHvacLG(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_FUJITSU
|
||||
case VNDR_FUJITSU:
|
||||
return IrHvacFujitsu(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_MIDEA
|
||||
case VNDR_MIDEA:
|
||||
return IrHvacMidea(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);
|
||||
#endif
|
||||
default:
|
||||
irsend_active = false;
|
||||
}
|
||||
|
||||
return IE_SYNTAX_IRHVAC;
|
||||
}
|
||||
|
||||
void CmndIrHvac(void)
|
||||
{
|
||||
uint8_t error = IE_SYNTAX_IRHVAC;
|
||||
|
||||
if (XdrvMailbox.data_len) {
|
||||
error = IrRemoteCmndIrHvacJson();
|
||||
}
|
||||
IrRemoteCmndResponse(error);
|
||||
}
|
||||
|
||||
#endif // USE_IR_HVAC
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Commands
|
||||
\*********************************************************************************************/
|
||||
|
||||
/*
|
||||
* ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
|
||||
IRsend:
|
||||
{ "protocol": "RC5", "bits": 12, "data":"0xC86" }
|
||||
{ "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> }
|
||||
*/
|
||||
|
||||
bool IrSendCommand(void)
|
||||
uint32_t IrRemoteCmndIrSendRaw(void)
|
||||
{
|
||||
char command [CMDSZ];
|
||||
bool serviced = true;
|
||||
uint8_t error = IE_NO_ERROR;
|
||||
// IRsend <freq>,<rawdata>,<rawdata> ...
|
||||
// or
|
||||
// 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>
|
||||
// IRsend raw,<freq>,<zero space>,<one space>,<bit stream>
|
||||
// IRsend raw,<freq>,<header mark>,<header space>,<bit mark>,<zero space>,<one space>,<bit stream>
|
||||
|
||||
int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kIrRemoteCommands);
|
||||
if (-1 == command_code) {
|
||||
serviced = false; // Unknown command
|
||||
char *p;
|
||||
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
if (p == nullptr) {
|
||||
return IE_INVALID_RAWDATA;
|
||||
}
|
||||
else if (CMND_IRSEND == command_code) {
|
||||
if (XdrvMailbox.data_len) {
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_DONE);
|
||||
|
||||
if (strstr(XdrvMailbox.data, "{") == nullptr) { // If no JSON it must be rawdata
|
||||
// IRsend <freq>,<rawdata>,<rawdata> ...
|
||||
// or
|
||||
// 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>
|
||||
// IRsend raw,<freq>,<zero space>,<one space>,<bit stream>
|
||||
// IRsend raw,<freq>,<header mark>,<header space>,<bit mark>,<zero space>,<one space>,<bit stream>
|
||||
char *p;
|
||||
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
|
||||
if (p == nullptr) {
|
||||
error = IE_INVALID_RAWDATA;
|
||||
uint16_t freq = atoi(str);
|
||||
if (!freq && (*str != '0')) { // First parameter is any string
|
||||
uint16_t count = 0;
|
||||
char *q = p;
|
||||
for (; *q; count += (*q++ == ','));
|
||||
if (count < 2) {
|
||||
return IE_INVALID_RAWDATA;
|
||||
} // Parameters must be at least 3
|
||||
|
||||
uint16_t parm[count];
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
parm[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0);
|
||||
if (!parm[i]) {
|
||||
if (!i) {
|
||||
parm[0] = 38000; // Frequency default to 38kHz
|
||||
} else {
|
||||
uint16_t freq = atoi(str);
|
||||
if (!freq && (*str != '0')) { // First parameter is any string
|
||||
uint16_t count = 0;
|
||||
char *q = p;
|
||||
for (; *q; count += (*q++ == ','));
|
||||
if (count < 2) { // Parameters must be at least 3
|
||||
error = IE_INVALID_RAWDATA;
|
||||
} else {
|
||||
uint16_t parm[count];
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
parm[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0);
|
||||
if (!parm[i]) {
|
||||
if (!i) {
|
||||
parm[0] = 38000; // Frequency default to 38kHz
|
||||
} else {
|
||||
error = IE_INVALID_RAWDATA; // Other parameters may not be 0
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IE_NO_ERROR == error) {
|
||||
uint16_t i = 0;
|
||||
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)
|
||||
}
|
||||
}
|
||||
uint16_t raw_array[strlen(p)]; // Bits
|
||||
for (; *p; *p++) {
|
||||
if (*p == '0') {
|
||||
raw_array[i++] = parm[1]; // Space
|
||||
}
|
||||
else if (*p == '1') {
|
||||
raw_array[i++] = mark; // Mark
|
||||
}
|
||||
}
|
||||
irsend_active = true;
|
||||
irsend->sendRaw(raw_array, i, parm[0]);
|
||||
}
|
||||
else if (6 == count) { // NEC Protocol
|
||||
// IRsend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
|
||||
uint16_t raw_array[strlen(p)*2+3]; // Header + bits + end
|
||||
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
|
||||
irsend_active = true;
|
||||
irsend->sendRaw(raw_array, i, parm[0]);
|
||||
}
|
||||
else {
|
||||
error = IE_INVALID_RAWDATA; // Invalid number of parameters
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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
|
||||
// IRsend 0,896,876,900,888,894,876,1790,874,872,1810,1736,948,872,880,872,936,872,1792,900,888,1734
|
||||
count++;
|
||||
if (count < 200) {
|
||||
uint16_t raw_array[count]; // It's safe to use stack for up to 200 packets (limited by mqtt_data length)
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
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 {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
char dataBufUc[XdrvMailbox.data_len];
|
||||
UpperCase(dataBufUc, XdrvMailbox.data);
|
||||
RemoveSpace(dataBufUc);
|
||||
if (strlen(dataBufUc) < 8) {
|
||||
error = IE_INVALID_JSON;
|
||||
} else {
|
||||
StaticJsonBuffer<140> jsonBuf;
|
||||
JsonObject &root = jsonBuf.parseObject(dataBufUc);
|
||||
if (!root.success()) {
|
||||
error = IE_INVALID_JSON;
|
||||
} else {
|
||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||
// IRsend { "protocol": "NEC", "bits": 32, "data":"0x02FDFE80", "repeat": 2 }
|
||||
char parm_uc[10];
|
||||
const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))];
|
||||
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);
|
||||
uint16_t repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT))];
|
||||
if (protocol && bits) {
|
||||
char protocol_text[20];
|
||||
int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols);
|
||||
|
||||
char dvalue[64];
|
||||
char hvalue[64];
|
||||
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);
|
||||
|
||||
irsend_active = true;
|
||||
switch (protocol_code) { // Equals IRremoteESP8266.h enum decode_type_t
|
||||
#ifdef USE_IR_SEND_RC5
|
||||
case RC5:
|
||||
irsend->sendRC5(data, bits, repeat); break;
|
||||
#endif
|
||||
#ifdef USE_IR_SEND_RC6
|
||||
case RC6:
|
||||
irsend->sendRC6(data, bits, repeat); break;
|
||||
#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
|
||||
case JVC:
|
||||
irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, repeat > 1 ? repeat : 1); break;
|
||||
#endif
|
||||
#ifdef USE_IR_SEND_SAMSUNG
|
||||
case SAMSUNG:
|
||||
irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits, repeat); break;
|
||||
#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
|
||||
#ifdef USE_IR_SEND_PIONEER
|
||||
case IR_PIONEER:
|
||||
irsend->sendPioneer(data, bits, repeat); break;
|
||||
#endif // USE_IR_SEND_PIONEER
|
||||
default:
|
||||
irsend_active = false;
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_PROTOCOL_NOT_SUPPORTED);
|
||||
}
|
||||
} else {
|
||||
error = IE_SYNTAX_IRSEND;
|
||||
}
|
||||
}
|
||||
return IE_INVALID_RAWDATA; // Other parameters may not be 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error = IE_SYNTAX_IRSEND;
|
||||
}
|
||||
}
|
||||
#ifdef USE_IR_HVAC
|
||||
else if (CMND_IRHVAC == command_code) {
|
||||
const char *HVAC_Mode;
|
||||
const char *HVAC_FanMode;
|
||||
const char *HVAC_Vendor;
|
||||
int HVAC_Temp = 21;
|
||||
bool HVAC_Power = true;
|
||||
|
||||
if (XdrvMailbox.data_len) {
|
||||
char dataBufUc[XdrvMailbox.data_len];
|
||||
UpperCase(dataBufUc, XdrvMailbox.data);
|
||||
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;
|
||||
uint16_t i = 0;
|
||||
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 {
|
||||
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) {
|
||||
#ifdef USE_IR_HVAC_TOSHIBA
|
||||
case VNDR_TOSHIBA:
|
||||
error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_MITSUBISHI
|
||||
case VNDR_MITSUBISHI:
|
||||
error = IrHvacMitsubishi(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_LG
|
||||
case VNDR_LG:
|
||||
error = IrHvacLG(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_FUJITSU
|
||||
case VNDR_FUJITSU:
|
||||
error = IrHvacFujitsu(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
||||
#endif
|
||||
#ifdef USE_IR_HVAC_MIDEA
|
||||
case VNDR_MIDEA:
|
||||
error = IrHvacMidea(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); break;
|
||||
#endif
|
||||
default:
|
||||
error = IE_SYNTAX_IRHVAC;
|
||||
}
|
||||
// IRsend raw,0,889,1778,000000100110000001001
|
||||
mark = parm[2]; // Protocol where 0 = t1, 1 = t2 (Could be RC5)
|
||||
}
|
||||
}
|
||||
uint16_t raw_array[strlen(p)]; // Bits
|
||||
for (; *p; *p++) {
|
||||
if (*p == '0') {
|
||||
raw_array[i++] = parm[1]; // Space
|
||||
}
|
||||
else if (*p == '1') {
|
||||
raw_array[i++] = mark; // Mark
|
||||
}
|
||||
}
|
||||
irsend_active = true;
|
||||
irsend->sendRaw(raw_array, i, parm[0]);
|
||||
}
|
||||
else if (6 == count) { // NEC Protocol
|
||||
// IRsend raw,0,8620,4260,544,411,1496,010101101000111011001110000000001100110000000001100000000000000010001100
|
||||
uint16_t raw_array[strlen(p)*2+3]; // Header + bits + end
|
||||
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
|
||||
irsend_active = true;
|
||||
irsend->sendRaw(raw_array, i, parm[0]);
|
||||
}
|
||||
else {
|
||||
error = IE_SYNTAX_IRHVAC;
|
||||
return IE_INVALID_RAWDATA; // Invalid number of parameters
|
||||
}
|
||||
} else {
|
||||
if (!freq) { freq = 38000; } // Default to 38kHz
|
||||
uint16_t count = 0;
|
||||
char *q = p;
|
||||
for (; *q; count += (*q++ == ','));
|
||||
if (0 == count) {
|
||||
return IE_INVALID_RAWDATA;
|
||||
}
|
||||
|
||||
// IRsend 0,896,876,900,888,894,876,1790,874,872,1810,1736,948,872,880,872,936,872,1792,900,888,1734
|
||||
count++;
|
||||
if (count < 200) {
|
||||
uint16_t raw_array[count]; // It's safe to use stack for up to 200 packets (limited by mqtt_data length)
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
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) {
|
||||
return IE_INVALID_RAWDATA;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
#endif // USE_IR_HVAC
|
||||
else serviced = false; // Unknown command
|
||||
|
||||
return IE_NO_ERROR;
|
||||
}
|
||||
|
||||
uint32_t IrRemoteCmndIrSendJson(void)
|
||||
{
|
||||
// ArduinoJSON entry used to calculate jsonBuf: JSON_OBJECT_SIZE(3) + 40 = 96
|
||||
// IRsend { "protocol": "RC5", "bits": 12, "data":"0xC86" }
|
||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||
|
||||
char dataBufUc[XdrvMailbox.data_len];
|
||||
UpperCase(dataBufUc, XdrvMailbox.data);
|
||||
RemoveSpace(dataBufUc);
|
||||
if (strlen(dataBufUc) < 8) {
|
||||
return IE_INVALID_JSON;
|
||||
}
|
||||
|
||||
StaticJsonBuffer<140> jsonBuf;
|
||||
JsonObject &root = jsonBuf.parseObject(dataBufUc);
|
||||
if (!root.success()) {
|
||||
return IE_INVALID_JSON;
|
||||
}
|
||||
|
||||
// IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
|
||||
// IRsend { "protocol": "NEC", "bits": 32, "data":"0x02FDFE80", "repeat": 2 }
|
||||
char parm_uc[10];
|
||||
const char *protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))];
|
||||
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);
|
||||
uint16_t repeat = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_REPEAT))];
|
||||
if (!(protocol && bits)) {
|
||||
return IE_SYNTAX_IRSEND;
|
||||
}
|
||||
|
||||
char protocol_text[20];
|
||||
int protocol_code = GetCommandCode(protocol_text, sizeof(protocol_text), protocol, kIrRemoteProtocols);
|
||||
|
||||
char dvalue[64];
|
||||
char hvalue[64];
|
||||
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);
|
||||
|
||||
irsend_active = true;
|
||||
switch (protocol_code) { // Equals IRremoteESP8266.h enum decode_type_t
|
||||
#ifdef USE_IR_SEND_RC5
|
||||
case RC5:
|
||||
irsend->sendRC5(data, bits, repeat); break;
|
||||
#endif
|
||||
#ifdef USE_IR_SEND_RC6
|
||||
case RC6:
|
||||
irsend->sendRC6(data, bits, repeat); break;
|
||||
#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
|
||||
case JVC:
|
||||
irsend->sendJVC(data, (bits > JVC_BITS) ? JVC_BITS : bits, repeat > 1 ? repeat : 1); break;
|
||||
#endif
|
||||
#ifdef USE_IR_SEND_SAMSUNG
|
||||
case SAMSUNG:
|
||||
irsend->sendSAMSUNG(data, (bits > SAMSUNG_BITS) ? SAMSUNG_BITS : bits, repeat); break;
|
||||
#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
|
||||
#ifdef USE_IR_SEND_PIONEER
|
||||
case IR_PIONEER:
|
||||
irsend->sendPioneer(data, bits, repeat); break;
|
||||
#endif // USE_IR_SEND_PIONEER
|
||||
default:
|
||||
irsend_active = false;
|
||||
Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.command, D_JSON_PROTOCOL_NOT_SUPPORTED);
|
||||
}
|
||||
|
||||
return IE_NO_ERROR;
|
||||
}
|
||||
|
||||
void CmndIrSend(void)
|
||||
{
|
||||
uint8_t error = IE_SYNTAX_IRSEND;
|
||||
|
||||
if (XdrvMailbox.data_len) {
|
||||
// error = (strstr(XdrvMailbox.data, "{") == nullptr) ? IrRemoteCmndIrSendRaw() : IrRemoteCmndIrSendJson();
|
||||
if (strstr(XdrvMailbox.data, "{") == nullptr) {
|
||||
error = IrRemoteCmndIrSendRaw();
|
||||
} else {
|
||||
error = IrRemoteCmndIrSendJson();
|
||||
}
|
||||
}
|
||||
IrRemoteCmndResponse(error);
|
||||
}
|
||||
|
||||
void IrRemoteCmndResponse(uint32_t error)
|
||||
{
|
||||
switch (error) {
|
||||
case IE_INVALID_RAWDATA:
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_RAWDATA);
|
||||
Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.command, D_JSON_INVALID_RAWDATA);
|
||||
break;
|
||||
case IE_INVALID_JSON:
|
||||
Response_P(S_JSON_COMMAND_SVALUE, command, D_JSON_INVALID_JSON);
|
||||
Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.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 "\"}"));
|
||||
|
@ -999,9 +1004,9 @@ bool IrSendCommand(void)
|
|||
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
|
||||
default: // IE_NO_ERROR
|
||||
Response_P(S_JSON_COMMAND_SVALUE, XdrvMailbox.command, D_JSON_DONE);
|
||||
}
|
||||
|
||||
return serviced;
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
|
@ -1034,7 +1039,7 @@ bool Xdrv05(uint8_t function)
|
|||
break;
|
||||
case FUNC_COMMAND:
|
||||
if (pin[GPIO_IRSEND] < 99) {
|
||||
result = IrSendCommand();
|
||||
result = DecodeCommand(kIrRemoteCommands, IrRemoteCommand);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue