mirror of https://github.com/arendst/Tasmota.git
Merge pull request #16138 from s-hadinger/irsend_multi
Support for multiple `IRsend` GPIOs
This commit is contained in:
commit
ac4d7c1761
|
@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
|
|||
### Added
|
||||
- Command ``SetOption45 1..250`` to change default bistable latching relay pulse length of 40 milliseconds
|
||||
- Support for Modbus bridge adding commands ``ModbusSend``, ``ModbusBaudrate`` and ``ModbusSerialConfig`` (#16013)
|
||||
- Support for multiple `IRsend` GPIOs
|
||||
|
||||
### Changed
|
||||
- ESP32 LVGL library from v8.2.0 to v8.3.0
|
||||
|
|
|
@ -511,6 +511,7 @@
|
|||
#define D_JSON_IR_HASH "Hash"
|
||||
#define D_JSON_IR_RAWDATA "RawData"
|
||||
#define D_JSON_IR_REPEAT "Repeat"
|
||||
#define D_JSON_IR_CHANNEL "Channel"
|
||||
#define D_CMND_IRHVAC "IRHVAC"
|
||||
#define D_JSON_IRHVAC_VENDOR "Vendor"
|
||||
#define D_JSON_IRHVAC_PROTOCOL "Protocol"
|
||||
|
|
|
@ -93,6 +93,7 @@ const uint8_t MAX_SHUTTERS = 4; // Max number of shutters
|
|||
const uint8_t MAX_SHUTTER_KEYS = 4; // Max number of shutter keys or buttons
|
||||
const uint8_t MAX_PCF8574 = 4; // Max number of PCF8574 devices
|
||||
const uint8_t MAX_DS3502 = 4; // Max number of DS3502 digitsal potentiometer devices
|
||||
const uint8_t MAX_IRSEND = 16; // Max number of IRSEND GPIOs
|
||||
const uint8_t MAX_RULE_SETS = 3; // Max number of rule sets of size 512 characters
|
||||
const uint16_t MAX_RULE_SIZE = 512; // Max number of characters in rules
|
||||
const uint16_t VL53LXX_MAX_SENSORS = 8; // Max number of VL53L0X sensors
|
||||
|
|
|
@ -721,7 +721,7 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
|||
\*-------------------------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(USE_IR_REMOTE) || defined(USE_IR_REMOTE_FULL)
|
||||
AGPIO(GPIO_IRSEND), // IR remote
|
||||
AGPIO(GPIO_IRSEND) + MAX_IRSEND, // IR remote
|
||||
#if defined(USE_IR_RECEIVE) || defined(USE_IR_REMOTE_FULL)
|
||||
AGPIO(GPIO_IRRECV), // IR receiver
|
||||
#endif
|
||||
|
|
|
@ -80,6 +80,9 @@ const char kIrRemoteCommands[] PROGMEM = "|"
|
|||
void (* const IrRemoteCommand[])(void) PROGMEM = {
|
||||
&CmndIrHvac, &CmndIrSend };
|
||||
|
||||
bool ir_send_active = false; // do we have a GPIO configured for IR_SEND
|
||||
bool ir_recv_active = false; // do we have a GPIO configured for IR_RECV
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Class used to make a compact IR Raw format.
|
||||
*
|
||||
|
@ -122,7 +125,6 @@ protected:
|
|||
* IR Send
|
||||
\*********************************************************************************************/
|
||||
|
||||
IRsend *irsend = nullptr;
|
||||
// some ACs send toggle messages rather than state. we need to help IRremoteESP8266 keep track of the state
|
||||
// have a flag that is a variable, can be later used to convert this functionality to an option (as in SetOptionXX)
|
||||
bool irhvac_stateful = true;
|
||||
|
@ -134,10 +136,18 @@ enum class StateModes { SEND_ONLY, // just send the IR signal, this is the defau
|
|||
SEND_STORE }; // send IR signal but also update stored state. this is for use cases when there is just one transmitter and there is no receiver in the device.
|
||||
StateModes strToStateMode(class JsonParserToken token, StateModes def); // declate to prevent errors related to ino files
|
||||
|
||||
void IrSendInit(void)
|
||||
{
|
||||
irsend = new IRsend(Pin(GPIO_IRSEND), IR_SEND_INVERTED, IR_SEND_USE_MODULATION); // an IR led is at GPIO_IRSEND
|
||||
irsend->begin();
|
||||
// initialize an `IRsend` static instance
|
||||
// channel is the IRSEND channel number (from 0..)
|
||||
class IRsend IrSendInitGPIO(int32_t channel = -1) {
|
||||
if (channel < 0) { channel = GPIO_ANY; } // take first available GPIO
|
||||
int32_t pin = Pin(GPIO_IRSEND, channel);
|
||||
if (pin < 0) {
|
||||
pin = Pin(GPIO_IRSEND, GPIO_ANY);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("IR : GPIO 'IRsend-%i' not assigned, revert to GPIO %i"), channel+1, pin);
|
||||
}
|
||||
IRsend irsend(pin, IR_SEND_INVERTED, IR_SEND_USE_MODULATION); // an IR led is at GPIO_IRSEND
|
||||
irsend.begin();
|
||||
return irsend;
|
||||
}
|
||||
|
||||
// from https://stackoverflow.com/questions/2602823/in-c-c-whats-the-simplest-way-to-reverse-the-order-of-bits-in-a-byte
|
||||
|
@ -279,8 +289,7 @@ void sendIRJsonState(const struct decode_results &results) {
|
|||
}
|
||||
}
|
||||
|
||||
void IrReceiveCheck(void)
|
||||
{
|
||||
void IrReceiveCheck(void) {
|
||||
decode_results results;
|
||||
|
||||
if (irrecv->decode(&results)) {
|
||||
|
@ -462,7 +471,14 @@ uint32_t IrRemoteCmndIrHvacJson(void)
|
|||
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||
if (stateMode == StateModes::SEND_ONLY || stateMode == StateModes::SEND_STORE) {
|
||||
IRac ac(Pin(GPIO_IRSEND), IR_SEND_INVERTED, IR_SEND_USE_MODULATION);
|
||||
int8_t channel = root.getUInt(PSTR(D_JSON_IR_CHANNEL), 1) - 1;
|
||||
if (channel < 0) { channel = GPIO_ANY; } // take first available GPIO
|
||||
int32_t pin = Pin(GPIO_IRSEND, channel);
|
||||
if (pin < 0) {
|
||||
pin = Pin(GPIO_IRSEND, GPIO_ANY);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("IR : GPIO 'IRsend-%i' not assigned, revert to GPIO %i"), channel+1, pin);
|
||||
}
|
||||
IRac ac(pin, IR_SEND_INVERTED, IR_SEND_USE_MODULATION);
|
||||
bool success = ac.sendAc(state, irhvac_stateful && irac_prev_state.protocol == state.protocol ? &irac_prev_state : nullptr);
|
||||
if (!success) { return IE_SYNTAX_IRHVAC; }
|
||||
}
|
||||
|
@ -511,6 +527,7 @@ uint32_t IrRemoteCmndIrSendJson(void)
|
|||
|
||||
uint16_t bits = root.getUInt(PSTR(D_JSON_IR_BITS), 0);
|
||||
uint16_t repeat = root.getUInt(PSTR(D_JSON_IR_REPEAT), 0);
|
||||
int8_t channel = root.getUInt(PSTR(D_JSON_IR_CHANNEL), 1) - 1;
|
||||
|
||||
uint64_t data;
|
||||
value = root[PSTR(D_JSON_IR_DATALSB)];
|
||||
|
@ -528,7 +545,8 @@ uint32_t IrRemoteCmndIrSendJson(void)
|
|||
// protocol, bits, ulltoa(data, dvalue, 10), Uint64toHex(data, hvalue, bits), repeat);
|
||||
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||
bool success = irsend->send(protocol, data, bits, repeat);
|
||||
IRsend irsend = IrSendInitGPIO(channel);
|
||||
bool success = irsend.send(protocol, data, bits, repeat);
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->enableIRIn(); }
|
||||
|
||||
if (!success) {
|
||||
|
@ -553,8 +571,9 @@ uint32_t IrRemoteSendGC(char ** pp, uint32_t count, uint32_t repeat) {
|
|||
if (!GC[i]) { return IE_INVALID_RAWDATA; }
|
||||
}
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||
IRsend irsend = IrSendInitGPIO();
|
||||
for (uint32_t r = 0; r <= repeat; r++) {
|
||||
irsend->sendGC(GC, count+1);
|
||||
irsend.sendGC(GC, count+1);
|
||||
}
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->enableIRIn(); }
|
||||
return IE_NO_ERROR;
|
||||
|
@ -608,11 +627,12 @@ uint32_t IrRemoteSendRawFormatted(char ** pp, uint32_t count, uint32_t repeat) {
|
|||
}
|
||||
}
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||
IRsend irsend = IrSendInitGPIO();
|
||||
for (uint32_t r = 0; r <= repeat; r++) {
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("sendRaw count=%d, space=%d, mark=%d, freq=%d"), count, space, mark, freq);
|
||||
irsend->sendRaw(raw_array, i, freq);
|
||||
irsend.sendRaw(raw_array, i, freq);
|
||||
if (r < repeat) { // if it's not the last message
|
||||
irsend->space(40000); // since we don't know the inter-message gap, place an arbitrary 40ms gap
|
||||
irsend.space(40000); // since we don't know the inter-message gap, place an arbitrary 40ms gap
|
||||
}
|
||||
}
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->enableIRIn(); }
|
||||
|
@ -635,11 +655,12 @@ uint32_t IrRemoteSendRawFormatted(char ** pp, uint32_t count, uint32_t repeat) {
|
|||
}
|
||||
raw_array[i++] = parm[2]; // Trailing mark
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||
IRsend irsend = IrSendInitGPIO();
|
||||
for (uint32_t r = 0; r <= repeat; r++) {
|
||||
// AddLog(LOG_LEVEL_DEBUG, PSTR("sendRaw %d %d %d %d %d %d"), raw_array[0], raw_array[1], raw_array[2], raw_array[3], raw_array[4], raw_array[5]);
|
||||
irsend->sendRaw(raw_array, i, freq);
|
||||
irsend.sendRaw(raw_array, i, freq);
|
||||
if (r < repeat) { // if it's not the last message
|
||||
irsend->space(inter_message); // since we don't know the inter-message gap, place an arbitrary 40ms gap
|
||||
irsend.space(inter_message); // since we don't know the inter-message gap, place an arbitrary 40ms gap
|
||||
}
|
||||
}
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->enableIRIn(); }
|
||||
|
@ -712,8 +733,9 @@ uint32_t IrRemoteSendRawStandard(char ** pp, uint16_t freq, uint32_t count, uint
|
|||
if (0 == count) { return IE_INVALID_RAWDATA; }
|
||||
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||
IRsend irsend = IrSendInitGPIO();
|
||||
for (uint32_t r = 0; r <= repeat; r++) {
|
||||
irsend->sendRaw(arr, count, freq);
|
||||
irsend.sendRaw(arr, count, freq);
|
||||
}
|
||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->enableIRIn(); }
|
||||
|
||||
|
@ -772,8 +794,7 @@ uint32_t IrRemoteCmndIrSendRaw(void)
|
|||
}
|
||||
}
|
||||
|
||||
void CmndIrSend(void)
|
||||
{
|
||||
void CmndIrSend(void) {
|
||||
uint8_t error = IE_SYNTAX_IRSEND;
|
||||
|
||||
if (XdrvMailbox.data_len) {
|
||||
|
@ -815,6 +836,11 @@ void IrRemoteCmndResponse(uint32_t error)
|
|||
}
|
||||
}
|
||||
|
||||
void IrInit(void) {
|
||||
ir_send_active = PinUsed(GPIO_IRSEND, GPIO_ANY);
|
||||
ir_recv_active = PinUsed(GPIO_IRRECV, GPIO_ANY);
|
||||
}
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Interface
|
||||
\*********************************************************************************************/
|
||||
|
@ -823,27 +849,23 @@ bool Xdrv05(uint8_t function)
|
|||
{
|
||||
bool result = false;
|
||||
|
||||
if (PinUsed(GPIO_IRSEND) || PinUsed(GPIO_IRRECV)) {
|
||||
switch (function) {
|
||||
case FUNC_PRE_INIT:
|
||||
if (PinUsed(GPIO_IRSEND)) {
|
||||
IrSendInit();
|
||||
}
|
||||
if (PinUsed(GPIO_IRRECV)) {
|
||||
IrReceiveInit();
|
||||
}
|
||||
break;
|
||||
case FUNC_EVERY_50_MSECOND:
|
||||
if (PinUsed(GPIO_IRRECV)) {
|
||||
IrReceiveCheck(); // check if there's anything on IR side
|
||||
}
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
if (PinUsed(GPIO_IRSEND)) {
|
||||
result = DecodeCommand(kIrRemoteCommands, IrRemoteCommand);
|
||||
}
|
||||
break;
|
||||
}
|
||||
switch (function) {
|
||||
case FUNC_PRE_INIT:
|
||||
IrInit();
|
||||
if (ir_recv_active) {
|
||||
IrReceiveInit();
|
||||
}
|
||||
break;
|
||||
case FUNC_EVERY_50_MSECOND:
|
||||
if (ir_recv_active) {
|
||||
IrReceiveCheck(); // check if there's anything on IR side
|
||||
}
|
||||
break;
|
||||
case FUNC_COMMAND:
|
||||
if (ir_send_active) {
|
||||
result = DecodeCommand(kIrRemoteCommands, IrRemoteCommand);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue