mirror of https://github.com/arendst/Tasmota.git
Support for multiple `IRsend` GPIOs
This commit is contained in:
parent
3d152699a2
commit
9f29e7c40d
|
@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
|
||||||
### Added
|
### Added
|
||||||
- Command ``SetOption45 1..250`` to change default bistable latching relay pulse length of 40 milliseconds
|
- 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 Modbus bridge adding commands ``ModbusSend``, ``ModbusBaudrate`` and ``ModbusSerialConfig`` (#16013)
|
||||||
|
- Support for multiple `IRsend` GPIOs
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- ESP32 LVGL library from v8.2.0 to v8.3.0
|
- 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_HASH "Hash"
|
||||||
#define D_JSON_IR_RAWDATA "RawData"
|
#define D_JSON_IR_RAWDATA "RawData"
|
||||||
#define D_JSON_IR_REPEAT "Repeat"
|
#define D_JSON_IR_REPEAT "Repeat"
|
||||||
|
#define D_JSON_IR_CHANNEL "Channel"
|
||||||
#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_PROTOCOL "Protocol"
|
#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_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_PCF8574 = 4; // Max number of PCF8574 devices
|
||||||
const uint8_t MAX_DS3502 = 4; // Max number of DS3502 digitsal potentiometer 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 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 MAX_RULE_SIZE = 512; // Max number of characters in rules
|
||||||
const uint16_t VL53LXX_MAX_SENSORS = 8; // Max number of VL53L0X sensors
|
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)
|
#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)
|
#if defined(USE_IR_RECEIVE) || defined(USE_IR_REMOTE_FULL)
|
||||||
AGPIO(GPIO_IRRECV), // IR receiver
|
AGPIO(GPIO_IRRECV), // IR receiver
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -80,6 +80,9 @@ const char kIrRemoteCommands[] PROGMEM = "|"
|
||||||
void (* const IrRemoteCommand[])(void) PROGMEM = {
|
void (* const IrRemoteCommand[])(void) PROGMEM = {
|
||||||
&CmndIrHvac, &CmndIrSend };
|
&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.
|
* Class used to make a compact IR Raw format.
|
||||||
*
|
*
|
||||||
|
@ -122,7 +125,6 @@ protected:
|
||||||
* IR Send
|
* IR Send
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
IRsend *irsend = nullptr;
|
|
||||||
// some ACs send toggle messages rather than state. we need to help IRremoteESP8266 keep track of the state
|
// 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)
|
// 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;
|
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.
|
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
|
StateModes strToStateMode(class JsonParserToken token, StateModes def); // declate to prevent errors related to ino files
|
||||||
|
|
||||||
void IrSendInit(void)
|
// initialize an `IRsend` static instance
|
||||||
{
|
// channel is the IRSEND channel number (from 0..)
|
||||||
irsend = new IRsend(Pin(GPIO_IRSEND), IR_SEND_INVERTED, IR_SEND_USE_MODULATION); // an IR led is at GPIO_IRSEND
|
class IRsend IrSendInitGPIO(int32_t channel = -1) {
|
||||||
irsend->begin();
|
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
|
// 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;
|
decode_results results;
|
||||||
|
|
||||||
if (irrecv->decode(&results)) {
|
if (irrecv->decode(&results)) {
|
||||||
|
@ -462,7 +471,14 @@ uint32_t IrRemoteCmndIrHvacJson(void)
|
||||||
|
|
||||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||||
if (stateMode == StateModes::SEND_ONLY || stateMode == StateModes::SEND_STORE) {
|
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);
|
bool success = ac.sendAc(state, irhvac_stateful && irac_prev_state.protocol == state.protocol ? &irac_prev_state : nullptr);
|
||||||
if (!success) { return IE_SYNTAX_IRHVAC; }
|
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 bits = root.getUInt(PSTR(D_JSON_IR_BITS), 0);
|
||||||
uint16_t repeat = root.getUInt(PSTR(D_JSON_IR_REPEAT), 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;
|
uint64_t data;
|
||||||
value = root[PSTR(D_JSON_IR_DATALSB)];
|
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);
|
// protocol, bits, ulltoa(data, dvalue, 10), Uint64toHex(data, hvalue, bits), repeat);
|
||||||
|
|
||||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
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 (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->enableIRIn(); }
|
||||||
|
|
||||||
if (!success) {
|
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 (!GC[i]) { return IE_INVALID_RAWDATA; }
|
||||||
}
|
}
|
||||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||||
|
IRsend irsend = IrSendInitGPIO();
|
||||||
for (uint32_t r = 0; r <= repeat; r++) {
|
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(); }
|
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->enableIRIn(); }
|
||||||
return IE_NO_ERROR;
|
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(); }
|
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||||
|
IRsend irsend = IrSendInitGPIO();
|
||||||
for (uint32_t r = 0; r <= repeat; r++) {
|
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);
|
// 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
|
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(); }
|
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
|
raw_array[i++] = parm[2]; // Trailing mark
|
||||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||||
|
IRsend irsend = IrSendInitGPIO();
|
||||||
for (uint32_t r = 0; r <= repeat; r++) {
|
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]);
|
// 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
|
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(); }
|
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 (0 == count) { return IE_INVALID_RAWDATA; }
|
||||||
|
|
||||||
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
if (!IR_RCV_WHILE_SENDING && (irrecv != nullptr)) { irrecv->disableIRIn(); }
|
||||||
|
IRsend irsend = IrSendInitGPIO();
|
||||||
for (uint32_t r = 0; r <= repeat; r++) {
|
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(); }
|
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;
|
uint8_t error = IE_SYNTAX_IRSEND;
|
||||||
|
|
||||||
if (XdrvMailbox.data_len) {
|
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
|
* Interface
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
@ -823,27 +849,23 @@ bool Xdrv05(uint8_t function)
|
||||||
{
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if (PinUsed(GPIO_IRSEND) || PinUsed(GPIO_IRRECV)) {
|
switch (function) {
|
||||||
switch (function) {
|
case FUNC_PRE_INIT:
|
||||||
case FUNC_PRE_INIT:
|
IrInit();
|
||||||
if (PinUsed(GPIO_IRSEND)) {
|
if (ir_recv_active) {
|
||||||
IrSendInit();
|
IrReceiveInit();
|
||||||
}
|
}
|
||||||
if (PinUsed(GPIO_IRRECV)) {
|
break;
|
||||||
IrReceiveInit();
|
case FUNC_EVERY_50_MSECOND:
|
||||||
}
|
if (ir_recv_active) {
|
||||||
break;
|
IrReceiveCheck(); // check if there's anything on IR side
|
||||||
case FUNC_EVERY_50_MSECOND:
|
}
|
||||||
if (PinUsed(GPIO_IRRECV)) {
|
break;
|
||||||
IrReceiveCheck(); // check if there's anything on IR side
|
case FUNC_COMMAND:
|
||||||
}
|
if (ir_send_active) {
|
||||||
break;
|
result = DecodeCommand(kIrRemoteCommands, IrRemoteCommand);
|
||||||
case FUNC_COMMAND:
|
}
|
||||||
if (PinUsed(GPIO_IRSEND)) {
|
break;
|
||||||
result = DecodeCommand(kIrRemoteCommands, IrRemoteCommand);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue