Add IR Raw data control

* Add command SetOption58 0/1 to enable IR raw data info in JSON message (#2116)
 * Add command IRSend <frequency>|0,<rawdata1>,<rawdata2>,.. to allow raw data transmission (#2116)
This commit is contained in:
Theo Arends 2018-11-21 16:36:10 +01:00
parent 9ad155436a
commit 070843200f
6 changed files with 101 additions and 26 deletions

View File

@ -2,6 +2,8 @@
* Add delays removed in 6.3.0.9 (#4233) * Add delays removed in 6.3.0.9 (#4233)
* Allow user definition of defines WIFI_RSSI_THRESHOLD (default 10) and WIFI_RESCAN_MINUTES (default 44) * Allow user definition of defines WIFI_RSSI_THRESHOLD (default 10) and WIFI_RESCAN_MINUTES (default 44)
* Add support for Fujitsu HVac and IrRemote (#4387) * Add support for Fujitsu HVac and IrRemote (#4387)
* Add command SetOption58 0/1 to enable IR raw data info in JSON message (#2116)
* Add command IRSend <frequency>|0,<rawdata1>,<rawdata2>,.. to allow raw data transmission (#2116)
* *
* 6.3.0.10 20181118 * 6.3.0.10 20181118
* Add command SetOption36 0..255 milliseconds (50 default) to tune main loop dynamic delay * Add command SetOption36 0..255 milliseconds (50 default) to tune main loop dynamic delay

View File

@ -335,10 +335,13 @@
// Commands xdrv_05_irremote.ino // Commands xdrv_05_irremote.ino
#define D_CMND_IRSEND "IRSend" #define D_CMND_IRSEND "IRSend"
#define D_JSON_INVALID_JSON "Invalid JSON" #define D_JSON_INVALID_JSON "Invalid JSON"
#define D_JSON_INVALID_RAWDATA "Invalid RawData"
#define D_JSON_NO_BUFFER_SPACE "No buffer space"
#define D_JSON_PROTOCOL_NOT_SUPPORTED "Protocol not supported" #define D_JSON_PROTOCOL_NOT_SUPPORTED "Protocol not supported"
#define D_JSON_IR_PROTOCOL "Protocol" #define D_JSON_IR_PROTOCOL "Protocol"
#define D_JSON_IR_BITS "Bits" #define D_JSON_IR_BITS "Bits"
#define D_JSON_IR_DATA "Data" #define D_JSON_IR_DATA "Data"
#define D_JSON_IR_RAWDATA "RawData"
#define D_CMND_IRHVAC "IRHVAC" #define D_CMND_IRHVAC "IRHVAC"
#define D_JSON_IRHVAC_VENDOR "VENDOR" #define D_JSON_IRHVAC_VENDOR "VENDOR"
#define D_JSON_IRHVAC_POWER "POWER" #define D_JSON_IRHVAC_POWER "POWER"

View File

@ -367,7 +367,10 @@
// -- Low level interface devices ----------------- // -- Low level interface devices -----------------
#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k3 code, 0k3 mem, 48 iram) #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k3 code, 0k3 mem, 48 iram)
// #define USE_IR_HVAC // Support for HVAC (Toshiba, Mitsubishi and LG) system using IR (+3k5 code) // #define USE_IR_HVAC // Support for HVAC (Toshiba, Mitsubishi and LG) system using IR (+3k5 code)
#define USE_IR_RECEIVE // Support for IR receiver (+6k5 code, 264 iram) #define USE_IR_RECEIVE // Support for IR receiver (+7k2 code, 264 iram)
#define IR_RCV_BUFFER_SIZE 100 // Max number of packets allowed in capture buffer (default 100 (*2 bytes ram))
#define IR_RCV_TIMEOUT 15 // Number of milli-Seconds of no-more-data before we consider a message ended (default 15)
#define IR_RCV_MIN_UNKNOWN_SIZE 6 // Set the smallest sized "UNKNOWN" message packets we actually care about (default 6)
#define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by //
#define USE_WS2812_CTYPE NEO_GRB // WS2812 Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW) #define USE_WS2812_CTYPE NEO_GRB // WS2812 Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW)

View File

@ -71,7 +71,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu
uint32_t hass_short_discovery_msg : 1; // bit 5 (v6.3.0.7) uint32_t hass_short_discovery_msg : 1; // bit 5 (v6.3.0.7)
uint32_t use_wifi_scan : 1; // bit 6 (v6.3.0.10) uint32_t use_wifi_scan : 1; // bit 6 (v6.3.0.10)
uint32_t use_wifi_rescan : 1; // bit 7 (v6.3.0.10) uint32_t use_wifi_rescan : 1; // bit 7 (v6.3.0.10)
uint32_t spare08 : 1; uint32_t receive_raw : 1; // bit 8 (v6.3.0.11)
uint32_t spare09 : 1; uint32_t spare09 : 1;
uint32_t spare10 : 1; uint32_t spare10 : 1;
uint32_t spare11 : 1; uint32_t spare11 : 1;

View File

@ -77,16 +77,21 @@ void IrSendInit(void)
* IR Receive * IR Receive
\*********************************************************************************************/ \*********************************************************************************************/
#define IR_RCV_SAVE_BUFFER 0 // 0 = do not use buffer, 1 = use buffer for decoding
#define IR_TIME_AVOID_DUPLICATE 500 // Milliseconds
#include <IRrecv.h> #include <IRrecv.h>
#define IR_TIME_AVOID_DUPLICATE 500 // Milliseconds
IRrecv *irrecv = NULL; IRrecv *irrecv = NULL;
unsigned long ir_lasttime = 0; unsigned long ir_lasttime = 0;
void IrReceiveInit(void) void IrReceiveInit(void)
{ {
irrecv = new IRrecv(pin[GPIO_IRRECV]); // an IR led is at GPIO_IRRECV // an IR led is at GPIO_IRRECV
irrecv = new IRrecv(pin[GPIO_IRRECV], IR_RCV_BUFFER_SIZE, IR_RCV_TIMEOUT, IR_RCV_SAVE_BUFFER);
irrecv->setUnknownThreshold(IR_RCV_MIN_UNKNOWN_SIZE);
irrecv->enableIRIn(); // Start the receiver irrecv->enableIRIn(); // Start the receiver
// AddLog_P(LOG_LEVEL_DEBUG, PSTR("IrReceive initialized")); // AddLog_P(LOG_LEVEL_DEBUG, PSTR("IrReceive initialized"));
@ -102,33 +107,58 @@ void IrReceiveCheck(void)
if (irrecv->decode(&results)) { if (irrecv->decode(&results)) {
snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_IRR "RawLen %d, Bits %d, Value %08X, Decode %d"), snprintf_P(log_data, sizeof(log_data), PSTR(D_LOG_IRR "RawLen %d, Overflow %d, Bits %d, Value %08X, Decode %d"),
results.rawlen, results.bits, results.value, results.decode_type); results.rawlen, results.overflow, results.bits, results.value, results.decode_type);
AddLog(LOG_LEVEL_DEBUG); AddLog(LOG_LEVEL_DEBUG);
unsigned long now = millis(); unsigned long now = millis();
if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) { // if ((now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) && (UNKNOWN != results.decode_type) && (results.bits > 0)) {
if (now - ir_lasttime > IR_TIME_AVOID_DUPLICATE) {
ir_lasttime = now; ir_lasttime = now;
iridx = results.decode_type; iridx = results.decode_type;
if ((iridx < 0) || (iridx > 14)) { if ((iridx < 0) || (iridx > 14)) {
iridx = 0; iridx = 0; // UNKNOWN
} }
if (Settings.flag.ir_receive_decimal) { if (Settings.flag.ir_receive_decimal) {
snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)results.value); snprintf_P(stemp, sizeof(stemp), PSTR("%u"), (uint32_t)results.value);
} else { } else {
snprintf_P(stemp, sizeof(stemp), PSTR("\"%lX\""), (uint32_t)results.value); snprintf_P(stemp, sizeof(stemp), PSTR("\"%lX\""), (uint32_t)results.value);
} }
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s}}"), snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_IRRECEIVED "\":{\"" D_JSON_IR_PROTOCOL "\":\"%s\",\"" D_JSON_IR_BITS "\":%d,\"" D_JSON_IR_DATA "\":%s"),
GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, stemp); GetTextIndexed(sirtype, sizeof(sirtype), iridx, kIrRemoteProtocols), results.bits, stemp);
if (Settings.flag3.receive_raw) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"" D_JSON_IR_RAWDATA "\":["), mqtt_data);
uint16_t i;
for (i = 1; i < results.rawlen; i++) {
if (i > 1) { snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,"), mqtt_data); }
uint32_t usecs;
for (usecs = results.rawbuf[i] * kRawTick; usecs > UINT16_MAX; usecs -= UINT16_MAX) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%d,0,"), mqtt_data, UINT16_MAX);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s%d"), mqtt_data, usecs);
if (strlen(mqtt_data) > sizeof(mqtt_data) - 40) { break; } // Quit if char string becomes too long
}
uint16_t extended_length = results.rawlen - 1;
for (uint16_t j = 0; j < results.rawlen - 1; j++) {
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;
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s],\"" D_JSON_IR_RAWDATA "Info\":[%d,%d,%d]"), mqtt_data, extended_length, i -1, results.overflow);
}
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s}}"), mqtt_data);
MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED)); MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED));
XdrvRulesProcess();
if (iridx) {
XdrvRulesProcess();
#ifdef USE_DOMOTICZ #ifdef USE_DOMOTICZ
unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28] unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28]
DomoticzSensor(DZ_COUNT, value); // Send data as Domoticz Counter value DomoticzSensor(DZ_COUNT, value); // Send data as Domoticz Counter value
#endif // USE_DOMOTICZ #endif // USE_DOMOTICZ
}
} }
irrecv->resume(); irrecv->resume();
@ -276,9 +306,9 @@ boolean IrHvacMitsubishi(const char *HVAC_Mode, const char *HVAC_FanMode, boolea
mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO); mitsubir->setVane(MITSUBISHI_AC_VANE_AUTO);
mitsubir->send(); mitsubir->send();
// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"), // snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Mitsubishi Power %d, Mode %d, FanSpeed %d, Temp %d, VaneMode %d"),
// mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane()); // mitsubir->getPower(), mitsubir->getMode(), mitsubir->getFan(), mitsubir->getTemp(), mitsubir->getVane());
// AddLog(LOG_LEVEL_DEBUG); // AddLog(LOG_LEVEL_DEBUG);
return false; return false;
} }
@ -469,28 +499,64 @@ boolean IrHvacFujitsu(const char *HVAC_Mode, const char *HVAC_FanMode, boolean H
{ "Vendor": "<Toshiba|Mitsubishi>", "Power": <0|1>, "Mode": "<Hot|Cold|Dry|Auto>", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> } { "Vendor": "<Toshiba|Mitsubishi>", "Power": <0|1>, "Mode": "<Hot|Cold|Dry|Auto>", "FanSpeed": "<1|2|3|4|5|Auto|Silence>", "Temp": <17..30> }
*/ */
//boolean IrSendCommand(char *type, uint16_t index, char *dataBuf, uint16_t data_len, int16_t payload)
boolean IrSendCommand(void) boolean IrSendCommand(void)
{ {
boolean serviced = true; boolean serviced = true;
boolean error = false; boolean error = false;
char dataBufUc[XdrvMailbox.data_len];
char protocol_text[20]; char protocol_text[20];
const char *protocol; const char *protocol;
uint32_t bits = 0; uint32_t bits = 0;
uint32_t data = 0; uint32_t data = 0;
char dataBufUc[XdrvMailbox.data_len];
UpperCase(dataBufUc, XdrvMailbox.data); UpperCase(dataBufUc, XdrvMailbox.data);
if (!strcasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_IRSEND))) { if (!strcasecmp_P(XdrvMailbox.topic, PSTR(D_CMND_IRSEND))) {
if (XdrvMailbox.data_len) { if (XdrvMailbox.data_len) {
StaticJsonBuffer<128> jsonBuf; StaticJsonBuffer<128> jsonBuf;
JsonObject &root = jsonBuf.parseObject(dataBufUc); JsonObject &root = jsonBuf.parseObject(dataBufUc);
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_DONE "\"}"));
if (!root.success()) { if (!root.success()) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_INVALID_JSON "\"}")); // JSON decode failed // IRSend frequency, rawdata, rawdata ...
char *p;
char *str = strtok_r(XdrvMailbox.data, ", ", &p);
uint16_t freq = atoi(str);
if (!freq) { freq = 38000; } // Default to 38kHz
uint16_t count = 0;
char *q = p;
for (; *q; count += (*q++ == ','));
if (count) { // At least two raw data values
count++;
uint16_t* raw_array = NULL;
raw_array = reinterpret_cast<uint16_t*>(malloc(count * sizeof(uint16_t)));
if (raw_array != NULL) {
byte i = 0;
for (str = strtok_r(NULL, ", ", &p); str && i < count; str = strtok_r(NULL, ", ", &p)) {
raw_array[i++] = strtoul(str, NULL, 0); // Allow decimal (5246996) and hexadecimal (0x501014) input
}
// snprintf_P(log_data, sizeof(log_data), PSTR("IRS: Count %d, Freq %d, Arr[0] %d, Arr[count -1] %d"),
// count, freq, raw_array[0], raw_array[count -1]);
// AddLog(LOG_LEVEL_DEBUG);
irsend->sendRaw(raw_array, count, freq);
free(raw_array);
if (!count) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_FAILED "\"}")); // JSON decode failed and invalid RawData
}
}
else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_NO_BUFFER_SPACE "\"}")); // JSON decode failed and invalid RawData
}
}
else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_INVALID_RAWDATA "\"}")); // JSON decode failed and invalid RawData
}
} }
else { else {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_IRSEND "\":\"" D_JSON_DONE "\"}")); // IRsend { "protocol": "SAMSUNG", "bits": 32, "data": 551502015 }
char parm_uc[10]; char parm_uc[10];
protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))]; protocol = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_PROTOCOL))];
bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))]; bits = root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_BITS))];
data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], NULL, 0); data = strtoul(root[UpperCase_P(parm_uc, PSTR(D_JSON_IR_DATA))], NULL, 0);
@ -556,9 +622,9 @@ boolean IrSendCommand(void)
HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED]; HVAC_FanMode = root[D_JSON_IRHVAC_FANSPEED];
HVAC_Temp = root[D_JSON_IRHVAC_TEMP]; HVAC_Temp = root[D_JSON_IRHVAC_TEMP];
// snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"), // snprintf_P(log_data, sizeof(log_data), PSTR("IRHVAC: Received Vendor %s, Power %d, Mode %s, FanSpeed %s, Temp %d"),
// HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp); // HVAC_Vendor, HVAC_Power, HVAC_Mode, HVAC_FanMode, HVAC_Temp);
// AddLog(LOG_LEVEL_DEBUG); // AddLog(LOG_LEVEL_DEBUG);
if (HVAC_Vendor == NULL || !strcasecmp_P(HVAC_Vendor, PSTR("TOSHIBA"))) { if (HVAC_Vendor == NULL || !strcasecmp_P(HVAC_Vendor, PSTR("TOSHIBA"))) {
error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp); error = IrHvacToshiba(HVAC_Mode, HVAC_FanMode, HVAC_Power, HVAC_Temp);

View File

@ -92,7 +92,8 @@ a_setoption = [[
"Use short Hass discovery messages", "Use short Hass discovery messages",
"Use wifi network scan at restart", "Use wifi network scan at restart",
"Use wifi network rescan regularly", "Use wifi network rescan regularly",
"","","","", "Add IR raw data to JSON message",
"","","",
"","","","", "","","","",
"","","","", "","","","",
"","","","", "","","","",