From 95bed62bd12fa94f147f4931db9c81070653eb55 Mon Sep 17 00:00:00 2001 From: halfbakery Date: Mon, 29 Jun 2020 19:38:50 +0200 Subject: [PATCH 01/91] Do not announce shutter controlling relays to Home Assistant --- tasmota/xdrv_12_home_assistant.ino | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index df53084a8..5163710cf 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -208,6 +208,7 @@ void HAssAnnounceRelayLight(void) uint8_t TuyaRel = 0; uint8_t TuyaRelInv = 0; uint8_t TuyaDim = 0; + uint8_t shutter_mask = 0; #ifdef ESP8266 if (PWM_DIMMER == my_module_type ) { PwmMod = true; } // @@ -225,6 +226,17 @@ void HAssAnnounceRelayLight(void) if (!PwmMulti) { max_lights = 2;} } +#ifdef USE_SHUTTER + if (Settings.flag3.shutter_mode) { + for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + if (Settings.shutter_startrelay[i] > 0 && Settings.shutter_startrelay[i] <= MAX_RELAYS) { + bitSet(shutter_mask, Settings.shutter_startrelay[i] -1); + bitSet(shutter_mask, Settings.shutter_startrelay[i]); + } + } + } +#endif + for (uint32_t i = 1; i <= MAX_RELAYS; i++) { @@ -248,7 +260,9 @@ void HAssAnnounceRelayLight(void) snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/%s/%s/config"), (is_topic_light) ? "light" : "switch", unique_id); - if ((i < Light.device) && !RelayX) { + if (bitRead(shutter_mask, i-1)) { + // suppress shutter relays + } else if ((i < Light.device) && !RelayX) { err_flag = true; AddLog_P2(LOG_LEVEL_ERROR, PSTR("%s"), kHAssError2); } else { From 50a9258eac90d32b2ffaca089c4c48982bce6d32 Mon Sep 17 00:00:00 2001 From: halfbakery Date: Mon, 29 Jun 2020 19:44:26 +0200 Subject: [PATCH 02/91] Home Assistant shutter autodiscovery --- tasmota/xdrv_12_home_assistant.ino | 60 ++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index 5163710cf..005daadfc 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -108,6 +108,21 @@ const char HASS_DISCOVER_LIGHT_SCHEME[] PROGMEM = "\"fx_val_tpl\":\"{{value_json." D_CMND_SCHEME "}}\"," "\"fx_list\":[\"0\",\"1\",\"2\",\"3\",\"4\"]"; // string list with reference to scheme parameter. +const char HASS_DISCOVER_SHUTTER_BASE[] PROGMEM = + ",\"cmd_t\":\"%s\"," // cmnd/%topic%/Backlog + "\"pl_open\":\"ShutterOpen%d\"," // 1 + "\"pl_cls\":\"ShutterClose%d\"," // 1 + "\"pl_stop\":\"ShutterStop%d\"," // 1 + "\"opt\":false," + "\"ret\":false," + "\"qos\":1"; + +const char HASS_DISCOVER_SHUTTER_POS[] PROGMEM = + ",\"pos_t\":\"%s%d\"," // stat/%topic%/SHUTTER1 + "\"pos_clsd\":0," + "\"pos_open\":100," + "\"set_pos_t\":\"%s%d\""; // cmnd/%topic%/ShutterPosition1 + const char HASS_DISCOVER_SENSOR_HASS_STATUS[] PROGMEM = ",\"json_attr_t\":\"%s\"," "\"unit_of_meas\":\"%%\"," @@ -726,6 +741,48 @@ void HAssAnnounceSensors(void) } while (hass_xsns_index != 0); } +void HAssAnnounceShutters(void) +{ +#ifdef USE_SHUTTER + char stopic[TOPSZ]; + char stemp1[TOPSZ]; + char stemp2[TOPSZ]; + char unique_id[30]; + + for (uint32_t i = 0; i < MAX_SHUTTERS; i++) { + mqtt_data[0] = '\0'; // Clear retained message + + snprintf_P(unique_id, sizeof(unique_id), PSTR("%06X_SHT_%d"), ESP_getChipId(), i + 1); + snprintf_P(stopic, sizeof(stopic), PSTR(HOME_ASSISTANT_DISCOVERY_PREFIX "/cover/%s/config"), unique_id); + + if (Settings.flag.hass_discovery && Settings.flag3.shutter_mode && Settings.shutter_startrelay[i] > 0 && Settings.shutter_startrelay[i] <= MAX_RELAYS) { + if (i > MAX_FRIENDLYNAMES) { + snprintf_P(stemp1, sizeof(stemp1), PSTR("%s Shutter %d"), SettingsText(SET_DEVICENAME), i + 1); + } else { + snprintf_P(stemp1, sizeof(stemp1), PSTR("%s"), SettingsText(SET_FRIENDLYNAME1 + i)); + } + GetTopic_P(stemp2, TELE, mqtt_topic, D_RSLT_STATE); + Response_P(HASS_DISCOVER_BASE, stemp1, stemp2); + + GetTopic_P(stemp1, TELE, mqtt_topic, S_LWT); + TryResponseAppend_P(HASS_DISCOVER_SENSOR_LWT, stemp1); + + GetTopic_P(stemp1, CMND, mqtt_topic, PSTR("Backlog")); + TryResponseAppend_P(HASS_DISCOVER_SHUTTER_BASE, stemp1, i + 1, i + 1, i + 1); + + GetTopic_P(stemp1, STAT, mqtt_topic, PSTR("SHUTTER")); + GetTopic_P(stemp2, CMND, mqtt_topic, PSTR("ShutterPosition")); + TryResponseAppend_P(HASS_DISCOVER_SHUTTER_POS, stemp1, i + 1, stemp2, i + 1); + + TryResponseAppend_P(HASS_DISCOVER_DEVICE_INFO_SHORT, unique_id, ESP_getChipId()); + TryResponseAppend_P(PSTR("}")); + } + + MqttPublish(stopic, true); + } +#endif +} + void HAssAnnounceDeviceInfoAndStatusSensor(void) { char stopic[TOPSZ]; @@ -801,6 +858,9 @@ void HAssDiscovery(void) // Send info about relays and lights HAssAnnounceRelayLight(); + // Send info about shutters + HAssAnnounceShutters(); + // Send info about status sensor HAssAnnounceDeviceInfoAndStatusSensor(); } From 63242de249de891e8a2869de6ba8370885f319f6 Mon Sep 17 00:00:00 2001 From: George Date: Sun, 19 Jul 2020 20:34:43 +1000 Subject: [PATCH 03/91] Serialsend6 * Adds serialsend6, allowing sending of binary data with comma-delimited string of decimal numbers. --- tasmota/support.ino | 11 +++++++++++ tasmota/support_command.ino | 3 +++ 2 files changed, 14 insertions(+) diff --git a/tasmota/support.ino b/tasmota/support.ino index 50cc4f920..ae42f3840 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -906,6 +906,17 @@ void SerialSendRaw(char *codes) } } +// values is a comma-delimited string: e.g. "72,101,108,108,111,32,87,111,114,108,100,33,10" +void SerialSendDecimal(char *values) +{ + char* &p; + uint8_t code; + for (str = strtok_r(values, ",", &p); str; str = strtok_r(nullptr, ",", &p)) { + code = (uint8_t)atoi(str); + Serial.write(code); + } +} + uint32_t GetHash(const char *buffer, size_t size) { uint32_t hash = 0; diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index abd75960e..5854c0ed1 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -1354,6 +1354,9 @@ void CmndSerialSend(void) else if (5 == XdrvMailbox.index) { SerialSendRaw(RemoveSpace(XdrvMailbox.data)); // "AA004566" as hex values } + else if (6 == XdrvMailbox.index) { + SerialSendDecimal(XdrvMailbox.data); + } ResponseCmndDone(); } } From 8a4a0d67ff415ca59072f999a2ce1815304894d4 Mon Sep 17 00:00:00 2001 From: George Date: Mon, 20 Jul 2020 10:08:20 +1000 Subject: [PATCH 04/91] serialsend6 - fixes Forgot to fix top condition --- tasmota/support_command.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index 5854c0ed1..61a0962b4 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -1334,7 +1334,7 @@ void CmndSerialConfig(void) void CmndSerialSend(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) { SetSeriallog(LOG_LEVEL_NONE); Settings.flag.mqtt_serial = 1; // CMND_SERIALSEND and CMND_SERIALLOG Settings.flag.mqtt_serial_raw = (XdrvMailbox.index > 3) ? 1 : 0; // CMND_SERIALSEND3 From 2ced749e4d48bdbdb8e0a6b7246bb8760499c9d2 Mon Sep 17 00:00:00 2001 From: George Date: Mon, 20 Jul 2020 10:14:01 +1000 Subject: [PATCH 05/91] serialsend6 - more fixes oops --- tasmota/support.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/support.ino b/tasmota/support.ino index ae42f3840..2e36793b0 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -909,9 +909,9 @@ void SerialSendRaw(char *codes) // values is a comma-delimited string: e.g. "72,101,108,108,111,32,87,111,114,108,100,33,10" void SerialSendDecimal(char *values) { - char* &p; + char *p; uint8_t code; - for (str = strtok_r(values, ",", &p); str; str = strtok_r(nullptr, ",", &p)) { + for (char* str = strtok_r(values, ",", &p); str; str = strtok_r(nullptr, ",", &p)) { code = (uint8_t)atoi(str); Serial.write(code); } From 1b380b5bc9e2a81c581ddf320b8dc121cdbcee42 Mon Sep 17 00:00:00 2001 From: Staars Date: Mon, 20 Jul 2020 08:51:17 +0200 Subject: [PATCH 06/91] update MQTT presentation --- tasmota/xsns_62_MI_ESP32.ino | 312 ++++++++++++++++++++++++++--------- 1 file changed, 233 insertions(+), 79 deletions(-) diff --git a/tasmota/xsns_62_MI_ESP32.ino b/tasmota/xsns_62_MI_ESP32.ino index fbdc5bf6b..612474172 100644 --- a/tasmota/xsns_62_MI_ESP32.ino +++ b/tasmota/xsns_62_MI_ESP32.ino @@ -66,14 +66,21 @@ struct { uint32_t willReadBatt:1; uint32_t shallSetUnit:1; uint32_t willSetUnit:1; + uint32_t shallTriggerTele:1; uint32_t triggeredTele:1; - uint32_t shallClearResults:1; - uint32_t directMQTT:1; // TODO: direct bridging of every single sensor message + uint32_t shallClearResults:1; // BLE scan results } mode; struct { uint8_t sensor; // points to to the number 0...255 } state; + struct { + uint32_t allwaysAggregate:1; + uint32_t showRSSI:1; + uint32_t ignoreBogusBattery:1; + uint32_t noSummary:1; + uint32_t minimalSummary:1; + } option; } MI32; #pragma pack(1) // byte-aligned structures to read the sensor data @@ -162,8 +169,39 @@ struct mi_sensor_t{ uint8_t lastCnt; //device generated counter of the packet uint8_t shallSendMQTT; uint8_t MAC[6]; + union { + struct { + uint32_t temp:1; + uint32_t hum:1; + uint32_t tempHum:1; //every hum sensor has temp too, easier to use Tasmota dew point functions + uint32_t lux:1; + uint32_t moist:1; + uint32_t fert:1; + uint32_t bat:1; + uint32_t NMT:1; + uint32_t PIR:1; + uint32_t Btn:1; + }; + uint32_t raw; + } feature; + union { + struct { + uint32_t temp:1; + uint32_t hum:1; + uint32_t tempHum:1; //can be combined from the sensor + uint32_t lux:1; + uint32_t moist:1; + uint32_t fert:1; + uint32_t bat:1; + uint32_t NMT:1; + uint32_t motion:1; + uint32_t noMotion:1; + uint32_t Btn:1; + }; + uint32_t raw; + } eventType; + int rssi; - // uint8_t showedUp; uint32_t lastTime; uint32_t lux; float temp; //Flora, MJ_HT_V1, LYWSD0x, CGx @@ -179,7 +217,6 @@ struct mi_sensor_t{ struct { uint16_t events; //"alarms" since boot uint32_t NMT; // no motion time in seconds for the MJYD2S - uint8_t eventType; //internal type of actual event for the MJYD2S -> 1: PIR, 2: No PIR, 3: NMT }; uint16_t Btn; }; @@ -523,7 +560,8 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter) mi_sensor_t _newSensor; memcpy(_newSensor.MAC,_MAC, sizeof(_MAC)); _newSensor.type = _type; - + _newSensor.eventType.raw = 0; + _newSensor.feature.raw = 0; _newSensor.temp =NAN; _newSensor.bat=0x00; _newSensor.rssi=0xffff; @@ -534,14 +572,34 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter) _newSensor.moisture =0xff; _newSensor.fertility =0xffff; _newSensor.firmware[0]='\0'; + _newSensor.feature.temp=1; + _newSensor.feature.moist=1; + _newSensor.feature.fert=1; + _newSensor.feature.lux=1; + _newSensor.feature.bat=1; break; - case NLIGHT: case MJYD2S: + case NLIGHT: + _newSensor.events=0x00; + _newSensor.feature.PIR=1; + _newSensor.feature.NMT=1; + break; + case MJYD2S: _newSensor.NMT=0; _newSensor.events=0x00; - _newSensor.eventType=0x00; + _newSensor.feature.PIR=1; + _newSensor.feature.NMT=1; + _newSensor.feature.lux=1; + _newSensor.feature.bat=1; + break; + case YEERC: + _newSensor.feature.Btn=1; break; default: _newSensor.hum=NAN; + _newSensor.feature.temp=1; + _newSensor.feature.hum=1; + _newSensor.feature.tempHum=1; + _newSensor.feature.bat=1; break; } MIBLEsensors.push_back(_newSensor); @@ -554,7 +612,7 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter) * */ void MI32triggerTele(void){ - MI32.mode.triggeredTele = true; + MI32.mode.triggeredTele = 1; mqtt_data[0] = '\0'; if (MqttShowSensor()) { MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); @@ -576,6 +634,13 @@ void MI32Init(void) { MI32.mode.init = 1; MI32.period = Settings.tele_period; + //test section for options + MI32.option.allwaysAggregate = 1; + MI32.option.showRSSI = 1; + MI32.option.ignoreBogusBattery = 1; // from advertisements + MI32.option.noSummary = 0; + MI32.option.minimalSummary = 1; + MI32StartScanTask(); // Let's get started !! } return; @@ -603,7 +668,14 @@ void MI32StartTask(uint32_t task){ break; case MI32_TASK_BATT: if (MI32.mode.willReadBatt == 1) return; - MI32StartBatteryTask(); + switch(MIBLEsensors[MI32.state.sensor].type) { + case LYWSD03MMC: case MHOC401: // the "original" battery value is crap ... + MI32.mode.willReadBatt = 1; + MI32StartSensorTask(); // ... but the part of the temp/hum-message is good! + break; + default: + MI32StartBatteryTask(); + } break; case MI32_TASK_UNIT: if (MI32.mode.shallSetUnit == 0) return; @@ -720,6 +792,7 @@ void MI32SensorTask(void *pvParameters){ MI32Client->disconnect(); // NimBLEDevice::deleteClient(MI32Client); MI32.mode.willConnect = 0; + MI32.mode.willReadBatt = 0; //could be a "battery task" for LYWSD03MMC or MHO-C401 vTaskDelay(100/ portTICK_PERIOD_MS); vTaskDelete( NULL ); } @@ -1054,7 +1127,7 @@ void MI32parseMiBeacon(char * _buf, uint32_t _slot, uint16_t _bufSize){ // MIBLEsensors[_slot].lastTime = millis(); // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("MI32: MJYD2S secondary PIR")); // MIBLEsensors[_slot].NMT = 0; - // MI32triggerTele(); + // MI32.mode.shallTriggerTele = 1; // } } break; @@ -1067,56 +1140,63 @@ if (MIBLEsensors[_slot].type==NLIGHT){ } if(MIBLEsensors[_slot].type==6){ - DEBUG_SENSOR_LOG(PSTR("LYWSD03 and CGD1 no support for MiBeacon, type %u"),MIBLEsensors[_slot].type); + DEBUG_SENSOR_LOG(PSTR("CGD1 no support for MiBeacon, type %u"),MIBLEsensors[_slot].type); return; } AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s at slot %u"), kMI32DeviceType[MIBLEsensors[_slot].type-1],_slot); switch(_beacon.type){ case 0x01: MIBLEsensors[_slot].Btn=_beacon.Btn.num + (_beacon.Btn.longPress/2)*6; - MIBLEsensors[_slot].shallSendMQTT = 1; - MI32triggerTele(); + MIBLEsensors[_slot].eventType.Btn = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 1: U16: %u Button"), MIBLEsensors[_slot].Btn ); break; case 0x04: _tempFloat=(float)(_beacon.temp)/10.0f; if(_tempFloat<60){ - MIBLEsensors[_slot].temp=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 4: temp updated")); + MIBLEsensors[_slot].temp=_tempFloat; + MIBLEsensors[_slot].eventType.temp = 1; + DEBUG_SENSOR_LOG(PSTR("Mode 4: temp updated")); } // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 4: U16: %u Temp"), _beacon.temp ); break; case 0x06: _tempFloat=(float)(_beacon.hum)/10.0f; if(_tempFloat<101){ - MIBLEsensors[_slot].hum=_tempFloat; - DEBUG_SENSOR_LOG(PSTR("Mode 6: hum updated")); + MIBLEsensors[_slot].hum=_tempFloat; + MIBLEsensors[_slot].eventType.hum = 1; + DEBUG_SENSOR_LOG(PSTR("Mode 6: hum updated")); } // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 6: U16: %u Hum"), _beacon.hum); break; case 0x07: MIBLEsensors[_slot].lux=_beacon.lux & 0x00ffffff; if(MIBLEsensors[_slot].type==MJYD2S){ - MIBLEsensors[_slot].eventType = 2; //No PIR - MIBLEsensors[_slot].shallSendMQTT = 1; - MIBLEsensors[_slot].lastTime = millis(); - MI32triggerTele(); + MIBLEsensors[_slot].eventType.noMotion = 1; } + MIBLEsensors[_slot].eventType.lux = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 7: U24: %u Lux"), _beacon.lux & 0x00ffffff); break; case 0x08: - MIBLEsensors[_slot].moisture=_beacon.moist; - DEBUG_SENSOR_LOG(PSTR("Mode 8: moisture updated")); + MIBLEsensors[_slot].moisture=_beacon.moist; + MIBLEsensors[_slot].eventType.moist = 1; + DEBUG_SENSOR_LOG(PSTR("Mode 8: moisture updated")); // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 8: U8: %u Moisture"), _beacon.moist); break; case 0x09: MIBLEsensors[_slot].fertility=_beacon.fert; + MIBLEsensors[_slot].eventType.fert = 1; DEBUG_SENSOR_LOG(PSTR("Mode 9: fertility updated")); // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 9: U16: %u Fertility"), _beacon.fert); break; case 0x0a: + if(MI32.option.ignoreBogusBattery){ + if(MIBLEsensors[_slot].type==LYWSD03MMC || MIBLEsensors[_slot].type==MHOC401){ + break; + } + } if(_beacon.bat<101){ MIBLEsensors[_slot].bat = _beacon.bat; + MIBLEsensors[_slot].eventType.bat = 1; DEBUG_SENSOR_LOG(PSTR("Mode a: bat updated")); } // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode a: U8: %u %%"), _beacon.bat); @@ -1132,40 +1212,39 @@ if (MIBLEsensors[_slot].type==NLIGHT){ MIBLEsensors[_slot].hum = _tempFloat; DEBUG_SENSOR_LOG(PSTR("Mode d: hum updated")); } + MIBLEsensors[_slot].eventType.tempHum = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode d: U16: %x Temp U16: %x Hum"), _beacon.HT.temp, _beacon.HT.hum); break; #ifdef USE_MI_DECRYPTION case 0x0f: if (_beacon.ten!=0) break; - MIBLEsensors[_slot].eventType = 1; //PIR - MIBLEsensors[_slot].shallSendMQTT = 1; + MIBLEsensors[_slot].eventType.motion = 1; MIBLEsensors[_slot].lastTime = millis(); MIBLEsensors[_slot].events++; MIBLEsensors[_slot].lux = _beacon.lux; + MIBLEsensors[_slot].eventType.lux = 1; MIBLEsensors[_slot].NMT = 0; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("PIR: primary"),MIBLEsensors[_slot].lux ); - MI32triggerTele(); break; case 0x17: MIBLEsensors[_slot].NMT = _beacon.NMT; - MIBLEsensors[_slot].eventType = 3; // NMT - MIBLEsensors[_slot].shallSendMQTT = 1; + MIBLEsensors[_slot].eventType.NMT = 1; // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("Mode 17: NMT: %u seconds"), _beacon.NMT); - MI32triggerTele(); break; #endif //USE_MI_DECRYPTION default: if (MIBLEsensors[_slot].type==NLIGHT){ - MIBLEsensors[_slot].eventType = 1; //PIR - MIBLEsensors[_slot].shallSendMQTT = 1; + MIBLEsensors[_slot].eventType.motion = 1; //PIR MIBLEsensors[_slot].events++; MIBLEsensors[_slot].NMT = 0; MIBLEsensors[_slot].lastTime = millis(); // AddLog_P2(LOG_LEVEL_DEBUG,PSTR("PIR: primary"),MIBLEsensors[_slot].lux ); - MI32triggerTele(); } break; } + if(MIBLEsensors[_slot].eventType.raw == 0) return; + MIBLEsensors[_slot].shallSendMQTT = 1; + MI32.mode.shallTriggerTele = 1; } void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int rssi){ // no MiBeacon @@ -1183,11 +1262,13 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int rssi _tempFloat=(float)(_packet.temp)/10.0f; if(_tempFloat<60){ MIBLEsensors.at(_slot).temp = _tempFloat; + MIBLEsensors[_slot].eventType.temp = 1; DEBUG_SENSOR_LOG(PSTR("CGD1: temp updated")); } _tempFloat=(float)(_packet.hum)/10.0f; if(_tempFloat<100){ MIBLEsensors.at(_slot).hum = _tempFloat; + MIBLEsensors[_slot].eventType.hum = 1; DEBUG_SENSOR_LOG(PSTR("CGD1: hum updated")); } DEBUG_SENSOR_LOG(PSTR("CGD1: U16: %x Temp U16: %x Hum"), _packet.temp, _packet.hum); @@ -1195,12 +1276,16 @@ void MI32parseCGD1Packet(char * _buf, uint32_t length, uint8_t addr[6], int rssi case 0x0102: if(_packet.bat<101){ MIBLEsensors.at(_slot).bat = _packet.bat; + MIBLEsensors[_slot].eventType.bat = 1; DEBUG_SENSOR_LOG(PSTR("Mode a: bat updated")); } break; default: DEBUG_SENSOR_LOG(PSTR("MI32: unexpected CGD1-packet")); } + if(MIBLEsensors[_slot].eventType.raw == 0) return; + MIBLEsensors[_slot].shallSendMQTT = 1; + MI32.mode.shallTriggerTele = 1; } void MI32ParseResponse(char *buf, uint16_t bufsize, uint8_t addr[6], int rssi) { @@ -1241,9 +1326,14 @@ void MI32readHT_LY(char *_buf){ MIBLEsensors[_slot].hum = _tempFloat; DEBUG_SENSOR_LOG(PSTR("LYWSD0x: hum updated")); } + MIBLEsensors[_slot].eventType.tempHum = 1; if (MIBLEsensors[_slot].type == LYWSD03MMC || MIBLEsensors[_slot].type == MHOC401){ MIBLEsensors[_slot].bat = ((float)LYWSD0x_HT.volt-2100.0f)/12.0f; + MI32.mode.willReadBatt = 0; + MIBLEsensors[_slot].eventType.bat = 1; } + MIBLEsensors[_slot].shallSendMQTT = 1; + MI32.mode.shallTriggerTele = 1; } } @@ -1260,12 +1350,27 @@ bool MI32readBat(char *_buf){ MIBLEsensors[_slot].firmware[5] = '\0'; AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s: Firmware: %s"),D_CMND_MI32,MIBLEsensors[_slot].firmware); } - return true; + MIBLEsensors[_slot].eventType.bat = 1; + MIBLEsensors[_slot].shallSendMQTT = 1; + MI32.mode.shallTriggerTele = 1; + return true; } } return false; } +/** + * @brief Launch functions from Core 1 to make race conditions less likely + * + */ + +void MI32Every50mSecond(){ + if(MI32.mode.shallTriggerTele){ + MI32.mode.shallTriggerTele = 0; + MI32triggerTele(); + } +} + /** * @brief Main loop of the driver, "high level"-loop * @@ -1473,71 +1578,117 @@ void MI32Show(bool json) if (json) { if(!MI32.mode.triggeredTele){ MI32.mode.shallClearResults=1; + if(MI32.option.noSummary) return; // no message at TELEPERIOD } - for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { - switch(MIBLEsensors[i].type){ - case NLIGHT: case MJYD2S: case YEERC: - if(MIBLEsensors[i].shallSendMQTT==0) continue; - break; - default: - if(MI32.mode.triggeredTele) continue; - break; - } - ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":{"), + for (uint32_t i = 0; i < MIBLEsensors.size(); i++) { + if(MI32.mode.triggeredTele && MIBLEsensors[i].eventType.raw == 0) continue; + if(MI32.mode.triggeredTele && MIBLEsensors[i].shallSendMQTT==0) continue; + + ResponseAppend_P(PSTR(",\"%s-%02x%02x%02x\":"), // do not add the '{' now ... kMI32DeviceType[MIBLEsensors[i].type-1], MIBLEsensors[i].MAC[3], MIBLEsensors[i].MAC[4], MIBLEsensors[i].MAC[5]); - ResponseAppend_P(PSTR("\"RSSI\":%d"), MIBLEsensors[i].rssi); + uint32_t _positionCurlyBracket = strlen(mqtt_data); // ... this will be a ',' first, but later be replaced - if (MIBLEsensors[i].type == FLORA) { - if (!isnan(MIBLEsensors[i].temp)) { - char temperature[FLOATSZ]; // all sensors have temperature - dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature); - ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"), temperature); + if((!MI32.mode.triggeredTele && !MI32.option.minimalSummary)||MI32.mode.triggeredTele){ + bool tempHumSended = false; + if(MIBLEsensors[i].feature.tempHum){ + if(MIBLEsensors[i].eventType.tempHum || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ + if (!isnan(MIBLEsensors[i].hum) && !isnan(MIBLEsensors[i].temp)) { + ResponseAppend_P(PSTR(",")); + ResponseAppendTHD(MIBLEsensors[i].temp, MIBLEsensors[i].hum); + tempHumSended = true; + } + } } - if (MIBLEsensors[i].lux!=0x0ffffff) { // this is the error code -> no lux - ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); + if(MIBLEsensors[i].feature.temp && !tempHumSended){ + if(MIBLEsensors[i].eventType.temp || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate) { + if (!isnan(MIBLEsensors[i].temp)) { + char temperature[FLOATSZ]; + dtostrfd(MIBLEsensors[i].temp, Settings.flag2.temperature_resolution, temperature); + ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%s"), temperature); + } + } } - if (MIBLEsensors[i].moisture!=0xff) { - ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); + if(MIBLEsensors[i].feature.hum && !tempHumSended){ + if(MIBLEsensors[i].eventType.hum || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate) { + if (!isnan(MIBLEsensors[i].hum)) { + char hum[FLOATSZ]; + dtostrfd(MIBLEsensors[i].hum, Settings.flag2.humidity_resolution, hum); + ResponseAppend_P(PSTR(",\"" D_JSON_HUMIDITY "\":%s"), hum); + } + } } - if (MIBLEsensors[i].fertility!=0xffff) { - ResponseAppend_P(PSTR(",\"Fertility\":%u"), MIBLEsensors[i].fertility); + if (MIBLEsensors[i].feature.lux){ + if(MIBLEsensors[i].eventType.lux || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ + if (MIBLEsensors[i].lux!=0x0ffffff) { // this is the error code -> no lux + ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); + } + } } + if (MIBLEsensors[i].feature.moist){ + if(MIBLEsensors[i].eventType.moist || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ + if (MIBLEsensors[i].moisture!=0xff) { + ResponseAppend_P(PSTR(",\"" D_JSON_MOISTURE "\":%u"), MIBLEsensors[i].moisture); + } + } + } + if (MIBLEsensors[i].feature.fert){ + if(MIBLEsensors[i].eventType.fert || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ + if (MIBLEsensors[i].fertility!=0xffff) { + ResponseAppend_P(PSTR(",\"Fertility\":%u"), MIBLEsensors[i].fertility); + } + } + } + if (MIBLEsensors[i].feature.Btn){ + if(MIBLEsensors[i].eventType.Btn){ + ResponseAppend_P(PSTR(",\"Btn\":%u"),MIBLEsensors[i].Btn); + } + } + } // minimal summary + if (MIBLEsensors[i].feature.PIR){ + if(MIBLEsensors[i].eventType.motion || !MI32.mode.triggeredTele){ + if(MI32.mode.triggeredTele) ResponseAppend_P(PSTR(",\"PIR\":1")); // only real-time + ResponseAppend_P(PSTR(",\"Events\":%u"),MIBLEsensors[i].events); + } + else if(MIBLEsensors[i].eventType.noMotion && MI32.mode.triggeredTele){ + ResponseAppend_P(PSTR(",\"PIR\":0")); + } + } + + if (MIBLEsensors[i].type == FLORA && !MI32.mode.triggeredTele) { if (MIBLEsensors[i].firmware[0] != '\0') { // this is the error code -> no firmware ResponseAppend_P(PSTR(",\"Firmware\":\"%s\""), MIBLEsensors[i].firmware); } } - if (MIBLEsensors[i].type > FLORA){ - if (!isnan(MIBLEsensors[i].hum) && !isnan(MIBLEsensors[i].temp)) { - ResponseAppend_P(PSTR(",")); - ResponseAppendTHD(MIBLEsensors[i].temp, MIBLEsensors[i].hum); + + if (MIBLEsensors[i].feature.NMT || !MI32.mode.triggeredTele){ + if(MIBLEsensors[i].eventType.NMT){ + ResponseAppend_P(PSTR(",\"NMT\":%u"), MIBLEsensors[i].NMT); } } -#ifdef USE_MI_DECRYPTION - if (MIBLEsensors[i].type == MJYD2S){ - ResponseAppend_P(PSTR(",\"Events\":%u"),MIBLEsensors[i].events); - if(MIBLEsensors[i].shallSendMQTT && MIBLEsensors[i].eventType<3) ResponseAppend_P(PSTR(",\"PIR\":%u"), 2 - MIBLEsensors[i].eventType); - if(MIBLEsensors[i].eventType==3) ResponseAppend_P(PSTR(",\"NMT\":%u"), MIBLEsensors[i].NMT); - MIBLEsensors[i].eventType=0; - if(MIBLEsensors[i].lux!=0x0ffffff) ResponseAppend_P(PSTR(",\"" D_JSON_ILLUMINANCE "\":%u"), MIBLEsensors[i].lux); - } -#endif //USE_MI_DECRYPTION - if (MIBLEsensors[i].type == NLIGHT){ - ResponseAppend_P(PSTR(",\"Events\":%u"),MIBLEsensors[i].events); - if(MIBLEsensors[i].shallSendMQTT) ResponseAppend_P(PSTR(",\"PIR\":1")); - } - if (MIBLEsensors[i].type == YEERC){ - if(MIBLEsensors[i].shallSendMQTT) ResponseAppend_P(PSTR(",\"Btn\":%u"),MIBLEsensors[i].Btn); - } - if (MIBLEsensors[i].bat != 0x00) { // this is the error code -> no battery - ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors[i].bat); + if (MIBLEsensors[i].feature.bat){ + if(MIBLEsensors[i].eventType.bat || !MI32.mode.triggeredTele || MI32.option.allwaysAggregate){ + if (MIBLEsensors[i].bat != 0x00) { // this is the error code -> no battery + ResponseAppend_P(PSTR(",\"Battery\":%u"), MIBLEsensors[i].bat); + } + } } + if (MI32.option.showRSSI && MI32.mode.triggeredTele) ResponseAppend_P(PSTR(",\"RSSI\":%d"), MIBLEsensors[i].rssi); + + + if(_positionCurlyBracket==strlen(mqtt_data)) ResponseAppend_P(PSTR(",")); // write some random char, to be overwritten in the next step ResponseAppend_P(PSTR("}")); - MIBLEsensors[i].shallSendMQTT = 0; - MI32.mode.triggeredTele = 0; + mqtt_data[_positionCurlyBracket] = '{'; + MIBLEsensors[i].eventType.raw = 0; + if(MIBLEsensors[i].shallSendMQTT==1){ + MIBLEsensors[i].shallSendMQTT = 0; + break; + } } + MI32.mode.triggeredTele = 0; + // ResponseAppend_P(PSTR("}")); #ifdef USE_WEBSERVER } else { static uint16_t _page = 0; @@ -1618,6 +1769,9 @@ bool Xsns62(uint8_t function) if (MI32.mode.init) { switch (function) { + case FUNC_EVERY_50_MSECOND: + MI32Every50mSecond(); + break; case FUNC_EVERY_SECOND: MI32EverySecond(false); break; From 57fe4cf2482847ac24a3483f18907a10e7015e95 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 20 Jul 2020 10:04:39 +0200 Subject: [PATCH 07/91] Use Tasmota_stage core 2.7.3.1 from Tasmota Github and delete unneeded compiler flags --- platformio_override_sample.ini | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 57d7498cb..48298c782 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -88,13 +88,9 @@ extra_scripts = ${scripts_defaults.extra_scripts} [tasmota_stage] ; *** Esp8266 core for Arduino version Tasmota stage platform = espressif8266@2.5.1 -platform_packages = framework-arduinoespressif8266 @ https://github.com/Jason2866/Arduino/releases/download/2.7.3.1/esp8266-2.7.3.1.zip +platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.1/esp8266-2.7.3.1.zip build_unflags = ${esp_defaults.build_unflags} - -std=c17 - -std=gnu++17 build_flags = ${esp82xx_defaults.build_flags} - -std=gnu99 - -std=c++11 ; *********** Alternative Options, enable only if you know exactly what you do ******** ; NONOSDK221 From eeed6768d09640f9ff612491d7c8ee6657d54245 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 20 Jul 2020 11:20:58 +0200 Subject: [PATCH 08/91] Third try to fix counter interrupt storm --- tasmota/support_tasmota.ino | 15 ++++++--------- tasmota/xdrv_01_webserver.ino | 8 ++++---- tasmota/xsns_01_counter.ino | 32 +++----------------------------- 3 files changed, 13 insertions(+), 42 deletions(-) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 0fbcbb615..054d830cc 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -969,6 +969,9 @@ void Every250mSeconds(void) SettingsSave(1); // Free flash for OTA update } if (ota_state_flag <= 0) { +#ifdef USE_COUNTER + CounterInterruptDisable(true); // Prevent OTA failures on 100Hz counter interrupts +#endif // USE_COUNTER #ifdef USE_WEBSERVER if (Settings.webserver) StopWebserver(); #endif // USE_WEBSERVER @@ -1000,15 +1003,6 @@ void Every250mSeconds(void) char *bch = strrchr(mqtt_data, '/'); // Only consider filename after last backslash prevent change of urls having "-" in it if (bch == nullptr) { bch = mqtt_data; } // No path found so use filename only -/* - char *ech = strrchr(bch, '.'); // Find file type in filename (none, .bin or .gz) - if ((ech != nullptr) && (0 == strncasecmp_P(ech, PSTR(".GZ"), 3))) { - char *fch = ech; - *fch = '\0'; - ech = strrchr(bch, '.'); // Find file type .bin.gz - *fch = '.'; - } -*/ char *ech = strchr(bch, '.'); // Find file type in filename (none, .ino.bin, .ino.bin.gz, .bin, .bin.gz or .gz) if (ech == nullptr) { ech = mqtt_data + strlen(mqtt_data); } // Point to '/0' at end of mqtt_data becoming an empty string @@ -1055,6 +1049,9 @@ void Every250mSeconds(void) ResponseAppend_P(PSTR("\"}")); // restart_flag = 2; // Restart anyway to keep memory clean webserver MqttPublishPrefixTopic_P(STAT, PSTR(D_CMND_UPGRADE)); +#ifdef USE_COUNTER + CounterInterruptDisable(false); +#endif // USE_COUNTER } } break; diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 112b9ac7f..b94a2a902 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -2600,7 +2600,7 @@ void HandleUploadDone(void) MqttRetryCounter(0); #ifdef USE_COUNTER CounterInterruptDisable(false); -#endif +#endif // USE_COUNTER WSContentStart_P(S_INFORMATION); if (!Web.upload_error) { @@ -2677,8 +2677,8 @@ void HandleUploadLoop(void) } else { MqttRetryCounter(60); #ifdef USE_COUNTER - CounterInterruptDisable(true); -#endif + CounterInterruptDisable(true); // Prevent OTA failures on 100Hz counter interrupts +#endif // USE_COUNTER #ifdef USE_EMULATION UdpDisconnect(); #endif // USE_EMULATION @@ -2876,7 +2876,7 @@ void HandleUploadLoop(void) MqttRetryCounter(0); #ifdef USE_COUNTER CounterInterruptDisable(false); -#endif +#endif // USE_COUNTER Web.upload_error = 7; // Upload aborted if (UPL_TASMOTA == Web.upload_file_type) { Update.end(); } } diff --git a/tasmota/xsns_01_counter.ino b/tasmota/xsns_01_counter.ino index 73c19322e..5b6de4e4c 100644 --- a/tasmota/xsns_01_counter.ino +++ b/tasmota/xsns_01_counter.ino @@ -49,7 +49,6 @@ struct COUNTER { uint32_t last_cycle; uint32_t cycle_time; -//void ICACHE_RAM_ATTR CounterUpdate(uint8_t index) { void ICACHE_RAM_ATTR CounterIsrArg(void *arg) { uint32_t index = *static_cast(arg); @@ -94,15 +93,15 @@ void ICACHE_RAM_ATTR CounterIsrArg(void *arg) { // add 100.000 cpu ticks to ensure right step calculation uint32_t steps = (current_cycle-last_cycle+100000)/(clockCyclesPerMicrosecond() * 10000); cycle_time = (current_cycle-last_cycle)/steps; - #ifdef ESP8266 +#ifdef ESP8266 pinMode(Pin(GPIO_PWM1, index), OUTPUT); uint32_t high = (cycle_time * 5) / 1023; uint32_t low = cycle_time - high; // Find the first GPIO being generated by checking GCC's find-first-set (returns 1 + the bit of the first 1 in an int32_t startWaveformClockCycles(Pin(GPIO_PWM1, index), high, low, 0, -1, 0, true); - #else +#else // ESP32 analogWrite(Pin(GPIO_PWM1, index), 5); - #endif +#endif // ESP8266 - ESP32 } last_cycle = current_cycle; } @@ -120,27 +119,7 @@ void ICACHE_RAM_ATTR CounterIsrArg(void *arg) { } } } -/* -void ICACHE_RAM_ATTR CounterUpdate1(void) -{ - CounterUpdate(0); -} -void ICACHE_RAM_ATTR CounterUpdate2(void) -{ - CounterUpdate(1); -} - -void ICACHE_RAM_ATTR CounterUpdate3(void) -{ - CounterUpdate(2); -} - -void ICACHE_RAM_ATTR CounterUpdate4(void) -{ - CounterUpdate(3); -} -*/ /********************************************************************************************/ void CounterInterruptDisable(bool state) { @@ -172,20 +151,15 @@ bool CounterPinState(void) void CounterInit(void) { -// typedef void (*function) () ; -// function counter_callbacks[] = { CounterUpdate1, CounterUpdate2, CounterUpdate3, CounterUpdate4 }; - for (uint32_t i = 0; i < MAX_COUNTERS; i++) { if (PinUsed(GPIO_CNTR1, i)) { Counter.any_counter = true; pinMode(Pin(GPIO_CNTR1, i), bitRead(Counter.no_pullup, i) ? INPUT : INPUT_PULLUP); if ((0 == Settings.pulse_counter_debounce_low) && (0 == Settings.pulse_counter_debounce_high) && !Settings.flag4.zerocross_dimmer) { Counter.pin_state = 0; -// attachInterrupt(Pin(GPIO_CNTR1, i), counter_callbacks[i], FALLING); attachInterruptArg(Pin(GPIO_CNTR1, i), CounterIsrArg, &ctr_index[i], FALLING); } else { Counter.pin_state = 0x8f; -// attachInterrupt(Pin(GPIO_CNTR1, i), counter_callbacks[i], CHANGE); attachInterruptArg(Pin(GPIO_CNTR1, i), CounterIsrArg, &ctr_index[i], CHANGE); } } From cea8e169a428cc85bc97b57d07241f0df86ec670 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 20 Jul 2020 12:00:46 +0200 Subject: [PATCH 09/91] Adding maintained badges in readme. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 19fbff041..97413616e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ _Written for PlatformIO with limited support for Arduino IDE._ [![GitHub download](https://img.shields.io/github/downloads/arendst/Tasmota/total.svg)](https://github.com/arendst/Tasmota/releases/latest) [![License](https://img.shields.io/github/license/arendst/Tasmota.svg)](LICENSE.txt) [![Chat](https://img.shields.io/discord/479389167382691863.svg)](https://discord.gg/Ks2Kzd4) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/arendst/Tasmota.svg)](http://isitmaintained.com/project/arendst/Tasmota "Average time to resolve an issue") +[![Percentage of issues still open](http://isitmaintained.com/badge/open/arendst/Tasmota.svg)](http://isitmaintained.com/project/arendst/Tasmota "Percentage of issues still open") If you like **Tasmota**, give it a star, or fork it and contribute! From 0a64625e9a1486c75f07ea7ec2892112ed4bb576 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 20 Jul 2020 16:26:32 +0200 Subject: [PATCH 10/91] Allow rules on energy margins Allow rules on energy margins (#8935) --- tasmota/xdrv_03_energy.ino | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino index f38265bb8..afa818913 100644 --- a/tasmota/xdrv_03_energy.ino +++ b/tasmota/xdrv_03_energy.ino @@ -110,7 +110,6 @@ struct ENERGY { #ifdef USE_ENERGY_MARGIN_DETECTION uint16_t power_history[3] = { 0 }; uint8_t power_steady_counter = 8; // Allow for power on stabilization - bool power_delta = false; bool min_power_flag = false; bool max_power_flag = false; bool min_voltage_flag = false; @@ -306,23 +305,30 @@ void EnergyMarginCheck(void) uint16_t energy_power_u = (uint16_t)(Energy.active_power[0]); + bool jsonflg = false; + Response_P(PSTR("{")); + if (Settings.energy_power_delta) { - uint16_t delta = abs(Energy.power_history[0] - energy_power_u); + int16_t power_diff = energy_power_u - Energy.power_history[0]; + uint16_t delta = abs(power_diff); if (delta > 0) { if (Settings.energy_power_delta < 101) { // 1..100 = Percentage uint16_t min_power = (Energy.power_history[0] > energy_power_u) ? energy_power_u : Energy.power_history[0]; if (0 == min_power) { min_power++; } // Fix divide by 0 exception (#6741) - if (((delta * 100) / min_power) > Settings.energy_power_delta) { - Energy.power_delta = true; + delta = (delta * 100) / min_power; + if (delta > Settings.energy_power_delta) { + jsonflg = true; } } else { // 101..32000 = Absolute if (delta > (Settings.energy_power_delta -100)) { - Energy.power_delta = true; + jsonflg = true; } } - if (Energy.power_delta) { + if (jsonflg) { Energy.power_history[1] = Energy.active_power[0]; // We only want one report so reset history Energy.power_history[2] = Energy.active_power[0]; + + ResponseAppend_P(PSTR("\"" D_CMND_POWERDELTA "\":%d"), power_diff); } } } @@ -336,9 +342,7 @@ void EnergyMarginCheck(void) DEBUG_DRIVER_LOG(PSTR("NRG: W %d, U %d, I %d"), energy_power_u, energy_voltage_u, energy_current_u); - Response_P(PSTR("{")); bool flag; - bool jsonflg = false; if (EnergyMargin(false, Settings.energy_min_power, energy_power_u, flag, Energy.min_power_flag)) { ResponseAppend_P(PSTR("%s\"" D_CMND_POWERLOW "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; @@ -363,11 +367,12 @@ void EnergyMarginCheck(void) ResponseAppend_P(PSTR("%s\"" D_CMND_CURRENTHIGH "\":\"%s\""), (jsonflg)?",":"", GetStateText(flag)); jsonflg = true; } - if (jsonflg) { - ResponseJsonEnd(); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN); - EnergyMqttShow(); - } + } + if (jsonflg) { + ResponseJsonEnd(); + MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN); + XdrvRulesProcess(); + EnergyMqttShow(); } #ifdef USE_ENERGY_POWER_LIMIT @@ -436,8 +441,6 @@ void EnergyMarginCheck(void) } } #endif // USE_ENERGY_POWER_LIMIT - - if (Energy.power_delta) { EnergyMqttShow(); } } void EnergyMqttShow(void) @@ -451,7 +454,6 @@ void EnergyMqttShow(void) tele_period = tele_period_save; ResponseJsonEnd(); MqttPublishTeleSensor(); - Energy.power_delta = false; } #endif // USE_ENERGY_MARGIN_DETECTION From 59f50d04f2c0f1bca8d949d913a68dcfff3801e9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 20 Jul 2020 16:41:05 +0200 Subject: [PATCH 11/91] Allow rules on energy margins Allow rules on energy margins (#8935) --- tasmota/xdrv_03_energy.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino index afa818913..0afeec26b 100644 --- a/tasmota/xdrv_03_energy.ino +++ b/tasmota/xdrv_03_energy.ino @@ -306,7 +306,7 @@ void EnergyMarginCheck(void) uint16_t energy_power_u = (uint16_t)(Energy.active_power[0]); bool jsonflg = false; - Response_P(PSTR("{")); + Response_P(PSTR("{\"" D_RSLT_MARGINS "\":{")); if (Settings.energy_power_delta) { int16_t power_diff = energy_power_u - Energy.power_history[0]; @@ -369,7 +369,7 @@ void EnergyMarginCheck(void) } } if (jsonflg) { - ResponseJsonEnd(); + ResponseJsonEndEnd(); MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN); XdrvRulesProcess(); EnergyMqttShow(); From bc3efb5696f6b3001856f88aae17fdfa9d22b359 Mon Sep 17 00:00:00 2001 From: Antonio Fernandez Date: Mon, 20 Jul 2020 10:57:38 -0400 Subject: [PATCH 12/91] Updated the D_TIMER_ARM variable to say "Enable" Arm has been a bit of a confusing term. I think it would help new users out to rename this to "Enable". It will make the button more intuitive. --- tasmota/language/en_GB.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 98badad64..1ae054f0e 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -419,7 +419,7 @@ #define D_CONFIGURE_TIMER "Configure Timer" #define D_TIMER_PARAMETERS "Timer parameters" #define D_TIMER_ENABLE "Enable Timers" -#define D_TIMER_ARM "Arm" +#define D_TIMER_ARM "Enable" #define D_TIMER_TIME "Time" #define D_TIMER_DAYS "Days" #define D_TIMER_REPEAT "Repeat" From a84ebe552adce2f482d906107554704c06a696f1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 20 Jul 2020 17:24:51 +0200 Subject: [PATCH 13/91] Refactor rules processing --- tasmota/support_command.ino | 3 +- tasmota/support_rotary.ino | 3 +- tasmota/support_tasmota.ino | 3 +- tasmota/xdrv_02_mqtt.ino | 14 ++++- tasmota/xdrv_03_energy.ino | 3 +- tasmota/xdrv_04_light.ino | 3 +- tasmota/xdrv_05_irremote.ino | 3 +- tasmota/xdrv_05_irremote_full.ino | 6 +-- tasmota/xdrv_06_snfbridge.ino | 7 +-- tasmota/xdrv_08_serial_bridge.ino | 3 +- tasmota/xdrv_17_rcswitch.ino | 3 +- tasmota/xdrv_23_zigbee_5_converters.ino | 6 +-- tasmota/xdrv_23_zigbee_7_statemachine.ino | 3 +- tasmota/xdrv_23_zigbee_8_parsers.ino | 63 ++++++++--------------- tasmota/xdrv_23_zigbee_9_serial.ino | 21 ++++---- tasmota/xdrv_23_zigbee_A_impl.ino | 7 ++- tasmota/xdrv_27_shutter.ino | 6 +-- tasmota/xdrv_31_tasmota_client.ino | 3 +- tasmota/xdrv_38_ping.ino | 11 ++-- 19 files changed, 68 insertions(+), 103 deletions(-) diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index abd75960e..6d0f50f3a 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -288,8 +288,7 @@ void CommandHandler(char* topicBuf, char* dataBuf, uint32_t data_len) } if (mqtt_data[0] != '\0') { - MqttPublishPrefixTopic_P(RESULT_OR_STAT, type); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, type); } fallback_topic_flag = false; } diff --git a/tasmota/support_rotary.ino b/tasmota/support_rotary.ino index 4fc776511..76c748203 100644 --- a/tasmota/support_rotary.ino +++ b/tasmota/support_rotary.ino @@ -136,8 +136,7 @@ void RotaryHandler(void) { #ifdef USE_LIGHT if (!Settings.flag4.rotary_uses_rules) { // SetOption98 - Use rules instead of light control ResponseLightState(0); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_CMND_STATE)); } #endif // USE_LIGHT Encoder[index].direction = 0; diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 054d830cc..9007d0157 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1429,8 +1429,7 @@ void SerialInput(void) } ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_SERIALRECEIVED)); serial_in_byte_counter = 0; } } diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 1f232cff8..a9038a941 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -381,10 +381,20 @@ void MqttPublishPrefixTopic_P(uint32_t prefix, const char* subtopic) MqttPublishPrefixTopic_P(prefix, subtopic, false); } +void MqttPublishPrefixTopicRulesProcess_P(uint32_t prefix, const char* subtopic, bool retained) +{ + MqttPublishPrefixTopic_P(prefix, subtopic, retained); + XdrvRulesProcess(); +} + +void MqttPublishPrefixTopicRulesProcess_P(uint32_t prefix, const char* subtopic) +{ + MqttPublishPrefixTopicRulesProcess_P(prefix, subtopic, false); +} + void MqttPublishTeleSensor(void) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); // CMND_SENSORRETAIN - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain); // CMND_SENSORRETAIN } void MqttPublishPowerState(uint32_t device) diff --git a/tasmota/xdrv_03_energy.ino b/tasmota/xdrv_03_energy.ino index 0afeec26b..4d53af77c 100644 --- a/tasmota/xdrv_03_energy.ino +++ b/tasmota/xdrv_03_energy.ino @@ -370,8 +370,7 @@ void EnergyMarginCheck(void) } if (jsonflg) { ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_MARGINS), MQTT_TELE_RETAIN); EnergyMqttShow(); } diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index ab311d6f0..18881d119 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1878,8 +1878,7 @@ void LightAnimate(void) Response_P(PSTR("{\"" D_CMND_WAKEUP "\":\"" D_JSON_DONE "\"")); ResponseLightState(1); ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_CMND_WAKEUP)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_CMND_WAKEUP)); Light.wakeup_active = 0; Settings.light_scheme = LS_POWER; diff --git a/tasmota/xdrv_05_irremote.ino b/tasmota/xdrv_05_irremote.ino index 87a51de53..bb5ce0c3c 100644 --- a/tasmota/xdrv_05_irremote.ino +++ b/tasmota/xdrv_05_irremote.ino @@ -155,9 +155,8 @@ void IrReceiveCheck(void) } ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED)); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED)); - XdrvRulesProcess(); #ifdef USE_DOMOTICZ if (iridx) { unsigned long value = results.value | (iridx << 28); // [Protocol:4, Data:28] diff --git a/tasmota/xdrv_05_irremote_full.ino b/tasmota/xdrv_05_irremote_full.ino index 457ff63f4..9649e87b4 100644 --- a/tasmota/xdrv_05_irremote_full.ino +++ b/tasmota/xdrv_05_irremote_full.ino @@ -232,9 +232,7 @@ void IrReceiveCheck(void) } ResponseJsonEndEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED)); - - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_IRRECEIVED)); } irrecv->resume(); @@ -475,7 +473,7 @@ uint32_t IrRemoteCmndIrSendRaw(void) for (uint32_t i = 0; i <= count; i++) { GC[i] = strtol(strtok_r(nullptr, ", ", &p), nullptr, 0); if (!GC[i]) { - return IE_INVALID_RAWDATA; + return IE_INVALID_RAWDATA; } } irsend_active = true; diff --git a/tasmota/xdrv_06_snfbridge.ino b/tasmota/xdrv_06_snfbridge.ino index 210ff87a3..af6f928bd 100644 --- a/tasmota/xdrv_06_snfbridge.ino +++ b/tasmota/xdrv_06_snfbridge.ino @@ -226,9 +226,7 @@ void SonoffBridgeReceivedRaw(void) } } ResponseAppend_P(PSTR("\"}}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_CMND_RFRAW)); - - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_CMND_RFRAW)); } /********************************************************************************************/ @@ -298,8 +296,7 @@ void SonoffBridgeReceived(void) } ResponseTime_P(PSTR(",\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_SYNC "\":%d,\"" D_JSON_LOW "\":%d,\"" D_JSON_HIGH "\":%d,\"" D_JSON_DATA "\":%s,\"" D_CMND_RFKEY "\":%s}}"), sync_time, low_time, high_time, stemp, rfkey); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED)); #ifdef USE_DOMOTICZ DomoticzSensor(DZ_COUNT, received_id); // Send rid as Domoticz Counter value #endif // USE_DOMOTICZ diff --git a/tasmota/xdrv_08_serial_bridge.ino b/tasmota/xdrv_08_serial_bridge.ino index 0dec9cb6b..b5a9143b7 100644 --- a/tasmota/xdrv_08_serial_bridge.ino +++ b/tasmota/xdrv_08_serial_bridge.ino @@ -93,8 +93,7 @@ void SerialBridgeInput(void) } ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_SSERIALRECEIVED)); serial_bridge_in_byte_counter = 0; } } diff --git a/tasmota/xdrv_17_rcswitch.ino b/tasmota/xdrv_17_rcswitch.ino index c5013828c..ac4111e83 100644 --- a/tasmota/xdrv_17_rcswitch.ino +++ b/tasmota/xdrv_17_rcswitch.ino @@ -69,8 +69,7 @@ void RfReceiveCheck(void) } ResponseTime_P(PSTR(",\"" D_JSON_RFRECEIVED "\":{\"" D_JSON_RF_DATA "\":%s,\"" D_JSON_RF_BITS "\":%d,\"" D_JSON_RF_PROTOCOL "\":%d,\"" D_JSON_RF_PULSE "\":%d}}"), stemp, bits, protocol, delay); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_RFRECEIVED)); #ifdef USE_DOMOTICZ DomoticzSensor(DZ_COUNT, data); // Send data as Domoticz Counter value #endif // USE_DOMOTICZ diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 26781d358..578e3c3bf 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -622,8 +622,7 @@ public: _frame_control, _manuf_code, _transact_seq, _cmd_id, hex_char); if (Settings.flag3.tuya_serial_mqtt_publish) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR)); } else { AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); } @@ -1152,8 +1151,7 @@ void ZCLFrame::parseResponse(void) { msg.reserve(100); json.printTo(msg); Response_P(PSTR("{\"" D_JSON_ZIGBEE_RESPONSE "\":%s}"), msg.c_str()); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); } diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index fecf68fe9..50e67f91c 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -1097,8 +1097,7 @@ void ZigbeeStateMachine_Run(void) { const char *f_msg = (const char*) cur_ptr1; Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{\"Status\":%d,\"Message\":\"%s\"}}"), cur_d8, f_msg); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); } break; case ZGB_INSTR_SEND: diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index a94a07aeb..e0239f316 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -43,8 +43,7 @@ int32_t EZ_RSTACK(uint8_t reset_code) { ",\"Code\":%d}}"), ZIGBEE_STATUS_BOOT, reason_str, reset_code); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); } // EZSP: received ASH "ERROR" frame, indicating that the MCU finished boot @@ -60,8 +59,7 @@ int32_t EZ_ERROR(uint8_t error_code) { ",\"Code\":%d}}"), ZIGBEE_STATUS_ABORT, reason_str, error_code); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); } int32_t EZ_ReadAPSUnicastMessage(int32_t res, class SBuffer &buf) { @@ -112,8 +110,7 @@ int32_t EZ_NetworkParameters(int32_t res, class SBuffer &buf) { ",\"DeviceType\":%d}}"), ZIGBEE_STATUS_EZ_INFO, hex, localShortAddr, node_type); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); return res; } @@ -161,8 +158,7 @@ int32_t Z_EZSPNetworkParameters(int32_t res, class SBuffer &buf) { ",\"DeviceType\":%d}}"), ZIGBEE_STATUS_EZ_INFO, hex, localShortAddr, node_type); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); return res; } @@ -212,10 +208,8 @@ int32_t ZNP_ReceiveDeviceInfo(int32_t res, class SBuffer &buf) { ResponseAppend_P(PSTR("]")); } - ResponseJsonEnd(); // append '}' - ResponseJsonEnd(); // append '}' - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + ResponseJsonEndEnd(); // append '}}' + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); return res; } @@ -257,8 +251,7 @@ int32_t ZNP_Reboot(int32_t res, class SBuffer &buf) { ZIGBEE_STATUS_BOOT, reason_str, major_rel, minor_rel); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); if ((0x02 == major_rel) && (0x06 == minor_rel)) { return 0; // version 2.6.x is ok @@ -289,8 +282,7 @@ int32_t ZNP_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { ZIGBEE_STATUS_CC_VERSION, major_rel, minor_rel, maint_rel, revision); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); if ((0x02 == major_rel) && (0x06 == minor_rel)) { return 0; // version 2.6.x is ok @@ -318,8 +310,7 @@ int32_t EZ_ReceiveCheckVersion(int32_t res, class SBuffer &buf) { stack_type ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); if (0x08 == protocol_version) { return 0; // protocol v8 is ok @@ -394,8 +385,7 @@ int32_t ZNP_ReceivePermitJoinStatus(int32_t res, const class SBuffer &buf) { ResponseAppend_P(message, duration); ResponseAppend_P(PSTR("\"}}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); return -1; } @@ -435,8 +425,7 @@ int32_t ZNP_ReceiveNodeDesc(int32_t res, const class SBuffer &buf) { complexDescriptorAvailable ? PSTR("true") : PSTR("false") ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); } return -1; @@ -473,8 +462,7 @@ int32_t Z_ReceiveActiveEp(int32_t res, const class SBuffer &buf) { ResponseAppend_P(PSTR("\"0x%02X\""), activeEpList[i]); } ResponseAppend_P(PSTR("]}}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); Z_SendAFInfoRequest(nwkAddr); // probe for ModelId and ManufId @@ -515,8 +503,7 @@ int32_t Z_ReceiveIEEEAddr(int32_t res, const class SBuffer &buf) { } ResponseAppend_P(PSTR("\"}}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); } return -1; } @@ -534,8 +521,7 @@ int32_t ZNP_DataConfirm(int32_t res, const class SBuffer &buf) { ",\"" D_JSON_ZIGBEE_STATUS "\":%d" ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" "}}"), endpoint, status, getZigbeeStatusMessage(status).c_str()); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); } return -1; @@ -591,8 +577,7 @@ int32_t ZNP_ReceiveStateChange(int32_t res, const class SBuffer &buf) { ZIGBEE_STATUS_SCANNING, state, msg ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); } if ((ZDO_DEV_END_DEVICE == state) || (ZDO_DEV_ROUTER == state) || (ZDO_DEV_ZB_COORD == state)) { @@ -637,8 +622,7 @@ int32_t Z_ReceiveEndDeviceAnnonce(int32_t res, const class SBuffer &buf) { uint32_t wait_ms = 2000; // wait for 2s Z_Query_Bulb(nwkAddr, wait_ms); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); Z_SendActiveEpReq(nwkAddr); return -1; } @@ -662,8 +646,7 @@ int32_t ZNP_ReceiveTCDevInd(int32_t res, const class SBuffer &buf) { ZIGBEE_STATUS_DEVICE_INDICATION, hex, srcAddr, parentNw ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); return -1; } @@ -692,8 +675,7 @@ int32_t Z_BindRsp(int32_t res, const class SBuffer &buf) { ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" "}}"), status, msg.c_str()); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); return -1; } @@ -723,8 +705,7 @@ int32_t Z_UnbindRsp(int32_t res, const class SBuffer &buf) { ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" "}}"), status, msg.c_str()); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); return -1; } @@ -799,8 +780,7 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { ResponseAppend_P(PSTR("]}}")); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_BIND_STATE)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_BIND_STATE)); return -1; } @@ -880,8 +860,7 @@ int32_t EZ_ReceiveTCJoinHandler(int32_t res, const class SBuffer &buf) { status, decision ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEEZCL_RECEIVED)); } return -1; } diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index aeefe8ae4..cd5ef3c4f 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -131,8 +131,7 @@ void ZigbeeInputLoop(void) { ToHex_P((unsigned char*)znp_buffer.getBuffer(), znp_buffer.len(), hex_char, sizeof(hex_char)); Response_P(PSTR("{\"" D_JSON_ZIGBEEZNPRECEIVED "\":\"%s\"}"), hex_char); if (Settings.flag3.tuya_serial_mqtt_publish) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR)); } else { AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); } @@ -194,7 +193,7 @@ void ZigbeeInputLoop(void) { if (zigbee_buffer->len() < ZIGBEE_BUFFER_SIZE) { if (escape) { // invert bit 5 - zigbee_in_byte ^= 0x20; + zigbee_in_byte ^= 0x20; escape = false; } @@ -252,8 +251,7 @@ void ZigbeeInputLoop(void) { ToHex_P((unsigned char*)ezsp_buffer.getBuffer(), ezsp_buffer.len(), hex_char, sizeof(hex_char)); Response_P(PSTR("{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "2\":\"%s\"}"), hex_char); if (Settings.flag3.tuya_serial_mqtt_publish) { - MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR)); } else { AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); // TODO move to LOG_LEVEL_DEBUG when stable } @@ -435,7 +433,7 @@ void ZigbeeEZSPSendRaw(const uint8_t *msg, size_t len, bool send_cancel) { bool data_frame = (0 == (msg[0] & 0x80)); uint8_t rand = 0x42; // pseudo-randomizer initial value uint16_t crc = 0xFFFF; // CRC16 CCITT initialization - + for (uint32_t i=0; i 0xFFFF) { group = 0xFFFF; } - + SBuffer buf(8); buf.add16(EZSP_setMulticastTableEntry); buf.add8(index); diff --git a/tasmota/xdrv_27_shutter.ino b/tasmota/xdrv_27_shutter.ino index 6d0c6e5ce..660c5e2c3 100644 --- a/tasmota/xdrv_27_shutter.ino +++ b/tasmota/xdrv_27_shutter.ino @@ -279,8 +279,7 @@ void ShutterReportPosition(bool always, uint32_t index) } ResponseJsonEnd(); if (always || (rules_flag.shutter_moving)) { - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); - XdrvRulesProcess(); //RulesProcess() now re-entry protected + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); // RulesProcess() now re-entry protected } //AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("SHT: rules_flag.shutter_moving: %d, moved %d"), rules_flag.shutter_moving, rules_flag.shutter_moved); @@ -716,8 +715,7 @@ void ShutterButtonHandler(void) Response_P(PSTR("{")); ResponseAppend_P(JSON_SHUTTER_BUTTON, shutter_index+1, (buttonState <= SHT_PRESSED_EXT_HOLD) ? (button_index+1) : 0, press_index); ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_STAT, PSTR(D_PRFX_SHUTTER)); } } diff --git a/tasmota/xdrv_31_tasmota_client.ino b/tasmota/xdrv_31_tasmota_client.ino index 3fdbad076..86121475c 100644 --- a/tasmota/xdrv_31_tasmota_client.ino +++ b/tasmota/xdrv_31_tasmota_client.ino @@ -539,8 +539,7 @@ void TasmotaClient_ProcessIn(void) { Response_P(PSTR("{\"TasmotaClient\":")); ResponseAppend_P("%s", inbuf); ResponseJsonEnd(); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, mqtt_data); - XdrvRulesProcess(); + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, mqtt_data); } if (CMND_EXECUTE_CMND == TClientCommand.command) { // We need to execute the incoming command ExecuteCommand(inbuf, SRC_IGNORE); diff --git a/tasmota/xdrv_38_ping.ino b/tasmota/xdrv_38_ping.ino index d30c0093d..4724ee310 100644 --- a/tasmota/xdrv_38_ping.ino +++ b/tasmota/xdrv_38_ping.ino @@ -35,7 +35,7 @@ void (* const PingCommand[])(void) PROGMEM = { }; extern "C" { - + extern uint32 system_relative_time(uint32 time); extern void ets_bzero(void *s, size_t n); @@ -130,7 +130,7 @@ extern "C" { if ((p->len == p->tot_len) && (p->next == nullptr)) { ip_addr_t ping_target; struct icmp_echo_hdr *iecho; - + ping_target.addr = ping->ip; iecho = (struct icmp_echo_hdr *) p->payload; @@ -177,7 +177,7 @@ extern "C" { iecho = (struct icmp_echo_hdr *)p->payload; if ((iecho->id == Ping_ID) && (iecho->seqno == htons(ping->seq_num)) && iecho->type == ICMP_ER) { - + if (iecho->seqno != ping->seqno){ // debounce already received packet /* do some ping result processing */ sys_untimeout(t_ping_timeout, ping); // remove time-out handler @@ -282,9 +282,8 @@ void PingResponsePoll(void) { success ? ping->min_time : 0, ping->max_time, success ? ping->sum_time / success : 0 ); - MqttPublishPrefixTopic_P(RESULT_OR_TELE, PSTR(D_JSON_PING)); - XdrvRulesProcess(); - + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_PING)); + // remove from linked list *prev_link = ping->next; // don't increment prev_link From 2da8f3c3934bbd8747545ea3700b8048fc0acef2 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Mon, 20 Jul 2020 19:30:32 +0200 Subject: [PATCH 14/91] Added `SO101 1` to suffix commands with source endpoint --- tasmota/settings.h | 2 +- tasmota/xdrv_23_zigbee_2_devices.ino | 18 +++++++++ tasmota/xdrv_23_zigbee_5_converters.ino | 9 ++++- tasmota/xdrv_23_zigbee_6_commands.ino | 24 +++++++++-- tasmota/xdrv_23_zigbee_8_parsers.ino | 53 +++++++++++++++++-------- tasmota/xdrv_23_zigbee_A_impl.ino | 16 +++++++- 6 files changed, 99 insertions(+), 23 deletions(-) diff --git a/tasmota/settings.h b/tasmota/settings.h index 9d4466028..57aa35860 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -120,7 +120,7 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t rotary_uses_rules : 1; // bit 16 (v8.3.1.6) - SetOption98 - Use rules instead of light control uint32_t zerocross_dimmer : 1; // bit 17 (v8.3.1.4) - SetOption99 - Enable zerocross dimmer on PWM DIMMER uint32_t remove_zbreceived : 1; // bit 18 (v8.3.1.7) - SetOption100 - Remove ZbReceived form JSON message - uint32_t spare19 : 1; + uint32_t zb_index_ep : 1; // bit 19 (v8.3.1.7) - SetOption101 - Add the source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 uint32_t spare20 : 1; uint32_t spare21 : 1; uint32_t spare22 : 1; diff --git a/tasmota/xdrv_23_zigbee_2_devices.ino b/tasmota/xdrv_23_zigbee_2_devices.ino index abcf6440c..d87fe4005 100644 --- a/tasmota/xdrv_23_zigbee_2_devices.ino +++ b/tasmota/xdrv_23_zigbee_2_devices.ino @@ -141,6 +141,7 @@ public: // Add an endpoint to a device void addEndpoint(uint16_t shortaddr, uint8_t endpoint); void clearEndpoints(uint16_t shortaddr); + uint32_t countEndpoints(uint16_t shortaddr) const; // return the number of known endpoints (0 if unknown) void setManufId(uint16_t shortaddr, const char * str); void setModelId(uint16_t shortaddr, const char * str); @@ -533,6 +534,23 @@ void Z_Devices::addEndpoint(uint16_t shortaddr, uint8_t endpoint) { } } +// +// Count the number of known endpoints +// +uint32_t Z_Devices::countEndpoints(uint16_t shortaddr) const { + uint32_t count_ep = 0; + int32_t found = findShortAddr(shortaddr); + if (found < 0) return 0; // avoid creating an entry if the device was never seen + const Z_Device &device = devicesAt(found); + + for (uint32_t i = 0; i < endpoints_max; i++) { + if (0 != device.endpoints[i]) { + count_ep++; + } + } + return count_ep; +} + // Find the first endpoint of the device uint8_t Z_Devices::findFirstEndpoint(uint16_t shortaddr) const { // When in router of end-device mode, the coordinator was not probed, in this case always talk to endpoint 1 diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 578e3c3bf..454e9b5cf 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -1157,7 +1157,7 @@ void ZCLFrame::parseResponse(void) { // Parse non-normalized attributes void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) { - convertClusterSpecific(json, _cluster_id, _cmd_id, _frame_control.b.direction, _payload); + convertClusterSpecific(json, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload); sendHueUpdate(_srcaddr, _groupaddr, _cluster_id, _cmd_id, _frame_control.b.direction); } @@ -1423,6 +1423,8 @@ int32_t Z_ApplyConverter(const class ZCLFrame *zcl, uint16_t shortaddr, JsonObje } void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) { + // source endpoint + uint8_t src_ep = _srcendpoint; // iterate on json elements for (auto kv : json) { String key_string = kv.key; @@ -1490,6 +1492,11 @@ void ZCLFrame::postProcessAttributes(uint16_t shortaddr, JsonObject& json) { ((conv_attribute == attribute) || (conv_attribute == 0xFFFF)) ) { String new_name_str = (const __FlashStringHelper*) converter->name; if (suffix > 1) { new_name_str += suffix; } // append suffix number + // else if (Settings.flag4.zb_index_ep) { + // if (zigbee_devices.countEndpoints(shortaddr) > 0) { + // new_name_str += _srcendpoint; + // } + // } // apply the transformation int32_t drop = Z_ApplyConverter(this, shortaddr, json, key, value, new_name_str, conv_cluster, conv_attribute, conv_multiplier, conv_cb); if (drop) { diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index 40545f737..c2ea81765 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -341,7 +341,7 @@ void sendHueUpdate(uint16_t shortaddr, uint16_t groupaddr, uint16_t cluster, uin // Parse a cluster specific command, and try to convert into human readable -void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, bool direction, const SBuffer &payload) { +void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, bool direction, uint16_t shortaddr, uint8_t srcendpoint, const SBuffer &payload) { size_t hex_char_len = payload.len()*2+2; char *hex_char = (char*) malloc(hex_char_len); if (!hex_char) { return; } @@ -414,11 +414,11 @@ void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, boo if (command_name) { // Now try to transform into a human readable format + String command_name2 = String(command_name); // if (direction & 0x80) then specific transform if (conv_direction & 0x80) { // TODO need to create a specific command // IAS - String command_name2 = String(command_name); if ((cluster == 0x0500) && (cmd == 0x00)) { // "ZoneStatusChange" json[command_name] = xyz.x; @@ -465,11 +465,21 @@ void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, boo String scene_payload = json[attrid_str]; json[F("ScenePayload")] = scene_payload.substring(8); // remove first 8 characters } - } else { + } else { // general case + bool extended_command = false; // do we send command with endpoint suffix + // if SO101 and multiple endpoints, append endpoint number + if (Settings.flag4.zb_index_ep) { + if (zigbee_devices.countEndpoints(shortaddr) > 0) { + command_name2 += srcendpoint; + extended_command = true; + } + } if (0 == xyz.x_type) { json[command_name] = true; // no parameter + if (extended_command) { json[command_name2] = true; } } else if (0 == xyz.y_type) { json[command_name] = xyz.x; // 1 parameter + if (extended_command) { json[command_name2] = xyz.x; } } else { // multiple answers, create an array JsonArray &arr = json.createNestedArray(command_name); @@ -478,6 +488,14 @@ void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, boo if (xyz.z_type) { arr.add(xyz.z); } + if (extended_command) { + JsonArray &arr = json.createNestedArray(command_name2); + arr.add(xyz.x); + arr.add(xyz.y); + if (xyz.z_type) { + arr.add(xyz.z); + } + } } } } diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index e0239f316..c08ff4d28 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -966,23 +966,44 @@ void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload, SBuffer buf(payload_len + 22); uint8_t seq = zigbee_devices.getNextSeqNumber(0x0000); - buf.add16(EZSP_sendUnicast); + if (shortaddr < 0xFFFC) { + // send unicast + buf.add16(EZSP_sendUnicast); - buf.add8(EMBER_OUTGOING_DIRECT); // 00 - buf.add16(shortaddr); // dest addr - // ApsFrame - buf.add16(0x0000); // ZOD profile - buf.add16(cmd); // ZDO cmd in cluster - buf.add8(0); // srcEp - buf.add8(0); // dstEp - buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame - buf.add16(0x0000); // groupId - buf.add8(seq); - // end of ApsFrame - buf.add8(0x01); // tag TODO - buf.add8(payload_len + 1); // insert seq number - buf.add8(seq); - buf.addBuffer(payload, payload_len); + buf.add8(EMBER_OUTGOING_DIRECT); // 00 + buf.add16(shortaddr); // dest addr + // ApsFrame + buf.add16(0x0000); // ZOD profile + buf.add16(cmd); // ZDO cmd in cluster + buf.add8(0); // srcEp + buf.add8(0); // dstEp + buf.add16(EMBER_APS_OPTION_ENABLE_ROUTE_DISCOVERY | EMBER_APS_OPTION_RETRY); // APS frame + buf.add16(0x0000); // groupId + buf.add8(seq); + // end of ApsFrame + buf.add8(0x01); // tag TODO + buf.add8(payload_len + 1); // insert seq number + buf.add8(seq); + buf.addBuffer(payload, payload_len); + } else { + // send broadcast + buf.add16(EZSP_sendBroadcast); + buf.add16(shortaddr); // dest addr + // ApsFrame + buf.add16(0x0000); // ZOD profile + buf.add16(cmd); // ZDO cmd in cluster + buf.add8(0); // srcEp + buf.add8(0); // dstEp + buf.add16(0x00); // APS frame + buf.add16(0x0000); // groupId + buf.add8(seq); + // end of ApsFrame + buf.add8(0x1E); // radius + buf.add8(0x01); // tag TODO + buf.add8(payload_len + 1); // insert seq number + buf.add8(seq); + buf.addBuffer(payload, payload_len); + } ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true); } diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 57ecd3764..5922b3ee3 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -992,12 +992,14 @@ void CmndZbPermitJoin(void) { if (payload <= 0) { duration = 0; - } else if (99 == payload) { - duration = 0xFF; // unlimited time } // ZNP Version #ifdef USE_ZIGBEE_ZNP + if (99 == payload) { + duration = 0xFF; // unlimited time + } + uint16_t dstAddr = 0xFFFC; // default addr SBuffer buf(34); @@ -1014,10 +1016,20 @@ void CmndZbPermitJoin(void) { // EZSP VERSION #ifdef USE_ZIGBEE_EZSP + if (99 == payload) { + ResponseCmndChar_P(PSTR("Unlimited time not supported")); return; + } + SBuffer buf(3); buf.add16(EZSP_permitJoining); buf.add8(duration); ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true); + + // send ZDO_Mgmt_Permit_Joining_req to all routers + buf.setLen(0); + buf.add8(duration); + buf.add8(0x01); // TC_Significance - This field shall always have a value of 1, indicating a request to change the Trust Center policy. If a frame is received with a value of 0, it shall be treated as having a value of 1. + // EZ_SendZDO(0xFFFC, ZDO_Mgmt_Permit_Joining_req, buf.buf(), buf.len()); TODO fix NAK/ACK first #endif // USE_ZIGBEE_EZSP ResponseCmndDone(); From f0177f3c483e4da8967baa0d741cc6a3e78901b8 Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Tue, 21 Jul 2020 07:24:14 +0200 Subject: [PATCH 15/91] Add ShutterToggleDir/ShutterStopToggleDir same function as ShutterToggle/ShutterStopToggle but based on last movement direction, not on current position (< or > 50%) --- tasmota/i18n.h | 2 ++ tasmota/xdrv_27_shutter.ino | 65 ++++++++++++++++++++++++++++--------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 70ca42a7e..fb5cbceb3 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -576,11 +576,13 @@ #define D_CMND_SHUTTER_OPEN "Open" #define D_CMND_SHUTTER_CLOSE "Close" #define D_CMND_SHUTTER_TOGGLE "Toggle" +#define D_CMND_SHUTTER_TOGGLEDIR "ToggleDir" #define D_CMND_SHUTTER_UP "Up" #define D_CMND_SHUTTER_DOWN "Down" #define D_CMND_SHUTTER_STOPOPEN "StopOpen" #define D_CMND_SHUTTER_STOPCLOSE "StopClose" #define D_CMND_SHUTTER_STOPTOGGLE "StopToggle" +#define D_CMND_SHUTTER_STOPTOGGLEDIR "StopToggleDir" #define D_CMND_SHUTTER_STOPPOSITION "StopPosition" #define D_CMND_SHUTTER_STOP "Stop" #define D_CMND_SHUTTER_POSITION "Position" diff --git a/tasmota/xdrv_27_shutter.ino b/tasmota/xdrv_27_shutter.ino index 660c5e2c3..15d5143f1 100644 --- a/tasmota/xdrv_27_shutter.ino +++ b/tasmota/xdrv_27_shutter.ino @@ -37,18 +37,18 @@ enum ShutterModes { SHT_OFF_OPEN__OFF_CLOSE, SHT_OFF_ON__OPEN_CLOSE, SHT_PULSE_O enum ShutterButtonStates { SHT_NOT_PRESSED, SHT_PRESSED_MULTI, SHT_PRESSED_HOLD, SHT_PRESSED_IMMEDIATE, SHT_PRESSED_EXT_HOLD, SHT_PRESSED_MULTI_SIMULTANEOUS, SHT_PRESSED_HOLD_SIMULTANEOUS, SHT_PRESSED_EXT_HOLD_SIMULTANEOUS,}; const char kShutterCommands[] PROGMEM = D_PRFX_SHUTTER "|" - D_CMND_SHUTTER_OPEN "|" D_CMND_SHUTTER_CLOSE "|" D_CMND_SHUTTER_TOGGLE "|" D_CMND_SHUTTER_STOP "|" D_CMND_SHUTTER_POSITION "|" + D_CMND_SHUTTER_OPEN "|" D_CMND_SHUTTER_CLOSE "|" D_CMND_SHUTTER_TOGGLE "|" D_CMND_SHUTTER_TOGGLEDIR "|" D_CMND_SHUTTER_STOP "|" D_CMND_SHUTTER_POSITION "|" D_CMND_SHUTTER_OPENTIME "|" D_CMND_SHUTTER_CLOSETIME "|" D_CMND_SHUTTER_RELAY "|" D_CMND_SHUTTER_SETHALFWAY "|" D_CMND_SHUTTER_SETCLOSE "|" D_CMND_SHUTTER_SETOPEN "|" D_CMND_SHUTTER_INVERT "|" D_CMND_SHUTTER_CLIBRATION "|" D_CMND_SHUTTER_MOTORDELAY "|" D_CMND_SHUTTER_FREQUENCY "|" D_CMND_SHUTTER_BUTTON "|" D_CMND_SHUTTER_LOCK "|" D_CMND_SHUTTER_ENABLEENDSTOPTIME "|" D_CMND_SHUTTER_INVERTWEBBUTTONS "|" - D_CMND_SHUTTER_STOPOPEN "|" D_CMND_SHUTTER_STOPCLOSE "|" D_CMND_SHUTTER_STOPTOGGLE "|" D_CMND_SHUTTER_STOPPOSITION; + D_CMND_SHUTTER_STOPOPEN "|" D_CMND_SHUTTER_STOPCLOSE "|" D_CMND_SHUTTER_STOPTOGGLE "|" D_CMND_SHUTTER_STOPTOGGLEDIR "|" D_CMND_SHUTTER_STOPPOSITION; void (* const ShutterCommand[])(void) PROGMEM = { - &CmndShutterOpen, &CmndShutterClose, &CmndShutterToggle, &CmndShutterStop, &CmndShutterPosition, + &CmndShutterOpen, &CmndShutterClose, &CmndShutterToggle, &CmndShutterToggleDir, &CmndShutterStop, &CmndShutterPosition, &CmndShutterOpenTime, &CmndShutterCloseTime, &CmndShutterRelay, &CmndShutterSetHalfway, &CmndShutterSetClose, &CmndShutterSetOpen, &CmndShutterInvert, &CmndShutterCalibration , &CmndShutterMotorDelay, &CmndShutterFrequency, &CmndShutterButton, &CmndShutterLock, &CmndShutterEnableEndStopTime, &CmndShutterInvertWebButtons, - &CmndShutterStopOpen, &CmndShutterStopClose, &CmndShutterStopToggle, &CmndShutterStopPosition}; + &CmndShutterStopOpen, &CmndShutterStopClose, &CmndShutterStopToggle, &CmndShutterStopToggleDir, &CmndShutterStopPosition}; const char JSON_SHUTTER_POS[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Position\":%d,\"Direction\":%d,\"Target\":%d}"; const char JSON_SHUTTER_BUTTON[] PROGMEM = "\"" D_PRFX_SHUTTER "%d\":{\"Button%d\":%d}"; @@ -70,6 +70,7 @@ struct SHUTTER { uint16_t close_time[MAX_SHUTTERS]; // duration to close the shutter. 112 = 11.2sec uint16_t close_velocity[MAX_SHUTTERS]; // in relation to open velocity. higher value = faster int8_t direction[MAX_SHUTTERS]; // 1 == UP , 0 == stop; -1 == down + int8_t lastdirection[MAX_SHUTTERS]; // last direction (1 == UP , -1 == down) uint8_t mode = 0; // operation mode definition. see enum type above SHT_OFF_OPEN__OFF_CLOSE, SHT_OFF_ON__OPEN_CLOSE, SHT_PULSE_OPEN__PULSE_CLOSE int16_t motordelay[MAX_SHUTTERS]; // initial motorstarttime in 0.05sec. int16_t pwm_frequency[MAX_SHUTTERS]; // frequency of PWN for stepper motors @@ -401,6 +402,9 @@ void ShutterUpdatePosition(void) Response_P("%d", (Settings.shutter_options[i] & 1) ? 100 - Settings.shutter_position[i]: Settings.shutter_position[i]); MqttPublish(stopic, Settings.flag.mqtt_power_retain); // CMND_POWERRETAIN + if (Shutter.direction[i] != 0) { + Shutter.lastdirection[i] = Shutter.direction[i]; + } Shutter.direction[i] = 0; ShutterReportPosition(true, i); rules_flag.shutter_moved = 1; @@ -726,6 +730,26 @@ void ShutterSetPosition(uint32_t device, uint32_t position) ExecuteCommand(svalue, SRC_IGNORE); } +void ShutterToggle(bool dir) +{ + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Payload toggle: %d, i %d"), XdrvMailbox.payload, XdrvMailbox.index); + if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { + XdrvMailbox.index = XdrvMailbox.payload; + } + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (dir) { + XdrvMailbox.payload = (Shutter.lastdirection[index] > 0) ? 0 : 100; + } + else { + XdrvMailbox.payload = (50 < ShutterRealToPercentPosition(Shutter.real_position[index], index)) ? 0 : 100; + } + XdrvMailbox.data_len = 0; + last_source = SRC_WEBGUI; + CmndShutterPosition(); + } +} + /*********************************************************************************************\ * Commands \*********************************************************************************************/ @@ -779,17 +803,12 @@ void CmndShutterStopClose(void) void CmndShutterToggle(void) { - //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("SHT: Payload toggle: %d, i %d"), XdrvMailbox.payload, XdrvMailbox.index); - if ((1 == XdrvMailbox.index) && (XdrvMailbox.payload != -99)) { - XdrvMailbox.index = XdrvMailbox.payload; - } - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { - uint32_t index = XdrvMailbox.index-1; - XdrvMailbox.payload = (50 < ShutterRealToPercentPosition(Shutter.real_position[index], index)) ? 0 : 100; - XdrvMailbox.data_len = 0; - last_source = SRC_WEBGUI; - CmndShutterPosition(); - } + ShutterToggle(false); +} + +void CmndShutterToggleDir(void) +{ + ShutterToggle(true); } void CmndShutterStopToggle(void) @@ -804,6 +823,18 @@ void CmndShutterStopToggle(void) } } +void CmndShutterStopToggleDir(void) +{ + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { + uint32_t index = XdrvMailbox.index-1; + if (Shutter.direction[index]) { + CmndShutterStop(); + } else { + CmndShutterToggleDir(); + } + } +} + void CmndShutterStop(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= shutters_present)) { @@ -856,6 +887,10 @@ void CmndShutterPosition(void) CmndShutterToggle(); return; } + if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_TOGGLEDIR)) { + CmndShutterToggleDir(); + return; + } if (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOP) || ((Shutter.direction[index]) && (!strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPOPEN) || !strcasecmp(XdrvMailbox.data,D_CMND_SHUTTER_STOPCLOSE)))) { XdrvMailbox.payload = -99; CmndShutterStop(); From 4584effbce672702e0cda3357bbea2de66e8bbee Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 21 Jul 2020 10:44:45 +0200 Subject: [PATCH 16/91] Change all timer references from ``Arm`` to ``Enable`` Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message --- RELEASENOTES.md | 4 +++- tasmota/CHANGELOG.md | 4 +++- tasmota/i18n.h | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5e5e3e549..59b1a263c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -63,6 +63,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Change ESP32 USER GPIO template representation decreasing template message size - Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT - Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset`` +- Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message - Fix escape of non-JSON received serial data (#8329) - Fix exception or watchdog on rule re-entry (#8757) - Add command ``Rule0`` to change global rule parameters @@ -71,7 +72,8 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add command ``SetOption97 0/1`` to switch between Tuya serial speeds 9600 bps (0) or 115200 bps (1) - Add command ``SetOption98 0/1`` to provide rotary rule triggers (1) instead of controlling light (0) - Add command ``SetOption99 0/1`` to enable zero cross detection on PWM dimmer -- Add command ``SetOption100 0/1`` to remove ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message +- Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message +- Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command ``Module2`` to configure fallback module on fast reboot (#8464) - Add commands ``LedPwmOn 0..255``, ``LedPwmOff 0..255`` and ``LedPwmMode1 0/1`` to control led brightness by George (#8491) - Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3`` diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 7dbad0a37..901dfb7e8 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -4,7 +4,9 @@ - Remove Arduino ESP8266 Core support for versions before 2.7.1 - Change to limited support of Arduino IDE as an increasing amount of features cannot be compiled with Arduino IDE -- Add command ``SetOption100 0/1`` to remove ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message +- Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message +- Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message +- Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 ### 8.3.1.6 20200617 diff --git a/tasmota/i18n.h b/tasmota/i18n.h index fb5cbceb3..a91ede963 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -481,7 +481,7 @@ // Commands xdrv_09_timers.ino #define D_CMND_TIMER "Timer" - #define D_JSON_TIMER_ARM "Arm" + #define D_JSON_TIMER_ARM "Enable" #define D_JSON_TIMER_MODE "Mode" #define D_JSON_TIMER_TIME "Time" #define D_JSON_TIMER_WINDOW "Window" From eb4164e713d86711b268dc9570759ade553389d1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 21 Jul 2020 11:03:03 +0200 Subject: [PATCH 17/91] Update RELEASENOTES.md --- RELEASENOTES.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 59b1a263c..3127bf4db 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -21,9 +21,9 @@ While fallback or downgrading is common practice it was never supported due to S ## Supported Core versions -This release will be supported from ESP8266/Arduino library Core version **2.7.2** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. +This release will be supported from ESP8266/Arduino library Core version **2.7.2.1** due to reported security and stability issues on previous Core version. This will also support gzipped binaries. -Although it might still compile on previous Core versions all support will be removed in the near future. +Support of Core versions before 2.7.1 has been removed. ## Support of TLS @@ -35,7 +35,7 @@ For initial configuration this release supports Webserver based **WifiManager** ## Provided Binary Downloads -The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.2**. +The following binary downloads have been compiled with ESP8266/Arduino library core version **2.7.2.1**. - **tasmota.bin** = The Tasmota version with most drivers. **RECOMMENDED RELEASE BINARY** - **tasmota-BG.bin** to **tasmota-TW.bin** = The Tasmota version in different languages. From 48c268a9200795a56c0bace19ec3e5104dedac67 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 21 Jul 2020 12:17:29 +0200 Subject: [PATCH 18/91] Update decode-status.py --- tools/decode-status.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/decode-status.py b/tools/decode-status.py index 22329c5f6..7539aa37a 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -152,7 +152,9 @@ a_setoption = [[ "Enable Ethernet (ESP32)", "Set Baud rate for TuyaMCU serial communication (0 = 9600 or 1 = 115200)", "Rotary encoder uses rules instead of light control", - "","","", + "Enable zerocross dimmer on PWM DIMMER", + "Remove ZbReceived form JSON message", + "Add the source endpoint as suffix to attributes", "","","","", "","","","", "","","","" @@ -239,7 +241,7 @@ else: obj = json.load(fp) def StartDecode(): - print ("\n*** decode-status.py v20200714 by Theo Arends and Jacek Ziolkowski ***") + print ("\n*** decode-status.py v20200721 by Theo Arends and Jacek Ziolkowski ***") # print("Decoding\n{}".format(obj)) From 72e3765a552d590088cf3c54940a39b8a9a143ec Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 21 Jul 2020 12:42:18 +0200 Subject: [PATCH 19/91] Add command (``S``)``SerialSend6`` \ Add command (``S``)``SerialSend6`` \ (#8937) --- RELEASENOTES.md | 1 + tasmota/CHANGELOG.md | 1 + tasmota/xdrv_08_serial_bridge.ino | 11 ++++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 3127bf4db..490280e79 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -75,6 +75,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command ``Module2`` to configure fallback module on fast reboot (#8464) +- Add command (``S``)``SerialSend6`` \ (#8937) - Add commands ``LedPwmOn 0..255``, ``LedPwmOff 0..255`` and ``LedPwmMode1 0/1`` to control led brightness by George (#8491) - Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3`` - Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 901dfb7e8..45967d240 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -7,6 +7,7 @@ - Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message - Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 +- Add command (``S``)``SerialSend6`` \ (#8937) ### 8.3.1.6 20200617 diff --git a/tasmota/xdrv_08_serial_bridge.ino b/tasmota/xdrv_08_serial_bridge.ino index b5a9143b7..210094048 100644 --- a/tasmota/xdrv_08_serial_bridge.ino +++ b/tasmota/xdrv_08_serial_bridge.ino @@ -124,7 +124,7 @@ void SerialBridgeInit(void) void CmndSSerialSend(void) { - if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) { + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 6)) { serial_bridge_raw = (XdrvMailbox.index > 3); if (XdrvMailbox.data_len > 0) { if (1 == XdrvMailbox.index) { @@ -153,6 +153,15 @@ void CmndSSerialSend(void) codes += 2; } } + else if (6 == XdrvMailbox.index) { + char *p; + uint8_t code; + char *values = XdrvMailbox.data; + for (char* str = strtok_r(values, ",", &p); str; str = strtok_r(nullptr, ",", &p)) { + code = (uint8_t)atoi(str); + SerialBridgeSerial->write(code); // "72,101,108,108" + } + } ResponseCmndDone(); } } From bdcc630886de8ad4c8c7e1db1acd68f5064beec2 Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Tue, 21 Jul 2020 18:46:52 +0200 Subject: [PATCH 20/91] Update Italian language --- tasmota/language/it_IT.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 3d26d9f09..dcc53fd68 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -403,23 +403,23 @@ #define D_DOMOTICZ_KEY_IDX "Idx - chiave" #define D_DOMOTICZ_SWITCH_IDX "Idx - switch" #define D_DOMOTICZ_SENSOR_IDX "Idx - sensore" - #define D_DOMOTICZ_TEMP "Temp" - #define D_DOMOTICZ_TEMP_HUM "Temp,Umd" - #define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Umd,Baro" - #define D_DOMOTICZ_POWER_ENERGY "Alim,Energia" - #define D_DOMOTICZ_ILLUMINANCE "Illuminazione" - #define D_DOMOTICZ_COUNT "Cont/PM1" - #define D_DOMOTICZ_VOLTAGE "Tensione/PM2.5" - #define D_DOMOTICZ_CURRENT "Corrente/PM10" - #define D_DOMOTICZ_AIRQUALITY "Qualità aria" - #define D_DOMOTICZ_P1_SMART_METER "P1SmartMeter" +#define D_DOMOTICZ_TEMP "Temp" +#define D_DOMOTICZ_TEMP_HUM "Temp,Umd" +#define D_DOMOTICZ_TEMP_HUM_BARO "Temp,Umd,Baro" +#define D_DOMOTICZ_POWER_ENERGY "Alim,Energia" +#define D_DOMOTICZ_ILLUMINANCE "Illuminazione" +#define D_DOMOTICZ_COUNT "Cont/PM1" +#define D_DOMOTICZ_VOLTAGE "Tensione/PM2.5" +#define D_DOMOTICZ_CURRENT "Corrente/PM10" +#define D_DOMOTICZ_AIRQUALITY "Qualità aria" +#define D_DOMOTICZ_P1_SMART_METER "P1SmartMeter" #define D_DOMOTICZ_UPDATE_TIMER "Intervallo aggiornamento" // xdrv_09_timers.ino #define D_CONFIGURE_TIMER "Timer" #define D_TIMER_PARAMETERS "Parametri timer" #define D_TIMER_ENABLE "Abilita timer" -#define D_TIMER_ARM "Attiva" +#define D_TIMER_ARM "Abilita" #define D_TIMER_TIME "Ora" #define D_TIMER_DAYS "Giorni" #define D_TIMER_REPEAT "Ripeti" From 93b36d5c469c2fb0a0d8269d21c0a1b614b3d5f7 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 21 Jul 2020 19:16:38 +0200 Subject: [PATCH 21/91] Change ``Ping`` now reports the hostname instead of IP address (#8948) --- tasmota/CHANGELOG.md | 1 + tasmota/xdrv_38_ping.ino | 45 +++++++++++++++++++++++++++------------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 45967d240..31231a6ad 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -8,6 +8,7 @@ - Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command (``S``)``SerialSend6`` \ (#8937) +- Change ``Ping`` now reports the hostname instead of IP address (#8948) ### 8.3.1.6 20200617 diff --git a/tasmota/xdrv_38_ping.ino b/tasmota/xdrv_38_ping.ino index 4724ee310..af6b634d5 100644 --- a/tasmota/xdrv_38_ping.ino +++ b/tasmota/xdrv_38_ping.ino @@ -58,6 +58,7 @@ extern "C" { uint32_t sum_time; // cumulated time in ms for all successful responses (used to compute the average) bool done; // indicates the ping campaign is finished bool fast; // fast mode, i.e. stop pings when first successful response + String hostname; // original hostname before convertion to IP address } Ping_t; // globals @@ -229,10 +230,22 @@ extern "C" { // ================================================================================ // Start pings // ================================================================================ - bool t_ping_start(uint32_t ip, uint32_t count) { + // returns: + // 0: OK + // -1: ping already ongoing for this address + // -2: unable to resolve address + int32_t t_ping_start(const char *hostname, uint32_t count) { + IPAddress ipfull; + if (!WiFi.hostByName(hostname, ipfull)) { + return -2; + } + + uint32_t ip = ipfull; + if (0xFFFFFFFF == ip) { return -2; } // invalid address + // check if pings are already ongoing for this IP if (t_ping_find(ip)) { - return false; + return -1; } Ping_t *ping = new Ping_t(); @@ -243,6 +256,7 @@ extern "C" { ping->min_time = UINT32_MAX; ping->ip = ip; ping->to_send_count = count - 1; + ping->hostname = hostname; // add to Linked List from head ping->next = ping_head; @@ -254,6 +268,8 @@ extern "C" { // set timers for time-out and cadence sys_timeout(Ping_timeout_ms, t_ping_timeout, ping); sys_timeout(Ping_coarse, t_ping_coarse_tmr, ping); + + return 0; } } @@ -268,18 +284,22 @@ void PingResponsePoll(void) { uint32_t success = ping->success_count; uint32_t ip = ping->ip; - Response_P(PSTR("{\"" D_JSON_PING "\":{\"%d.%d.%d.%d\":{" + Response_P(PSTR("{\"" D_JSON_PING "\":{\"%s\":{" "\"Reachable\":%s" + ",\"IP\":\"%d.%d.%d.%d\"" ",\"Success\":%d" ",\"Timeout\":%d" ",\"MinTime\":%d" ",\"MaxTime\":%d" ",\"AvgTime\":%d" "}}}"), - ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24, + ping->hostname.c_str(), success ? "true" : "false", - success, ping->timeout_count, - success ? ping->min_time : 0, ping->max_time, + ip & 0xFF, (ip >> 8) & 0xFF, (ip >> 16) & 0xFF, ip >> 24, + success, + ping->timeout_count, + success ? ping->min_time : 0, + ping->max_time, success ? ping->sum_time / success : 0 ); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_PING)); @@ -303,18 +323,15 @@ void PingResponsePoll(void) { void CmndPing(void) { uint32_t count = XdrvMailbox.index; - IPAddress ip; RemoveSpace(XdrvMailbox.data); if (count > 10) { count = 8; } // max 8 seconds - if (WiFi.hostByName(XdrvMailbox.data, ip)) { - bool ok = t_ping_start(ip, count); - if (ok) { - ResponseCmndDone(); - } else { - ResponseCmndChar_P(PSTR("Ping already ongoing for this IP")); - } + int32_t res = t_ping_start(XdrvMailbox.data, count); + if (0 == res) { + ResponseCmndDone(); + } else if (-1 == res) { + ResponseCmndChar_P(PSTR("Ping already ongoing for this IP")); } else { ResponseCmndChar_P(PSTR("Unable to resolve IP address")); } From 6d34813f45ac75be07a76dbc5eec6066ae82085d Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Tue, 21 Jul 2020 22:39:39 +0200 Subject: [PATCH 22/91] Zigbee CC2530 more robust reset --- tasmota/xdrv_23_zigbee_7_statemachine.ino | 16 ++++------------ tasmota/xdrv_23_zigbee_8_parsers.ino | 22 +++++++++++++++++++++- tasmota/xdrv_23_zigbee_9_serial.ino | 10 ++++++++++ 3 files changed, 35 insertions(+), 13 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index 50e67f91c..87bae5911 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -114,8 +114,6 @@ const uint8_t ZIGBEE_LABEL_START_ROUTER = 13; // Start ZNP as router const uint8_t ZIGBEE_LABEL_INIT_DEVICE = 14; // Init ZNP as end-device const uint8_t ZIGBEE_LABEL_START_DEVICE = 15; // Start ZNP as end-device const uint8_t ZIGBEE_LABEL_START_ROUTER_DEVICE = 16; // Start common to router and device -const uint8_t ZIGBEE_LABEL_BOOT_OK = 17; // MCU has rebooted -const uint8_t ZIGBEE_LABEL_BOOT_TIME_OUT = 18; // MCU has not rebooted const uint8_t ZIGBEE_LABEL_FACT_RESET_ROUTER_DEVICE_POST = 19; // common post configuration for router and device const uint8_t ZIGBEE_LABEL_READY = 20; // goto label 20 for main loop const uint8_t ZIGBEE_LABEL_MAIN_LOOP = 21; // main loop @@ -430,18 +428,12 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_WAIT(10500) // wait for 10 seconds for Tasmota to stabilize //ZI_MQTT_STATE(ZIGBEE_STATUS_BOOT, "Booting") - //ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting device") - ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_BOOT_TIME_OUT) // give a second chance - ZI_SEND(ZBS_RESET) // reboot cc2530 just in case we rebooted ESP8266 but not cc2530 - ZI_WAIT_RECV_FUNC(5000, ZBR_RESET, &ZNP_Reboot) // timeout 5s - ZI_GOTO(ZIGBEE_LABEL_BOOT_OK) + ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting device") - ZI_LABEL(ZIGBEE_LABEL_BOOT_TIME_OUT) - ZI_ON_TIMEOUT_GOTO(ZIGBEE_LABEL_ABORT) - ZI_SEND(ZBS_RESET) // reboot cc2530 just in case we rebooted ESP8266 but not cc2530 + ZI_CALL(&ZNP_Reset_Device, 0) // LOW = reset + ZI_WAIT(100) // wait for .1 second + ZI_CALL(&ZNP_Reset_Device, 1) // HIGH = release reset ZI_WAIT_RECV_FUNC(5000, ZBR_RESET, &ZNP_Reboot) // timeout 5s - - ZI_LABEL(ZIGBEE_LABEL_BOOT_OK) ZI_WAIT(100) ZI_LOG(LOG_LEVEL_DEBUG, kCheckingDeviceConfiguration) // Log Debug: checking device configuration ZI_SEND(ZBS_VERSION) // check ZNP software version diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index c08ff4d28..2382a97a3 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -1065,7 +1065,7 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { } // -// Callback for loading Zigbee configuration from Flash, called by the state machine +// Callback for resetting the NCP, called by the state machine // // value = 0 : drive reset pin and halt MCU // value = 1 : release the reset pin, restart @@ -1147,6 +1147,26 @@ int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t clu #ifdef USE_ZIGBEE_ZNP +// +// Callback for resetting the NCP, called by the state machine +// +// value = 0 : drive reset pin and halt MCU +// value = 1 : release the reset pin, restart +int32_t ZNP_Reset_Device(uint8_t value) { + // we use Led4i to drive the reset pin. Since it is reverted we need to pass 1 to start reset, and 0 to release reset + if (PinUsed(GPIO_LED1, ZIGBEE_EZSP_RESET_LED - 1)) { + SetLedPowerIdx(ZIGBEE_EZSP_RESET_LED - 1, value ? 0 : 1); + } else { + // no GPIO so we use software Reset instead + if (value) { // send reset only when we are supposed to release reset + // flush the serial buffer, sending 0xFF 256 times. + ZigbeeZNPFlush(); + ZigbeeZNPSend(ZBS_RESET, sizeof(ZBS_RESET)); + } + } + return 0; // continue +} + int32_t ZNP_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { uint16_t groupid = buf.get16(2); uint16_t clusterid = buf.get16(4); diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index cd5ef3c4f..c4f214bcd 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -302,6 +302,16 @@ void ZigbeeInitSerial(void) #ifdef USE_ZIGBEE_ZNP +// flush any ongoing frame, sending 256 times 0xFF +void ZigbeeZNPFlush(void) { + if (ZigbeeSerial) { + for (uint32_t i = 0; i < 256; i++) { + ZigbeeSerial->write(0xFF); + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEEZNPSENT " 0xFF x 255")); + } +} + void ZigbeeZNPSend(const uint8_t *msg, size_t len) { if ((len < 2) || (len > 252)) { // abort, message cannot be less than 2 bytes for CMD1 and CMD2 From a1fc5d48909aa7f1799c3348fec647609c6ace09 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 22 Jul 2020 09:34:35 +0200 Subject: [PATCH 23/91] Fix telegram restart loop Fix telegram restart loop (#8619) --- tasmota/xdrv_40_telegram.ino | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tasmota/xdrv_40_telegram.ino b/tasmota/xdrv_40_telegram.ino index a7beb5005..f99a121b7 100644 --- a/tasmota/xdrv_40_telegram.ino +++ b/tasmota/xdrv_40_telegram.ino @@ -57,7 +57,7 @@ BearSSL::WiFiClientSecure_light *telegramClient = nullptr; static const uint8_t Telegram_Fingerprint[] PROGMEM = USE_TELEGRAM_FINGERPRINT; struct { - String message[3][6]; // amount of messages read per time (update_id, name_id, name, lastname, chat_id, text) + String message[3][6]; // Amount of messages read per time (update_id, name_id, name, lastname, chat_id, text) uint8_t state = 0; uint8_t index = 0; uint8_t retry = 0; @@ -67,6 +67,7 @@ struct { bool recv_enable = false; bool echo_enable = false; bool recv_busy = false; + bool skip = true; // Skip first telegram if restarted } Telegram; bool TelegramInit(void) { @@ -172,7 +173,7 @@ void TelegramGetUpdates(String offset) { // } // ]} -// AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str()); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("TGM: Response %s"), response.c_str()); // parsing of reply from Telegram into separate received messages int i = 0; //messages received counter @@ -349,10 +350,14 @@ void TelegramLoop(void) { Telegram.state++; } } else { - if (Telegram.message[0][0].toInt() && (Telegram.message[Telegram.index][5].length() > 0)) { - String logging = TelegramExecuteCommand(Telegram.message[Telegram.index][5].c_str()); - if (logging.length() > 0) { - TelegramSendMessage(Telegram.message[Telegram.index][4], logging); + if (Telegram.skip) { // Skip first update as it may be a restart (again) + Telegram.skip = false; + } else { + if (Telegram.message[0][0].toInt() && (Telegram.message[Telegram.index][5].length() > 0)) { + String logging = TelegramExecuteCommand(Telegram.message[Telegram.index][5].c_str()); + if (logging.length() > 0) { + TelegramSendMessage(Telegram.message[Telegram.index][4], logging); + } } } Telegram.message[0][0] = ""; // All messages have been replied - reset new messages From 0fc41f302e38e68078e78f8ae6f5c603b6d01fc3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 22 Jul 2020 09:36:18 +0200 Subject: [PATCH 24/91] Update xdrv_40_telegram.ino --- tasmota/xdrv_40_telegram.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xdrv_40_telegram.ino b/tasmota/xdrv_40_telegram.ino index f99a121b7..92fca7c90 100644 --- a/tasmota/xdrv_40_telegram.ino +++ b/tasmota/xdrv_40_telegram.ino @@ -350,7 +350,7 @@ void TelegramLoop(void) { Telegram.state++; } } else { - if (Telegram.skip) { // Skip first update as it may be a restart (again) + if (Telegram.skip) { // Skip first update after restart as it may be a restart (again) Telegram.skip = false; } else { if (Telegram.message[0][0].toInt() && (Telegram.message[Telegram.index][5].length() > 0)) { From d8c4240656c1406c004d8b5223cf9602815a8417 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 22 Jul 2020 10:07:07 +0200 Subject: [PATCH 25/91] Prep Zigbee reset GPIO --- tasmota/language/bg_BG.h | 1 + tasmota/language/cs_CZ.h | 1 + tasmota/language/de_DE.h | 1 + tasmota/language/el_GR.h | 1 + tasmota/language/en_GB.h | 1 + tasmota/language/es_ES.h | 1 + tasmota/language/fr_FR.h | 1 + tasmota/language/he_HE.h | 1 + tasmota/language/hu_HU.h | 1 + tasmota/language/it_IT.h | 1 + tasmota/language/ko_KO.h | 1 + tasmota/language/nl_NL.h | 1 + tasmota/language/pl_PL.h | 1 + tasmota/language/pt_BR.h | 1 + tasmota/language/pt_PT.h | 1 + tasmota/language/ro_RO.h | 1 + tasmota/language/ru_RU.h | 1 + tasmota/language/sk_SK.h | 1 + tasmota/language/sv_SE.h | 1 + tasmota/language/tr_TR.h | 1 + tasmota/language/uk_UA.h | 1 + tasmota/language/zh_CN.h | 1 + tasmota/language/zh_TW.h | 1 + tasmota/tasmota_template.h | 5 ++++- tasmota/tasmota_template_ESP32.h | 5 ++++- tasmota/xdrv_23_zigbee_9_serial.ino | 6 ++++++ 26 files changed, 37 insertions(+), 2 deletions(-) diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index ca4afb0bc..f0ff9b818 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "Нулиране OLED" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index b07d032e7..f85fc4439 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 3517251be..05d72f4db 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index 8eaff86f0..ea2db9c98 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 1ae054f0e..9a79758d8 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 04116ea2a..02f41e118 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 8aea1b4cc..05bbf565e 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee TX" #define D_SENSOR_ZIGBEE_RXD "Zigbee RX" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 TX" #define D_SENSOR_SOLAXX1_RX "SolaxX1 RX" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index f7a721739..2db6b36ab 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index f521c06fd..917d2a155 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index dcc53fd68..4f74a9477 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "Ripristino OLED" #define D_SENSOR_ZIGBEE_TXD "Zigbee - TX" #define D_SENSOR_ZIGBEE_RXD "Zigbee - RX" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 - TX" #define D_SENSOR_SOLAXX1_RX "SolaxX1- RX" #define D_SENSOR_IBEACON_TX "iBeacon - TX" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index d635d1d65..61c9ba720 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index b024dc538..139bf4837 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index 0ecea1a77..c31dc569a 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index be5d98464..dcb308ae9 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index c489327a7..a34d0e1d1 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index 23f160f19..fa01b1705 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index b033ebcd1..3079c00ac 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 9e5cc35e0..09402307c 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index ac416e9b5..c6b3ef835 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index f402cf803..010228272 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 97cd77f91..1f8bb46b1 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 10f609c64..7b925abc6 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 4c52eef18..6031e82a8 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -647,6 +647,7 @@ #define D_SENSOR_OLED_RESET "OLED Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee Tx" #define D_SENSOR_ZIGBEE_RXD "Zigbee Rx" +#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" #define D_SENSOR_SOLAXX1_TX "SolaxX1 Tx" #define D_SENSOR_SOLAXX1_RX "SolaxX1 Rx" #define D_SENSOR_IBEACON_TX "iBeacon TX" diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 25adf6b62..2247372d1 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -241,6 +241,7 @@ enum UserSelectablePins { GPIO_LMT01, // LMT01 input counting pin GPIO_IEM3000_TX, // IEM3000 Serial interface GPIO_IEM3000_RX, // IEM3000 Serial interface + GPIO_ZIGBEE_RST, // Zigbee reset GPIO_SENSOR_END }; // Programmer selectable GPIO functionality @@ -335,7 +336,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_TCP_TXD "|" D_SENSOR_TCP_RXD "|" D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE "|" D_SENSOR_LMT01_PULSE "|" - D_SENSOR_IEM3000_TX "|" D_SENSOR_IEM3000_RX + D_SENSOR_IEM3000_TX "|" D_SENSOR_IEM3000_RX "|" + D_SENSOR_ZIGBEE_RST ; const char kSensorNamesFixed[] PROGMEM = @@ -605,6 +607,7 @@ const uint8_t kGpioNiceList[] PROGMEM = { #ifdef USE_ZIGBEE GPIO_ZIGBEE_TX, // Zigbee Serial interface GPIO_ZIGBEE_RX, // Zigbee Serial interface + GPIO_ZIGBEE_RST, // Zigbee reset #endif #ifdef USE_MHZ19 GPIO_MHZ_TXD, // MH-Z19 Serial interface diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index bb1574a77..ddd13d87b 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -138,6 +138,7 @@ enum UserSelectablePins { GPIO_TELEINFO_ENABLE, // Teleinfo Enable Receive Pin GPIO_LMT01, // LMT01 input counting pin GPIO_IEM3000_TX, GPIO_IEM3000_RX, // IEM3000 Serial interface + GPIO_ZIGBEE_RST, // Zigbee reset GPIO_SENSOR_END }; enum ProgramSelectablePins { @@ -235,7 +236,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_ETH_PHY_POWER "|" D_SENSOR_ETH_PHY_MDC "|" D_SENSOR_ETH_PHY_MDIO "|" D_SENSOR_TELEINFO_RX "|" D_SENSOR_TELEINFO_ENABLE "|" D_SENSOR_LMT01_PULSE "|" - D_SENSOR_IEM3000_TX "|" D_SENSOR_IEM3000_RX + D_SENSOR_IEM3000_TX "|" D_SENSOR_IEM3000_RX "|" + D_SENSOR_ZIGBEE_RST ; const char kSensorNamesFixed[] PROGMEM = @@ -451,6 +453,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { #ifdef USE_ZIGBEE AGPIO(GPIO_ZIGBEE_TX), // Zigbee Serial interface AGPIO(GPIO_ZIGBEE_RX), // Zigbee Serial interface + AGPIO(GPIO_ZIGBEE_RST), // Zigbee reset #endif #ifdef USE_MHZ19 AGPIO(GPIO_MHZ_TXD), // MH-Z19 Serial interface diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index c4f214bcd..34555441f 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -292,6 +292,12 @@ void ZigbeeInitSerial(void) zigbee_buffer = new SBuffer(ZIGBEE_BUFFER_SIZE); // AddLog_P2(LOG_LEVEL_INFO, PSTR("ZigbeeInit Mem3 = %d"), ESP_getFreeHeap()); } + + if (PinUsed(GPIO_ZIGBEE_RST)) { + pinMode(Pin(GPIO_ZIGBEE_RST), OUTPUT); + digitalWrite(Pin(GPIO_ZIGBEE_RST), 1); + } + zigbee.active = true; zigbee.init_phase = true; // start the state machine zigbee.state_machine = true; // start the state machine From 6f320780a043e0d0ac96d8d0d19852f1fc69a3ab Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 22 Jul 2020 10:12:24 +0200 Subject: [PATCH 26/91] Change zigbee reset using new GPIO --- tasmota/xdrv_23_zigbee_8_parsers.ino | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 2382a97a3..738a67c8b 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -1070,9 +1070,13 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { // value = 0 : drive reset pin and halt MCU // value = 1 : release the reset pin, restart int32_t EZ_Reset_Device(uint8_t value) { +/* // we use Led4i to drive the reset pin. Since it is reverted we need to pass 1 to start reset, and 0 to release reset if (PinUsed(GPIO_LED1, ZIGBEE_EZSP_RESET_LED - 1)) { SetLedPowerIdx(ZIGBEE_EZSP_RESET_LED - 1, value ? 0 : 1); +*/ + if (PinUsed(GPIO_ZIGBEE_RST)) { + digitalWrite(Pin(GPIO_ZIGBEE_RST), value); } else { // no GPIO so we use software Reset instead if (value) { // send reset only when we are supposed to release reset @@ -1153,9 +1157,13 @@ int32_t Z_PublishAttributes(uint16_t shortaddr, uint16_t groupaddr, uint16_t clu // value = 0 : drive reset pin and halt MCU // value = 1 : release the reset pin, restart int32_t ZNP_Reset_Device(uint8_t value) { +/* // we use Led4i to drive the reset pin. Since it is reverted we need to pass 1 to start reset, and 0 to release reset if (PinUsed(GPIO_LED1, ZIGBEE_EZSP_RESET_LED - 1)) { SetLedPowerIdx(ZIGBEE_EZSP_RESET_LED - 1, value ? 0 : 1); +*/ + if (PinUsed(GPIO_ZIGBEE_RST)) { + digitalWrite(Pin(GPIO_ZIGBEE_RST), value); } else { // no GPIO so we use software Reset instead if (value) { // send reset only when we are supposed to release reset From eec6869a0a276d5057d78734a4894d345a37ad0d Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Wed, 22 Jul 2020 19:29:16 +0200 Subject: [PATCH 27/91] EZSP flow control --- tasmota/xdrv_23_zigbee_7_statemachine.ino | 2 +- tasmota/xdrv_23_zigbee_8_parsers.ino | 2 +- tasmota/xdrv_23_zigbee_9_serial.ino | 117 +++++++++++++++++----- tasmota/xdrv_23_zigbee_A_impl.ino | 11 +- 4 files changed, 100 insertions(+), 32 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index 87bae5911..f04c0ca34 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -1097,7 +1097,7 @@ void ZigbeeStateMachine_Run(void) { ZigbeeZNPSend((uint8_t*) cur_ptr1, cur_d8 /* len */); #endif // USE_ZIGBEE_ZNP #ifdef USE_ZIGBEE_EZSP - ZigbeeEZSPSendCmd((uint8_t*) cur_ptr1, cur_d8 /* len */, true); // send cancel byte + ZigbeeEZSPSendCmd((uint8_t*) cur_ptr1, cur_d8 /* len */); // send cancel byte #endif // USE_ZIGBEE_EZSP break; case ZGB_INSTR_WAIT_UNTIL: diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 738a67c8b..58d4e330b 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -1005,7 +1005,7 @@ void EZ_SendZDO(uint16_t shortaddr, uint16_t cmd, const unsigned char *payload, buf.addBuffer(payload, payload_len); } - ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true); + ZigbeeEZSPSendCmd(buf.buf(), buf.len()); } /*********************************************************************************************\ diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index 34555441f..bfec8c3bb 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -36,11 +36,15 @@ const uint32_t ZIGBEE_LED_SEND = 0; // LED<2> blinks when receiving class EZSP_Serial_t { public: - uint8_t to_ack = 0; // 0..7, frame number of next id to send + uint8_t to_send = 0; // 0..7, frame number of next packet to send, nothing to send if equal to to_end + uint8_t to_end = 0; // 0..7, frame number of next packet to send + uint8_t to_ack = 0; // 0..7, frame number of last packet acknowledged + 1 uint8_t from_ack = 0; // 0..7, frame to ack uint8_t ezsp_seq = 0; // 0..255, EZSP sequence number + SBuffer *to_packets[8] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; }; + EZSP_Serial_t EZSP_Serial; #endif // USE_ZIGBEE_EZSP @@ -493,7 +497,7 @@ void ZigbeeEZSPSendRaw(const uint8_t *msg, size_t len, bool send_cancel) { // Send an EZSP command and data // Ex: Version with min v8 = 000008 -void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len, bool send_cancel) { +void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len) { char hex_char[len*2 + 2]; ToHex_P(msg, len, hex_char, sizeof(hex_char)); AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbEZSPSend %s"), hex_char); @@ -506,20 +510,45 @@ void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len, bool send_cancel) { cmd.addBuffer(msg, len); // send - ZigbeeEZSPSendDATA(cmd.getBuffer(), cmd.len(), send_cancel); + ZigbeeEZSPSendDATA(cmd.getBuffer(), cmd.len()); } // Send an EZSP DATA frame, automatically calculating the correct frame numbers -void ZigbeeEZSPSendDATA(const uint8_t *msg, size_t len, bool send_cancel) { - uint8_t control_byte = ((EZSP_Serial.to_ack & 0x07) << 4) + (EZSP_Serial.from_ack & 0x07); - // increment to_ack - EZSP_Serial.to_ack = (EZSP_Serial.to_ack + 1) & 0x07; - // build complete frame - SBuffer buf(len+1); - buf.add8(control_byte); - buf.addBuffer(msg, len); +void ZigbeeEZSPSendDATA_frm(bool send_cancel, uint8_t to_frm, uint8_t from_ack) { + SBuffer *buf = EZSP_Serial.to_packets[to_frm]; + if (!buf) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Buffer for packet %d is not allocated"), EZSP_Serial.to_send); + return; + } + + uint8_t control_byte = ((to_frm & 0x07) << 4) + (from_ack & 0x07); + buf->set8(0, control_byte); // change control_byte // send - ZigbeeEZSPSendRaw(buf.getBuffer(), buf.len(), send_cancel); + ZigbeeEZSPSendRaw(buf->getBuffer(), buf->len(), send_cancel); +} + +// Send an EZSP DATA frame, automatically calculating the correct frame numbers +void ZigbeeEZSPSendDATA(const uint8_t *msg, size_t len) { + // prepare buffer by adding 1 byte prefix + SBuffer *buf = new SBuffer(len+1); // prepare for control_byte prefix + buf->add8(0x00); // placeholder for control_byte + buf->addBuffer(msg, len); + // + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: adding packet to_send, to_ack:%d, to_send:%d, to_end:%d"), + EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end); + uint8_t to_frm = EZSP_Serial.to_end; + if (EZSP_Serial.to_packets[to_frm]) { + delete EZSP_Serial.to_packets[to_frm]; + EZSP_Serial.to_packets[to_frm] = nullptr; + } + EZSP_Serial.to_packets[to_frm] = buf; + EZSP_Serial.to_end = (to_frm + 1) & 0x07; // move cursor + + // ZigbeeEZSPSendDATA_frm(send_cancel, to_frm, EZSP_Serial.from_ack); + + // increment to_frame + //EZSP_Serial.to_ack = (EZSP_Serial.to_ack + 1) & 0x07; + //EZSP_Serial.to_frm = (EZSP_Serial.to_frm + 1) & 0x07; } // Receive a high-level EZSP command/response, starting with 16-bits frame ID @@ -557,23 +586,41 @@ int32_t ZigbeeProcessInputEZSP(class SBuffer &buf) { ZigbeeProcessInput(buf); } +// Check if we advanced in the ACKed frames, and free from memory packets acknowledged +void EZSP_HandleAck(uint8_t new_ack) { + if (EZSP_Serial.to_ack != new_ack) { // new ack receveid + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: new ack/data received, was %d now %d"), EZSP_Serial.to_ack, new_ack); + uint32_t i = EZSP_Serial.to_ack; + do { + if (EZSP_Serial.to_packets[i]) { + delete EZSP_Serial.to_packets[i]; + EZSP_Serial.to_packets[i] = nullptr; + } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: freeing packet %d from memory"), i); + i = (i + 1) & 0x07; + } while (i != new_ack); + EZSP_Serial.to_ack = new_ack; + } +} // Receive raw ASH frame (CRC was removed, data unstuffed) but still contains frame numbers int32_t ZigbeeProcessInputRaw(class SBuffer &buf) { uint8_t control_byte = buf.get8(0); uint8_t ack_num = control_byte & 0x07; // keep 3 LSB - if (control_byte & 0x80) { + if (control_byte & 0x80) { // non DATA frame - // non DATA frame uint8_t frame_type = control_byte & 0xE0; // keep 3 MSB if (frame_type == 0x80) { // ACK - EZSP_Serial.from_ack = ack_num; // update ack num + EZSP_HandleAck(ack_num); } else if (frame_type == 0xA0) { // NAK - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: Received NAK %d, resending not implemented"), ack_num); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Received NAK %d, to_ack:%d, to_send:%d, to_end:%d"), + ack_num, EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end); + EZSP_Serial.to_send = ack_num; + AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: NAK, resending packet %d"), ack_num); } else if (control_byte == 0xC1) { // RSTACK @@ -581,6 +628,8 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) { EZ_RSTACK(buf.get8(2)); EZSP_Serial.from_ack = 0; EZSP_Serial.to_ack = 0; + EZSP_Serial.to_end = 0; + EZSP_Serial.to_send = 0; // pass it to state machine with a special 0xFFFE frame code (EZSP_RSTACK_ID) buf.set8(0, Z_B0(EZSP_rstAck)); @@ -598,14 +647,12 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) { // Unknown AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Received unknown control byte 0x%02X"), control_byte); } - } else { + } else { // DATA Frame + + // adjust to latest acked packet + uint8_t new_ack = control_byte & 0x07; + EZSP_HandleAck(new_ack); - // DATA Frame - // check the frame number, and send ACK or NAK - if ((control_byte & 0x07) != EZSP_Serial.to_ack) { - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: wrong ack, received %d, expected %d"), control_byte & 0x07, EZSP_Serial.to_ack); - //EZSP_Serial.to_ack = control_byte & 0x07; - } // MCU acknowledged the correct frame // we acknowledge the frame too EZSP_Serial.from_ack = ((control_byte >> 4) + 1) & 0x07; @@ -651,9 +698,9 @@ void CmndZbEZSPSendOrReceive(bool send) } if (send) { // Command was `ZbEZSPSend` - if (2 == XdrvMailbox.index) { ZigbeeEZSPSendDATA(buf.getBuffer(), buf.len(), true); } + if (2 == XdrvMailbox.index) { ZigbeeEZSPSendDATA(buf.getBuffer(), buf.len()); } else if (3 == XdrvMailbox.index) { ZigbeeEZSPSendRaw(buf.getBuffer(), buf.len(), true); } - else { ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true); } + else { ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len()); } } else { // Command was `ZbEZSPReceive` @@ -785,7 +832,25 @@ void ZigbeeZCLSend_Raw(uint16_t shortaddr, uint16_t groupaddr, uint16_t clusterI } } - ZigbeeEZSPSendCmd(buf.buf(), buf.len(), true); + ZigbeeEZSPSendCmd(buf.buf(), buf.len()); +#endif // USE_ZIGBEE_EZSP +} + +// +// Send any buffered data to the NCP +// +// Used only with EZSP, as there is no replay of procotol control with ZNP +void ZigbeeOutputLoop(void) { +#ifdef USE_ZIGBEE_EZSP + // while (EZSP_Serial.to_send != EZSP_Serial.to_end) { + if (EZSP_Serial.to_send != EZSP_Serial.to_end) { // we send only one packet per tick to lower the chance of NAK + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Something to_send, to_ack:%d, to_send:%d, to_end:%d"), + EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end); + // we have a frame waiting to be sent + ZigbeeEZSPSendDATA_frm(true, EZSP_Serial.to_send, EZSP_Serial.from_ack); + // increment sent counter + EZSP_Serial.to_send = (EZSP_Serial.to_send + 1) & 0x07; + } #endif // USE_ZIGBEE_EZSP } diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 5922b3ee3..6b23590cc 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -1023,13 +1023,13 @@ void CmndZbPermitJoin(void) { SBuffer buf(3); buf.add16(EZSP_permitJoining); buf.add8(duration); - ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true); + ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len()); // send ZDO_Mgmt_Permit_Joining_req to all routers buf.setLen(0); buf.add8(duration); buf.add8(0x01); // TC_Significance - This field shall always have a value of 1, indicating a request to change the Trust Center policy. If a frame is received with a value of 0, it shall be treated as having a value of 1. - // EZ_SendZDO(0xFFFC, ZDO_Mgmt_Permit_Joining_req, buf.buf(), buf.len()); TODO fix NAK/ACK first + EZ_SendZDO(0xFFFC, ZDO_Mgmt_Permit_Joining_req, buf.buf(), buf.len()); #endif // USE_ZIGBEE_EZSP ResponseCmndDone(); @@ -1059,7 +1059,7 @@ void CmndZbEZSPListen(void) { buf.add16(group); // group buf.add8(0x01); // endpoint buf.add8(0x00); // network index - ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len(), true); + ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len()); ResponseCmndDone(); } @@ -1240,7 +1240,10 @@ bool Xdrv23(uint8_t function) } break; case FUNC_LOOP: - if (ZigbeeSerial) { ZigbeeInputLoop(); } + if (ZigbeeSerial) { + ZigbeeInputLoop(); + ZigbeeOutputLoop(); // send any outstanding data + } if (zigbee.state_machine) { ZigbeeStateMachine_Run(); } From 1709d5f73ef3ba55e88c38d25720a245574facdb Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 22 Jul 2020 20:51:44 +0200 Subject: [PATCH 28/91] Prep for ZigbeeBridge build --- platformio_tasmota_env.ini | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platformio_tasmota_env.ini b/platformio_tasmota_env.ini index 4a447da82..d0e28b990 100644 --- a/platformio_tasmota_env.ini +++ b/platformio_tasmota_env.ini @@ -38,6 +38,9 @@ build_flags = ${common.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_I [env:tasmota-ircustom] build_flags = ${common.build_flags} ${irremoteesp_full.build_flags} -DFIRMWARE_IR_CUSTOM +[env:tasmota-zbbridge] +build_flags = ${common.build_flags} -DFIRMWARE_ZBBRIDGE + [env:tasmota-BG] build_flags = ${common.build_flags} -DMY_LANGUAGE=bg_BG From 246dcea2d1e590ce11f584d8290cf9a9e6286f30 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 22 Jul 2020 21:07:40 +0200 Subject: [PATCH 29/91] new build variant ZigbeeBridge --- tasmota/tasmota_configurations.h | 258 +++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 61baee7aa..f067a7cda 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -406,6 +406,264 @@ #undef USE_DEBUG_DRIVER // Disable debug code #endif // FIRMWARE_IR + +/*********************************************************************************************\ + * [tasmota-zbbridge.bin] + * Provide an image for the Sonoff Zigbee Bridge +\*********************************************************************************************/ + +#ifdef FIRMWARE_ZBBRIDGE // ******************************************************************* + +#undef CODE_IMAGE_STR +#define CODE_IMAGE_STR "zbbridge" + +//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+13k code) +#define USE_DOMOTICZ // Enable Domoticz (+6k code, +0.3k mem) +//#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+7k code) + +//#define USE_MQTT_TLS // Use TLS for MQTT connection (+34.5k code, +7.0k mem and +4.8k additional during connection handshake) +// #define USE_MQTT_TLS_CA_CERT // Force full CA validation instead of fingerprints, slower, but simpler to use (+2.2k code, +1.9k mem during connection handshake) +// #define USE_MQTT_TLS_FORCE_EC_CIPHER // Force Elliptic Curve cipher (higher security) required by some servers (automatically enabled with USE_MQTT_AWS_IOT) (+11.4k code, +0.4k mem) +// #define USE_MQTT_AWS_IOT // Enable MQTT for AWS IoT - requires a private key (+11.9k code, +0.4k mem) + +//#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem) +#define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem) + #define USE_JAVASCRIPT_ES6 // Enable ECMAScript6 syntax using less JavaScript code bytes (fails on IE11) +#define USE_WEBSEND_RESPONSE // Enable command WebSend response message (+1k code) +#define USE_EMULATION_HUE // Enable Hue Bridge emulation for Alexa (+14k code, +2k mem) +// #define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem) +// #define USE_SENDMAIL + +//#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) +#define USE_TIMERS // Add support for up to 16 timers (+2k2 code) + #define USE_TIMERS_WEB // Add timer webpage support (+4k5 code) + #define USE_SUNRISE // Add support for Sunrise and sunset tools (+16k) + +// -- Compression --------------------------------- +#define USE_UNISHOX_COMPRESSION // Add support for string compression in Rules or Scripts + +#define USE_RULES // Add support for rules (+4k4 code) +// #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem) +// #define SUPPORT_IF_STATEMENT // Add support for IF statement in rules (+4k2 code, -332 bytes mem) +// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) + +//#define USE_SCRIPT // Add support for script + #define USE_SCRIPT_FATFS 4 // Add support for script storage on SD card (+12k code, +4k mem) + +// -- Optional modules ---------------------------- +//#define ROTARY_V1 // Add support for MI Desk Lamp +//#define USE_SONOFF_RF // Add support for Sonoff Rf Bridge +// #define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+3k code) +//#define USE_SONOFF_SC // Add support for Sonoff Sc (+1k1 code) +//#define USE_TUYA_MCU // Add support for Tuya Serial Dimmer +//#define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) +//#define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) +//#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) +//#define USE_BUZZER // Add support for a buzzer (+0k6 code) +//#define USE_ARILUX_RF // Add support for Arilux RF remote controller (+1k code, 252 iram (non 2.3.0)) +//#define USE_SHUTTER // Add Shutter support for up to 4 shutter with different motortypes (+6k code) +//#define USE_DEEPSLEEP // Add support for deepsleep (+1k code) +//#define USE_EXS_DIMMER // Add support for ES-Store WiFi Dimmer (+2k6 code) +//#define USE_HOTPLUG // Add support for HotPlug +//#define USE_DEVICE_GROUPS // Add support for device groups (+4k code) +//#define USE_PWM_DIMMER // Add support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) +// #define USE_PWM_DIMMER_REMOTE // Add support for remote switches to PWM Dimmer, also adds device groups support (+0k7 code, also includes device groups) +//#define USE_KEELOQ // Add support for Jarolift rollers by Keeloq algorithm (+4k5 code) +//#define USE_SONOFF_D1 // Add support for Sonoff D1 Dimmer + +// -- Optional light modules ---------------------- +#undef USE_LIGHT // DISABLES LIGHTS support +// #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // +// // #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow +// #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106) +// // #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_GRBW // WS2812 Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW) +// #define USE_MY92X1 // Add support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas +// #define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code) +// #define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code) +// #define USE_SONOFF_L1 // Add support for Sonoff L1 led control +//#define USE_ELECTRIQ_MOODL // Add support for ElectriQ iQ-wifiMOODL RGBW LED controller + +//#define USE_COUNTER // Enable counters +#define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices + +// #define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+2k6 code) +// #define W1_PARASITE_POWER // Optimize for parasite powered sensors + +// -- I2C sensors --------------------------------- +// #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) +#ifdef USE_I2C +// #define USE_SHT // Enable SHT1X sensor (+1k4 code) +// #define USE_HTU // Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code) +// #define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address 0x76 or 0x77) (+4k code) + #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code) +// #define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code) +// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+0k5 code) +// #define USE_ADS1115 // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) based on Adafruit ADS1x15 library (no library needed) (+0k7 code) +// #define USE_INA219 // Enable INA219 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+1k code) +// #define USE_INA226 // Enable INA226 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+2k3 code) +// #define USE_SHT3X // Enable SHT3x (I2C address 0x44 or 0x45) or SHTC3 (I2C address 0x70) sensor (+0k7 code) +// #define USE_TSL2561 // Enable TSL2561 sensor (I2C address 0x29, 0x39 or 0x49) using library Joba_Tsl2561 (+2k3 code) +// #define USE_TSL2591 // Enable TSL2591 sensor (I2C address 0x29, 0x39 or 0x49) using library Adafruit_TSL2591 (+2k3 code) +// #define USE_MGS // Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) + #define MGS_SENSOR_ADDR 0x04 // Default Mutichannel Gas sensor i2c address +// #define USE_SGP30 // Enable SGP30 sensor (I2C address 0x58) (+1k1 code) +// #define USE_SI1145 // Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) +// #define USE_LM75AD // Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) +// #define USE_APDS9960 // Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) +// #define USE_MCP230xx // Enable MCP23008/MCP23017 for GP INPUT ONLY (I2C addresses 0x20 - 0x27) providing command Sensor29 for configuration (+2k2 code) +// #define USE_MCP230xx_ADDR 0x20 // Enable MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x27 - set according to your wired setup) +// #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k code) +// #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code) +// #define USE_PCA9685 // Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) +// #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup) +// #define USE_PCA9685_FREQ 50 // Define default PWM frequency in Hz to be used (must be within 24 to 1526) - If other value is used, it will rever to 50Hz +// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) +// #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) +// #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code) +// #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) +// #define USE_RTC_ADDR 0x68 // Default I2C address 0x68 +// #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) +// #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) +// #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) +// #define USE_SPS30 // Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code) +// #define USE_ADE7953 // Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) +// #define USE_VL53L0X // Enable VL53L0x time of flight sensor (I2C address 0x29) (+4k code) +// #define USE_MLX90614 // Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code) +// #define USE_CHIRP // Enable CHIRP soil moisture sensor (variable I2C address, default 0x20) +// #define USE_PAJ7620 // Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code) +// #define USE_PCF8574 // Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x27 and 0x38 - 0x3F) (+1k9 code) +// #define USE_HIH6 // Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) +// #define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) +// #define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) +// #define USE_AHT1x // [I2cDriver43] Enable AHT10/15 humidity and temperature sensor (I2C address 0x38) (+0k8 code) +// #define USE_WEMOS_MOTOR_V1 // [I2cDriver44] Enable Wemos motor driver V1 () +// #define USE_HDC1080 // [I2cDriver45] Enable HDC1080 temperature/humidity sensor (I2C address 0x40) (+1k5 code) + +// #define USE_DISPLAY // Add I2C Display Support (+2k code) +// #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 +// #define USE_DISPLAY_LCD // [DisplayModel 1] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code) +// #define USE_DISPLAY_SSD1306 // [DisplayModel 2] Enable SSD1306 Oled 128x64 display (I2C addresses 0x3C and 0x3D) (+16k code) +// #define USE_DISPLAY_MATRIX // [DisplayModel 3] Enable 8x8 Matrix display (I2C adresseses see below) (+11k code) +// #define MTX_ADDRESS1 0x71 // [DisplayAddress1] I2C address of first 8x8 matrix module +// #define MTX_ADDRESS2 0x74 // [DisplayAddress2] I2C address of second 8x8 matrix module +// #define MTX_ADDRESS3 0x75 // [DisplayAddress3] I2C address of third 8x8 matrix module +// #define MTX_ADDRESS4 0x72 // [DisplayAddress4] I2C address of fourth 8x8 matrix module +// #define MTX_ADDRESS5 0x73 // [DisplayAddress5] I2C address of fifth 8x8 matrix module +// #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module +// #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module +// #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module +// #define USE_DISPLAY_SH1106 // [DisplayModel 7] Enable SH1106 Oled 128x64 display (I2C addresses 0x3C and 0x3D) +#endif // USE_I2C + +// // -- SPI sensors --------------------------------- +// #define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) +// #ifdef USE_SPI +// // #define USE_NRF24 // Add SPI support for NRF24L01(+) (+2k6 code) +// #ifdef USE_NRF24 +// #define USE_MIBLE // BLE-bridge for some Mijia-BLE-sensors (+4k7 code) +// #else +// #ifndef USE_DISPLAY +// #define USE_DISPLAY // Add SPI Display support for 320x240 and 480x320 TFT +// #endif +// #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) +// // #define USE_DISPLAY_EPAPER_29 // [DisplayModel 5] Enable e-paper 2.9 inch display (+19k code) +// // #define USE_DISPLAY_EPAPER_42 // [DisplayModel 6] Enable e-paper 4.2 inch display +// // #define USE_DISPLAY_ILI9488 // [DisplayModel 8] [I2cDriver38] (Touch) +// // #define USE_DISPLAY_SSD1351 // [DisplayModel 9] +// // #define USE_DISPLAY_RA8876 // [DisplayModel 10] [I2cDriver39] (Touch) +// #endif // USE_NRF24 +// #endif // USE_SPI + +// -- Serial sensors ------------------------------ +//#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) +//#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code) +//#define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) +//#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) +//#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor (+1k4) +//#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+1k1 code) +//#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop +//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code) +//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) +// #define USE_PN532_CAUSE_EVENTS // Cause event execution for PN532_UID= and PN532_DATA=[if defined] (+ 30 bytes code) + #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+1k7 code, 388 bytes mem) + #define USE_PN532_DATA_RAW // Allow DATA block to be used by non-alpha-numberic data (+ 80 bytes code, 48 bytes ram) +//#define USE_RDM6300 // Add support for RDM6300 125kHz RFID Reader (+0k8) +//#define USE_IBEACON // Add support for bluetooth LE passive scan of ibeacon devices (uses HM17 module) +//#define USE_HM10 // Add support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code) +//#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7) + +// Power monitoring sensors ----------------------- +#undef USE_ENERGY_SENSOR // Disable energy sensors (-14k code) +// #define USE_ENERGY_MARGIN_DETECTION // Add support for Energy Margin detection (+1k6 code) +// // #define USE_ENERGY_POWER_LIMIT // Add additional support for Energy Power Limit detection (+1k2 code) +// #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) +// #define USE_PZEM_AC // Add support for PZEM014,016 Modbus Energy monitor (+1k1 code) +// //#define USE_PZEM_DC // Add support for PZEM003,017 Modbus Energy monitor (+1k1 code) +// #define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) +//#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy monitor (+1k1 code) +//#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy monitor (+0k6 code) +//#define USE_DDS2382 // Add support for Hiking DDS2382 Modbus energy monitor (+0k6 code) +//#define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code) +//#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+4k1 code) +//#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter + +// -- Low level interface devices ----------------- +//#define USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor + +//#define USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI + +// -- IR Remote features -------------------------- +//#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k3 code, 0k3 mem, 48 iram) + #define USE_IR_SEND_NEC // Support IRsend NEC protocol + #define USE_IR_SEND_RC5 // Support IRsend Philips RC5 protocol + #define USE_IR_SEND_RC6 // Support IRsend Philips RC6 protocol + +// #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, max 255) + +// -- Zigbee interface ---------------------------- +#define USE_ZIGBEE +#undef USE_ZIGBEE_ZNP +#define USE_ZIGBEE_EZSP +#define USE_TCP_BRIDGE + #define USE_ZIGBEE_PANID 0x1A63 // arbitrary PAN ID for Zigbee network, must be unique in the home + #define USE_ZIGBEE_EXTPANID 0xCCCCCCCCCCCCCCCCL // arbitrary extended PAN ID + #define USE_ZIGBEE_CHANNEL 11 // Zigbee Channel (11-26) + #define USE_ZIGBEE_PRECFGKEY_L 0x0F0D0B0907050301L // note: changing requires to re-pair all devices + #define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices + #define USE_ZIGBEE_PERMIT_JOIN false // don't allow joining by default + #define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms) + + +// ------------------------------------------------ + +//#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code) + +//#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code) +//#define USE_HX711 // Add support for HX711 load cell (+1k5 code) + #define USE_HX711_GUI // Add optional web GUI to HX711 as scale (+1k8 code) + +//#define USE_TX20_WIND_SENSOR // Add support for La Crosse TX20 anemometer (+2k6/0k8 code) +//#define USE_TX23_WIND_SENSOR // Add support for La Crosse TX23 anemometer (+2k7/1k code) + +//#define USE_RC_SWITCH // Add support for RF transceiver using library RcSwitch (+2k7 code, 460 iram) + +//#define USE_RF_SENSOR // Add support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) +// #define USE_THEO_V2 // Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver (+1k4 code) +// #define USE_ALECTO_V2 // Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 using 868MHz RF sensor receiver (+1k7 code) + +//#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code) +//#define USE_A4988_STEPPER // Add support for A4988 stepper-motor-driver-circuit (+10k5 code) + +//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem) + +#endif // SONOFF_ZIGBEEBRIDGE ****************************************************************** + + + /*********************************************************************************************\ * [tasmota-lite.bin] * Provide an image without sensors From 785289234f7c67eec9bf03b8ee902dc1bd9c71e6 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 22 Jul 2020 21:25:20 +0200 Subject: [PATCH 30/91] Lights support needed for HUE Emulation --- tasmota/tasmota_configurations.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index f067a7cda..952b7b4f6 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -472,7 +472,7 @@ //#define USE_SONOFF_D1 // Add support for Sonoff D1 Dimmer // -- Optional light modules ---------------------- -#undef USE_LIGHT // DISABLES LIGHTS support +#define USE_LIGHT // Add LIGHTS support // #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // // // #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow // #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106) From ced34fa858b9ccf2239f24a24a586a96cba6bae4 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 22 Jul 2020 21:29:06 +0200 Subject: [PATCH 31/91] zbbridge --- .github/workflows/CI_github.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/CI_github.yml b/.github/workflows/CI_github.yml index 0fe2fd9c5..1f4f79f38 100644 --- a/.github/workflows/CI_github.yml +++ b/.github/workflows/CI_github.yml @@ -110,6 +110,21 @@ jobs: - name: Run PlatformIO run: platformio run -e tasmota-ir + tasmota-zbbridge: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -U platformio + platformio upgrade --dev + platformio update + - name: Run PlatformIO + run: platformio run -e tasmota-zbbridge + tasmota-BG: runs-on: ubuntu-latest steps: From da09901d8b52209ce9a9dc614be100f7c35abc0c Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 22 Jul 2020 21:32:48 +0200 Subject: [PATCH 32/91] Build firmware zbbridge --- .github/workflows/Tasmota_build.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/Tasmota_build.yml b/.github/workflows/Tasmota_build.yml index 819771059..46c7beefb 100644 --- a/.github/workflows/Tasmota_build.yml +++ b/.github/workflows/Tasmota_build.yml @@ -207,6 +207,28 @@ jobs: path: ./build_output/firmware + tasmota-zbbridge: + needs: tasmota_pull + runs-on: ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@v1 + - name: Set up Python + uses: actions/setup-python@v1 + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -U platformio + platformio upgrade --dev + platformio update + - name: Run PlatformIO + run: | + platformio run -e tasmota-zbbridge + - uses: actions/upload-artifact@v2 + with: + name: firmware + path: ./build_output/firmware + tasmota-BG: needs: tasmota_pull runs-on: ubuntu-latest From 6f9715c0da2db85801861f24c783d807b18cc973 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 23 Jul 2020 09:26:10 +0200 Subject: [PATCH 33/91] needed undef added --- tasmota/tasmota_configurations.h | 317 ++++++++++--------------------- 1 file changed, 97 insertions(+), 220 deletions(-) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 952b7b4f6..ac0b629f2 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -417,214 +417,113 @@ #undef CODE_IMAGE_STR #define CODE_IMAGE_STR "zbbridge" -//#define USE_ARDUINO_OTA // Add optional support for Arduino OTA (+13k code) -#define USE_DOMOTICZ // Enable Domoticz (+6k code, +0.3k mem) -//#define USE_HOME_ASSISTANT // Enable Home Assistant Discovery Support (+7k code) +#undef USE_ARDUINO_OTA // Disable support for Arduino OTA +#define USE_DOMOTICZ // Disable Domoticz +#undef USE_HOME_ASSISTANT // Disable Home Assistant +#undef USE_MQTT_TLS // Disable TLS support won't work as the MQTTHost is not set +#undef USE_KNX // Disable KNX IP Protocol Support +//#undef USE_WEBSERVER // Disable Webserver +//#undef USE_WEBSEND_RESPONSE // Disable command WebSend response message (+1k code) +#define USE_EMULATION // Disable Wemo or Hue emulation +#define USE_EMULATION_HUE // Disable Hue Bridge emulation for Alexa (+14k code, +2k mem common) +//#undef USE_EMULATION_WEMO // Disable Belkin WeMo emulation for Alexa (+6k code, +2k mem common) +#undef USE_CUSTOM // Disable Custom features +#undef USE_DISCOVERY // Disable Discovery services for both MQTT and web server +//#undef USE_TIMERS // Disable support for up to 16 timers +//#undef USE_TIMERS_WEB // Disable support for timer webpage +//#undef USE_SUNRISE // Disable support for Sunrise and sunset tools +//#undef USE_RULES // Disable support for rules +#undef USE_SCRIPT // Add support for script (+17k code) -//#define USE_MQTT_TLS // Use TLS for MQTT connection (+34.5k code, +7.0k mem and +4.8k additional during connection handshake) -// #define USE_MQTT_TLS_CA_CERT // Force full CA validation instead of fingerprints, slower, but simpler to use (+2.2k code, +1.9k mem during connection handshake) -// #define USE_MQTT_TLS_FORCE_EC_CIPHER // Force Elliptic Curve cipher (higher security) required by some servers (automatically enabled with USE_MQTT_AWS_IOT) (+11.4k code, +0.4k mem) -// #define USE_MQTT_AWS_IOT // Enable MQTT for AWS IoT - requires a private key (+11.9k code, +0.4k mem) - -//#define USE_KNX // Enable KNX IP Protocol Support (+9.4k code, +3k7 mem) -#define USE_WEBSERVER // Enable web server and Wifi Manager (+66k code, +8k mem) - #define USE_JAVASCRIPT_ES6 // Enable ECMAScript6 syntax using less JavaScript code bytes (fails on IE11) -#define USE_WEBSEND_RESPONSE // Enable command WebSend response message (+1k code) -#define USE_EMULATION_HUE // Enable Hue Bridge emulation for Alexa (+14k code, +2k mem) -// #define USE_EMULATION_WEMO // Enable Belkin WeMo emulation for Alexa (+6k code, +2k mem) -// #define USE_SENDMAIL - -//#define USE_DISCOVERY // Enable mDNS for the following services (+8k code, +0.3k mem) -#define USE_TIMERS // Add support for up to 16 timers (+2k2 code) - #define USE_TIMERS_WEB // Add timer webpage support (+4k5 code) - #define USE_SUNRISE // Add support for Sunrise and sunset tools (+16k) - -// -- Compression --------------------------------- -#define USE_UNISHOX_COMPRESSION // Add support for string compression in Rules or Scripts - -#define USE_RULES // Add support for rules (+4k4 code) -// #define USE_EXPRESSION // Add support for expression evaluation in rules (+3k2 code, +64 bytes mem) -// #define SUPPORT_IF_STATEMENT // Add support for IF statement in rules (+4k2 code, -332 bytes mem) -// #define SUPPORT_MQTT_EVENT // Support trigger event with MQTT subscriptions (+3k5 code) - -//#define USE_SCRIPT // Add support for script - #define USE_SCRIPT_FATFS 4 // Add support for script storage on SD card (+12k code, +4k mem) - -// -- Optional modules ---------------------------- -//#define ROTARY_V1 // Add support for MI Desk Lamp -//#define USE_SONOFF_RF // Add support for Sonoff Rf Bridge -// #define USE_RF_FLASH // Add support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB (+3k code) -//#define USE_SONOFF_SC // Add support for Sonoff Sc (+1k1 code) -//#define USE_TUYA_MCU // Add support for Tuya Serial Dimmer -//#define USE_ARMTRONIX_DIMMERS // Add support for Armtronix Dimmers (+1k4 code) -//#define USE_PS_16_DZ // Add support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) -//#define USE_SONOFF_IFAN // Add support for Sonoff iFan02 and iFan03 (+2k code) -//#define USE_BUZZER // Add support for a buzzer (+0k6 code) -//#define USE_ARILUX_RF // Add support for Arilux RF remote controller (+1k code, 252 iram (non 2.3.0)) -//#define USE_SHUTTER // Add Shutter support for up to 4 shutter with different motortypes (+6k code) -//#define USE_DEEPSLEEP // Add support for deepsleep (+1k code) -//#define USE_EXS_DIMMER // Add support for ES-Store WiFi Dimmer (+2k6 code) -//#define USE_HOTPLUG // Add support for HotPlug -//#define USE_DEVICE_GROUPS // Add support for device groups (+4k code) -//#define USE_PWM_DIMMER // Add support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) -// #define USE_PWM_DIMMER_REMOTE // Add support for remote switches to PWM Dimmer, also adds device groups support (+0k7 code, also includes device groups) -//#define USE_KEELOQ // Add support for Jarolift rollers by Keeloq algorithm (+4k5 code) -//#define USE_SONOFF_D1 // Add support for Sonoff D1 Dimmer +// -- Optional modules ------------------------- +#undef ROTARY_V1 // Disable support for MI Desk Lamp +#undef USE_SONOFF_RF // Disable support for Sonoff Rf Bridge (+3k2 code) + #undef USE_RF_FLASH // Disable support for flashing the EFM8BB1 chip on the Sonoff RF Bridge. C2CK must be connected to GPIO4, C2D to GPIO5 on the PCB +#undef USE_SONOFF_SC // Disable support for Sonoff Sc (+1k1 code) +#undef USE_TUYA_MCU // Disable support for Tuya Serial MCU +#undef USE_ARMTRONIX_DIMMERS // Disable support for Armtronix Dimmers (+1k4 code) +#undef USE_PS_16_DZ // Disable support for PS-16-DZ Dimmer and Sonoff L1 (+2k code) +#undef USE_SONOFF_IFAN // Disable support for Sonoff iFan02 and iFan03 (+2k code) +#undef USE_BUZZER // Disable support for a buzzer (+0k6 code) +#undef USE_ARILUX_RF // Disable support for Arilux RF remote controller +#undef USE_SHUTTER // Disable Shutter support for up to 4 shutter with different motortypes (+6k code) +#undef USE_DEEPSLEEP // Disable support for deepsleep (+1k code) +#undef USE_EXS_DIMMER // Disable support for EX-Store WiFi Dimmer +#undef USE_HOTPLUG // Disable support for HotPlug +#undef USE_DEVICE_GROUPS // Disable support for device groups (+3k5 code) +#undef USE_PWM_DIMMER // Disable support for MJ-SD01/acenx/NTONPOWER PWM dimmers (+4k5 code) +#undef USE_PWM_DIMMER_REMOTE // Disbale support for remote switches to PWM Dimmer +#undef USE_KEELOQ // Disable support for Jarolift rollers by Keeloq algorithm (+4k5 code) +#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) // -- Optional light modules ---------------------- -#define USE_LIGHT // Add LIGHTS support -// #define USE_WS2812 // WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // -// // #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow -// #define USE_WS2812_HARDWARE NEO_HW_WS2812 // Hardware type (NEO_HW_WS2812, NEO_HW_WS2812X, NEO_HW_WS2813, NEO_HW_SK6812, NEO_HW_LC8812, NEO_HW_APA106) -// // #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_GRBW // WS2812 Color type (NEO_RGB, NEO_GRB, NEO_BRG, NEO_RBG, NEO_RGBW, NEO_GRBW) -// #define USE_MY92X1 // Add support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas -// #define USE_SM16716 // Add support for SM16716 RGB LED controller (+0k7 code) -// #define USE_SM2135 // Add support for SM2135 RGBCW led control as used in Action LSC (+0k6 code) -// #define USE_SONOFF_L1 // Add support for Sonoff L1 led control -//#define USE_ELECTRIQ_MOODL // Add support for ElectriQ iQ-wifiMOODL RGBW LED controller +//#undef USE_LIGHT // Enable Dimmer/Light support +#undef USE_WS2812 // Disable WS2812 Led string using library NeoPixelBus (+5k code, +1k mem, 232 iram) - Disable by // +#undef USE_MY92X1 // Disable support for MY92X1 RGBCW led controller as used in Sonoff B1, Ailight and Lohas +#undef USE_SM16716 // Disable support for SM16716 RGB LED controller (+0k7 code) +#undef USE_SM2135 // Disable support for SM2135 RGBCW led control as used in Action LSC (+0k6 code) +#undef USE_SONOFF_L1 // Disable support for Sonoff L1 led control +#undef USE_ELECTRIQ_MOODL // Disable support for ElectriQ iQ-wifiMOODL RGBW LED controller +#undef USE_LIGHT_PALETTE // Disable support for color palette (+0k9 code) -//#define USE_COUNTER // Enable counters +#undef USE_COUNTER // Disable counters #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices +#undef USE_DS18x20 // Disable DS18x20 sensor +#undef USE_I2C // Disable all I2C sensors and devices +#undef USE_SPI // Disable all SPI devices +#undef USE_DISPLAY // Disable Display support +#undef USE_MHZ19 // Disable support for MH-Z19 CO2 sensor +#undef USE_SENSEAIR // Disable support for SenseAir K30, K70 and S8 CO2 sensor +#undef USE_PMS5003 // Disable support for PMS5003 and PMS7003 particle concentration sensor +#undef USE_NOVA_SDS // Disable support for SDS011 and SDS021 particle concentration sensor +#undef USE_HPMA // Disable support for Honeywell HPMA115S0 particle concentration sensor +#undef USE_SERIAL_BRIDGE // Disable support for software Serial Bridge +#undef USE_MP3_PLAYER // Disable DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop +#undef USE_AZ7798 // Disable support for AZ-Instrument 7798 CO2 datalogger +#undef USE_PN532_HSU // Disable support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) +#undef USE_ZIGBEE // Disable serial communication with Zigbee CC2530 flashed with ZNP +#undef USE_RDM6300 // Disable support for RDM6300 125kHz RFID Reader (+0k8) +#undef USE_IBEACON // Disable support for bluetooth LE passive scan of ibeacon devices (uses HM17 module) +#undef USE_GPS // Disable support for GPS and NTP Server for becoming Stratus 1 Time Source (+ 3.1kb flash, +132 bytes RAM) +#undef USE_HM10 // (ESP8266 only) Disable support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code) +#undef USE_MI_ESP32 // (ESP32 only) Disable support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) +#undef USE_HRXL // Disable support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7) +#undef USE_TASMOTA_CLIENT // Disable support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem) +#undef USE_OPENTHERM // Disable support for OpenTherm (+15k code) -// #define USE_DS18x20 // Add support for DS18x20 sensors with id sort, single scan and read retry (+2k6 code) -// #define W1_PARASITE_POWER // Optimize for parasite powered sensors +#undef USE_ENERGY_SENSOR // Disable energy sensors +#undef USE_PZEM004T // Disable PZEM004T energy sensor +#undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor +#undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor +#undef USE_MCP39F501 // Disable MCP39F501 Energy monitor as used in Shelly 2 +#undef USE_SDM120 // Disable support for Eastron SDM120-Modbus energy meter +#undef USE_SDM630 // Disable support for Eastron SDM630-Modbus energy monitor (+0k6 code) +#undef USE_DDS2382 // Disable support for Hiking DDS2382 Modbus energy monitor (+0k6 code) +#undef USE_DDSU666 // Disable support for Chint DDSU666 Modbus energy monitor (+0k6 code) +#undef USE_SOLAX_X1 // Disable support for Solax X1 series Modbus log info (+3k1 code) +#undef USE_LE01MR // Disable support for F&F LE-01MR Modbus energy meter (+2k code) +#undef USE_TELEINFO // Disable support for French Energy Provider metering telemetry -// -- I2C sensors --------------------------------- -// #define USE_I2C // I2C using library wire (+10k code, 0k2 mem, 124 iram) -#ifdef USE_I2C -// #define USE_SHT // Enable SHT1X sensor (+1k4 code) -// #define USE_HTU // Enable HTU21/SI7013/SI7020/SI7021 sensor (I2C address 0x40) (+1k5 code) -// #define USE_BMP // Enable BMP085/BMP180/BMP280/BME280 sensor (I2C address 0x76 or 0x77) (+4k code) - #define USE_BME680 // Enable support for BME680 sensor using Bosch BME680 library (+4k code) -// #define USE_BH1750 // Enable BH1750 sensor (I2C address 0x23 or 0x5C) (+0k5 code) -// #define USE_VEML6070 // Enable VEML6070 sensor (I2C addresses 0x38 and 0x39) (+0k5 code) -// #define USE_ADS1115 // Enable ADS1115 16 bit A/D converter (I2C address 0x48, 0x49, 0x4A or 0x4B) based on Adafruit ADS1x15 library (no library needed) (+0k7 code) -// #define USE_INA219 // Enable INA219 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+1k code) -// #define USE_INA226 // Enable INA226 (I2C address 0x40, 0x41 0x44 or 0x45) Low voltage and current sensor (+2k3 code) -// #define USE_SHT3X // Enable SHT3x (I2C address 0x44 or 0x45) or SHTC3 (I2C address 0x70) sensor (+0k7 code) -// #define USE_TSL2561 // Enable TSL2561 sensor (I2C address 0x29, 0x39 or 0x49) using library Joba_Tsl2561 (+2k3 code) -// #define USE_TSL2591 // Enable TSL2591 sensor (I2C address 0x29, 0x39 or 0x49) using library Adafruit_TSL2591 (+2k3 code) -// #define USE_MGS // Enable Xadow and Grove Mutichannel Gas sensor using library Multichannel_Gas_Sensor (+10k code) - #define MGS_SENSOR_ADDR 0x04 // Default Mutichannel Gas sensor i2c address -// #define USE_SGP30 // Enable SGP30 sensor (I2C address 0x58) (+1k1 code) -// #define USE_SI1145 // Enable SI1145/46/47 sensor (I2C address 0x60) (+1k code) -// #define USE_LM75AD // Enable LM75AD sensor (I2C addresses 0x48 - 0x4F) (+0k5 code) -// #define USE_APDS9960 // Enable APDS9960 Proximity Sensor (I2C address 0x39). Disables SHT and VEML6070 (+4k7 code) -// #define USE_MCP230xx // Enable MCP23008/MCP23017 for GP INPUT ONLY (I2C addresses 0x20 - 0x27) providing command Sensor29 for configuration (+2k2 code) -// #define USE_MCP230xx_ADDR 0x20 // Enable MCP23008/MCP23017 I2C Address to use (Must be within range 0x20 through 0x27 - set according to your wired setup) -// #define USE_MCP230xx_OUTPUT // Enable MCP23008/MCP23017 OUTPUT support through sensor29 commands (+1k code) -// #define USE_MCP230xx_DISPLAYOUTPUT // Enable MCP23008/MCP23017 to display state of OUTPUT pins on Web UI (+0k2 code) -// #define USE_PCA9685 // Enable PCA9685 I2C HW PWM Driver - Must define I2C Address in #define USE_PCA9685_ADDR below - range 0x40 - 0x47 (+1k4 code) -// #define USE_PCA9685_ADDR 0x40 // Enable PCA9685 I2C Address to use (Must be within range 0x40 through 0x47 - set according to your wired setup) -// #define USE_PCA9685_FREQ 50 // Define default PWM frequency in Hz to be used (must be within 24 to 1526) - If other value is used, it will rever to 50Hz -// #define USE_MPR121 // Enable MPR121 controller (I2C addresses 0x5A, 0x5B, 0x5C and 0x5D) in input mode for touch buttons (+1k3 code) -// #define USE_CCS811 // Enable CCS811 sensor (I2C address 0x5A) (+2k2 code) -// #define USE_MPU6050 // Enable MPU6050 sensor (I2C address 0x68 AD0 low or 0x69 AD0 high) (+2k6 code) -// #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code) -// #define USE_RTC_ADDR 0x68 // Default I2C address 0x68 -// #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem) -// #define USE_MAX44009 // Enable MAX44009 Ambient Light sensor (I2C addresses 0x4A and 0x4B) (+0k8 code) -// #define USE_SCD30 // Enable Sensiron SCd30 CO2 sensor (I2C address 0x61) (+3k3 code) -// #define USE_SPS30 // Enable Sensiron SPS30 particle sensor (I2C address 0x69) (+1.7 code) -// #define USE_ADE7953 // Enable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) -// #define USE_VL53L0X // Enable VL53L0x time of flight sensor (I2C address 0x29) (+4k code) -// #define USE_MLX90614 // Enable MLX90614 ir temp sensor (I2C address 0x5a) (+0.6k code) -// #define USE_CHIRP // Enable CHIRP soil moisture sensor (variable I2C address, default 0x20) -// #define USE_PAJ7620 // Enable PAJ7620 gesture sensor (I2C address 0x73) (+2.5k code) -// #define USE_PCF8574 // Enable PCF8574 I/O Expander (I2C addresses 0x20 - 0x27 and 0x38 - 0x3F) (+1k9 code) -// #define USE_HIH6 // Enable Honeywell HIH Humidity and Temperature sensor (I2C address 0x27) (+0k6) -// #define USE_DHT12 // [I2cDriver41] Enable DHT12 humidity and temperature sensor (I2C address 0x5C) (+0k7 code) -// #define USE_DS1624 // [I2cDriver42] Enable DS1624, DS1621 temperature sensor (I2C addresses 0x48 - 0x4F) -// #define USE_AHT1x // [I2cDriver43] Enable AHT10/15 humidity and temperature sensor (I2C address 0x38) (+0k8 code) -// #define USE_WEMOS_MOTOR_V1 // [I2cDriver44] Enable Wemos motor driver V1 () -// #define USE_HDC1080 // [I2cDriver45] Enable HDC1080 temperature/humidity sensor (I2C address 0x40) (+1k5 code) -// #define USE_DISPLAY // Add I2C Display Support (+2k code) -// #define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0 -// #define USE_DISPLAY_LCD // [DisplayModel 1] Enable Lcd display (I2C addresses 0x27 and 0x3F) (+6k code) -// #define USE_DISPLAY_SSD1306 // [DisplayModel 2] Enable SSD1306 Oled 128x64 display (I2C addresses 0x3C and 0x3D) (+16k code) -// #define USE_DISPLAY_MATRIX // [DisplayModel 3] Enable 8x8 Matrix display (I2C adresseses see below) (+11k code) -// #define MTX_ADDRESS1 0x71 // [DisplayAddress1] I2C address of first 8x8 matrix module -// #define MTX_ADDRESS2 0x74 // [DisplayAddress2] I2C address of second 8x8 matrix module -// #define MTX_ADDRESS3 0x75 // [DisplayAddress3] I2C address of third 8x8 matrix module -// #define MTX_ADDRESS4 0x72 // [DisplayAddress4] I2C address of fourth 8x8 matrix module -// #define MTX_ADDRESS5 0x73 // [DisplayAddress5] I2C address of fifth 8x8 matrix module -// #define MTX_ADDRESS6 0x76 // [DisplayAddress6] I2C address of sixth 8x8 matrix module -// #define MTX_ADDRESS7 0x00 // [DisplayAddress7] I2C address of seventh 8x8 matrix module -// #define MTX_ADDRESS8 0x00 // [DisplayAddress8] I2C address of eigth 8x8 matrix module -// #define USE_DISPLAY_SH1106 // [DisplayModel 7] Enable SH1106 Oled 128x64 display (I2C addresses 0x3C and 0x3D) -#endif // USE_I2C +#undef USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor +#undef USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI +#undef USE_MAX31865 // Disable support for MAX31865 RTD sensors using softSPI +#undef USE_IR_REMOTE // Disable IR driver -// // -- SPI sensors --------------------------------- -// #define USE_SPI // Hardware SPI using GPIO12(MISO), GPIO13(MOSI) and GPIO14(CLK) in addition to two user selectable GPIOs(CS and DC) -// #ifdef USE_SPI -// // #define USE_NRF24 // Add SPI support for NRF24L01(+) (+2k6 code) -// #ifdef USE_NRF24 -// #define USE_MIBLE // BLE-bridge for some Mijia-BLE-sensors (+4k7 code) -// #else -// #ifndef USE_DISPLAY -// #define USE_DISPLAY // Add SPI Display support for 320x240 and 480x320 TFT -// #endif -// #define USE_DISPLAY_ILI9341 // [DisplayModel 4] Enable ILI9341 Tft 480x320 display (+19k code) -// // #define USE_DISPLAY_EPAPER_29 // [DisplayModel 5] Enable e-paper 2.9 inch display (+19k code) -// // #define USE_DISPLAY_EPAPER_42 // [DisplayModel 6] Enable e-paper 4.2 inch display -// // #define USE_DISPLAY_ILI9488 // [DisplayModel 8] [I2cDriver38] (Touch) -// // #define USE_DISPLAY_SSD1351 // [DisplayModel 9] -// // #define USE_DISPLAY_RA8876 // [DisplayModel 10] [I2cDriver39] (Touch) -// #endif // USE_NRF24 -// #endif // USE_SPI +#undef USE_SR04 // Disable support for for HC-SR04 ultrasonic devices +#undef USE_TM1638 // Disable support for TM1638 switches copying Switch1 .. Switch8 +#undef USE_HX711 // Disable support for HX711 load cell +#undef USE_TX20_WIND_SENSOR // Disable support for La Crosse TX20 anemometer +#undef USE_TX23_WIND_SENSOR // Disable support for La Crosse TX23 anemometer +#undef USE_WINDMETER // Disable support for analog anemometer (+2k2 code) +#undef USE_RC_SWITCH // Disable support for RF transceiver using library RcSwitch +#undef USE_RF_SENSOR // Disable support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) +#undef USE_HRE // Disable support for Badger HR-E Water Meter (+1k4 code) +#undef USE_A4988_STEPPER // Disable support for A4988_Stepper +#undef USE_THERMOSTAT // Disable support for Thermostat +#undef DEBUG_THEO // Disable debug code +#undef USE_DEBUG_DRIVER // Disable debug code -// -- Serial sensors ------------------------------ -//#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+2k code) -//#define USE_SENSEAIR // Add support for SenseAir K30, K70 and S8 CO2 sensor (+2k3 code) -//#define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) -//#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) -//#define USE_HPMA // Add support for Honeywell HPMA115S0 particle concentration sensor (+1k4) -//#define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+1k1 code) -//#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop -//#define USE_AZ7798 // Add support for AZ-Instrument 7798 CO2 datalogger (+1k6 code) -//#define USE_PN532_HSU // Add support for PN532 using HSU (Serial) interface (+1k8 code, 140 bytes mem) -// #define USE_PN532_CAUSE_EVENTS // Cause event execution for PN532_UID= and PN532_DATA=[if defined] (+ 30 bytes code) - #define USE_PN532_DATA_FUNCTION // Add sensor40 command support for erase, setting data block content (+1k7 code, 388 bytes mem) - #define USE_PN532_DATA_RAW // Allow DATA block to be used by non-alpha-numberic data (+ 80 bytes code, 48 bytes ram) -//#define USE_RDM6300 // Add support for RDM6300 125kHz RFID Reader (+0k8) -//#define USE_IBEACON // Add support for bluetooth LE passive scan of ibeacon devices (uses HM17 module) -//#define USE_HM10 // Add support for HM-10 as a BLE-bridge for the LYWSD03 (+5k1 code) -//#define USE_HRXL // Add support for MaxBotix HRXL-MaxSonar ultrasonic range finders (+0k7) - -// Power monitoring sensors ----------------------- -#undef USE_ENERGY_SENSOR // Disable energy sensors (-14k code) -// #define USE_ENERGY_MARGIN_DETECTION // Add support for Energy Margin detection (+1k6 code) -// // #define USE_ENERGY_POWER_LIMIT // Add additional support for Energy Power Limit detection (+1k2 code) -// #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) -// #define USE_PZEM_AC // Add support for PZEM014,016 Modbus Energy monitor (+1k1 code) -// //#define USE_PZEM_DC // Add support for PZEM003,017 Modbus Energy monitor (+1k1 code) -// #define USE_MCP39F501 // Add support for MCP39F501 Energy monitor as used in Shelly 2 (+3k1 code) -//#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy monitor (+1k1 code) -//#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy monitor (+0k6 code) -//#define USE_DDS2382 // Add support for Hiking DDS2382 Modbus energy monitor (+0k6 code) -//#define USE_DDSU666 // Add support for Chint DDSU666 Modbus energy monitor (+0k6 code) -//#define USE_SOLAX_X1 // Add support for Solax X1 series Modbus log info (+4k1 code) -//#define USE_LE01MR // Add support for F&F LE-01MR modbus energy meter - -// -- Low level interface devices ----------------- -//#define USE_DHT // Disable support for DHT11, AM2301 (DHT21, DHT22, AM2302, AM2321) and SI7021 Temperature and Humidity sensor - -//#define USE_MAX31855 // Disable MAX31855 K-Type thermocouple sensor using softSPI - -// -- IR Remote features -------------------------- -//#define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k3 code, 0k3 mem, 48 iram) - #define USE_IR_SEND_NEC // Support IRsend NEC protocol - #define USE_IR_SEND_RC5 // Support IRsend Philips RC5 protocol - #define USE_IR_SEND_RC6 // Support IRsend Philips RC6 protocol - -// #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, max 255) - -// -- Zigbee interface ---------------------------- #define USE_ZIGBEE #undef USE_ZIGBEE_ZNP #define USE_ZIGBEE_EZSP @@ -638,28 +537,6 @@ #define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms) -// ------------------------------------------------ - -//#define USE_SR04 // Add support for HC-SR04 ultrasonic devices (+1k code) - -//#define USE_TM1638 // Add support for TM1638 switches copying Switch1 .. Switch8 (+1k code) -//#define USE_HX711 // Add support for HX711 load cell (+1k5 code) - #define USE_HX711_GUI // Add optional web GUI to HX711 as scale (+1k8 code) - -//#define USE_TX20_WIND_SENSOR // Add support for La Crosse TX20 anemometer (+2k6/0k8 code) -//#define USE_TX23_WIND_SENSOR // Add support for La Crosse TX23 anemometer (+2k7/1k code) - -//#define USE_RC_SWITCH // Add support for RF transceiver using library RcSwitch (+2k7 code, 460 iram) - -//#define USE_RF_SENSOR // Add support for RF sensor receiver (434MHz or 868MHz) (+0k8 code) -// #define USE_THEO_V2 // Add support for decoding Theo V2 sensors as documented on https://sidweb.nl using 434MHz RF sensor receiver (+1k4 code) -// #define USE_ALECTO_V2 // Add support for decoding Alecto V2 sensors like ACH2010, WS3000 and DKW2012 using 868MHz RF sensor receiver (+1k7 code) - -//#define USE_HRE // Add support for Badger HR-E Water Meter (+1k4 code) -//#define USE_A4988_STEPPER // Add support for A4988 stepper-motor-driver-circuit (+10k5 code) - -//#define USE_TASMOTA_CLIENT // Add support for Arduino Uno/Pro Mini via serial interface including flashing (+2k3 code, 44 mem) - #endif // SONOFF_ZIGBEEBRIDGE ****************************************************************** From 354b6375cdb54143fe59fb6e7fdc1e5838b02bd1 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 23 Jul 2020 10:31:37 +0200 Subject: [PATCH 34/91] mv firmware bridge to commit folder --- .github/workflows/Tasmota_build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/Tasmota_build.yml b/.github/workflows/Tasmota_build.yml index 46c7beefb..1a9a011de 100644 --- a/.github/workflows/Tasmota_build.yml +++ b/.github/workflows/Tasmota_build.yml @@ -1504,6 +1504,7 @@ jobs: [ ! -f ./mv_firmware/tasmota-ir*.* ] || mv ./mv_firmware/tasmota-ir*.* ./firmware/tasmota/ [ ! -f ./mv_firmware/tasmota-display.* ] || mv ./mv_firmware/tasmota-display.* ./firmware/tasmota/ [ ! -f ./mv_firmware/tasmota-knx.* ] || mv ./mv_firmware/tasmota-knx.* ./firmware/tasmota/ + [ ! -f ./mv_firmware/tasmota-zbbridge.* ] || mv ./mv_firmware/tasmota-zbbridge.* ./firmware/tasmota/ [ ! -f ./mv_firmware/tasmota32.* ] || mv ./mv_firmware/tasmota32.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/tasmota32-sensors.* ] || mv ./mv_firmware/tasmota32-sensors.* ./firmware/tasmota32/ [ ! -f ./mv_firmware/tasmota32-minimal.* ] || mv ./mv_firmware/tasmota32-minimal.* ./firmware/tasmota32/ From 9adc4b420228c5534fc2dd7c6da05f892c07559b Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 23 Jul 2020 11:39:51 +0200 Subject: [PATCH 35/91] Add new module 75 supporting Sonoff Zigbee Bridge Add new module 75 supporting Sonoff Zigbee Bridge (#8583) --- tasmota/tasmota_template.h | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 2247372d1..8c62a236b 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -799,7 +799,7 @@ enum SupportedModules { SONOFF_S31, ZENGGE_ZF_WF017, SONOFF_POW_R2, SONOFF_IFAN02, BLITZWOLF_BWSHP, SHELLY1, SHELLY2, PHILIPS, NEO_COOLCAM, ESP_SWITCH, OBI, TECKIN, APLIC_WDP303075, TUYA_DIMMER, GOSUND, ARMTRONIX_DIMMERS, SK03_TUYA, PS_16_DZ, TECKIN_US, MANZOKU_EU_4, OBI2, YTF_IR_BRIDGE, DIGOO, KA10, ZX2820, MI_DESK_LAMP, SP10, WAGA, SYF05, SONOFF_L1, - SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, + SONOFF_IFAN03, EXS_DIMMER, PWM_DIMMER, SONOFF_D1, SONOFF_ZB_BRIDGE, MAXMODULE}; #define USER_MODULE 255 @@ -812,7 +812,7 @@ const char kModuleNames[] PROGMEM = "Sonoff S31|Zengge WF017|Sonoff Pow R2|Sonoff iFan02|BlitzWolf SHP|Shelly 1|Shelly 2|Xiaomi Philips|Neo Coolcam|ESP Switch|" "OBI Socket|Teckin|AplicWDP303075|Tuya MCU|Gosund SP1 v23|ARMTR Dimmer|SK03 Outdoor|PS-16-DZ|Teckin US|Manzoku strip|" "OBI Socket 2|YTF IR Bridge|Digoo DG-SP202|KA10|Luminea ZX2820|Mi Desk Lamp|SP10|WAGA CHCZ02MB|SYF05|Sonoff L1|" - "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1" + "Sonoff iFan03|EXS Dimmer|PWM Dimmer|Sonoff D1|Sonoff ZbBridge" ; const uint8_t kModuleNiceList[] PROGMEM = { @@ -850,6 +850,9 @@ const uint8_t kModuleNiceList[] PROGMEM = { #endif #ifdef USE_SONOFF_RF SONOFF_BRIDGE, // Sonoff Bridge +#endif +#ifdef USE_ZIGBEE_EZSP + SONOFF_ZB_BRIDGE, #endif SONOFF_SV, // Sonoff Development Devices SONOFF_DEV, @@ -2278,6 +2281,25 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, // GPIO12 GPIO_LED1_INV, // GPIO13 WiFi Blue Led - Link and Power status 0, 0, 0, 0 + }, + { // SONOFF_ZB_BRIDGE - Sonoff Zigbee Bridge (ESP8266) + GPIO_LED1_INV, // GPIO00 Led (0 = On, 1 = Off) - Status + GPIO_ZIGBEE_TX, // GPIO01 Zigbee Serial control + 0, // GPIO02 + GPIO_ZIGBEE_RX, // GPIO03 Zigbee Serial control + GPIO_ZIGBEE_RST, // GPIO04 ZIgbee Reset + 0, + // GPIO06 (SD_CLK Flash) + // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) + // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) + 0, // GPIO09 (SD_DATA2 Flash QIO) + 0, // GPIO10 (SD_DATA3 Flash QIO) + // GPIO11 (SD_CMD Flash) + 0, + GPIO_LEDLNK_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link status + 0, 0, + GPIO_KEY1, // GPIO16 Button + 0 } }; From efbcb9b80e61cb8d5e0044bef0aa5f1a9e3713dd Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 23 Jul 2020 12:06:29 +0200 Subject: [PATCH 36/91] Create readme.txt --- tools/fw_zbbridge/readme.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 tools/fw_zbbridge/readme.txt diff --git a/tools/fw_zbbridge/readme.txt b/tools/fw_zbbridge/readme.txt new file mode 100644 index 000000000..38049cf62 --- /dev/null +++ b/tools/fw_zbbridge/readme.txt @@ -0,0 +1,2 @@ +The ncp-uart-sw_6.7.6_115200.ota is for EZSP v8 compatible hosts +The ncp-uart-sw_6.5.5_115200.ota its for older like current ZHA From 0c743e0901c95e06634b297963812e2054426f25 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 23 Jul 2020 12:08:32 +0200 Subject: [PATCH 37/91] EFR32 firmware for ZigbeeBridge --- tools/fw_zbbridge/ncp-uart-sw_6.5.5_115200.ota | Bin 0 -> 181500 bytes tools/fw_zbbridge/ncp-uart-sw_6.7.6_115200.ota | Bin 0 -> 190272 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 tools/fw_zbbridge/ncp-uart-sw_6.5.5_115200.ota create mode 100644 tools/fw_zbbridge/ncp-uart-sw_6.7.6_115200.ota diff --git a/tools/fw_zbbridge/ncp-uart-sw_6.5.5_115200.ota b/tools/fw_zbbridge/ncp-uart-sw_6.5.5_115200.ota new file mode 100644 index 0000000000000000000000000000000000000000..3655bf8a42d76ca880f5f6ebcaef7c72b184ca67 GIT binary patch literal 181500 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 literal 0 HcmV?d00001 diff --git a/tools/fw_zbbridge/ncp-uart-sw_6.7.6_115200.ota b/tools/fw_zbbridge/ncp-uart-sw_6.7.6_115200.ota new file mode 100644 index 0000000000000000000000000000000000000000..e8fed03b06138e10cf5598fe6e0e44c795a6e9c2 GIT binary patch literal 190272 zcmV()K;OUX7p4OU00000000940RRB{1_t^N0002A<^ljDRFk<>ia0S@o3z*Y2M75i z0000%eDNCB%_sU$LBO3u1v+@I*h<(*QG$8Yur+woY^-iR-nQlW2M76(<^li@(WI5R zdoErh z;-$BY(gJNBJja@y$Vtxp#XlTx{ia?dRct|cT2h1YV(8Qljkt9vD*(Wx1cmdyoxD(rwLFP68GLn4h19in_pKV`iN8>2i<0reimthMd{PH}9M$Ay+XM&PO z9jeTcy0g~*XyZ)KVrV_2MzGYvEurt?=#x$fhvK(7tV24a{&^QGtneYVEK(Q%FlaQm z6h^M5vEAMH7Lon$!@MC*L$LBArldde9swIh{+}D9Hy9!p328TVrs^np&;;LeB=U@q8TuJii4s1udRQhw59zRkKL48bZ{VP~+R#=5bm@_S3AA`H!? zjf)cP#Ved1BC^oY^C-R{!!0_B#5?f(biLr@xN9|;fsRn3+Vkf%XNgrqHPDk2pWvf3=1-__$<+; zh`D6^nOrgh*emC_S+Z9ysLmLq!V%L$Vzf_1s4$s?UO9Sg`IbX6@I|bld`*TBN{TXN zweTX>CXv7;%v#5L(G_9Wr%%0^-LfNLhZk1cVbX~|_vsOfx5OK6wUwLAdMy*QuhdGr z;z+OAMlvvwl)bP@l9=w@YKEo5d`D6{zqxQZSF0Bi?!B;~6Q>lKt1w~Qhg=&c(za4x zGv5MYmDRx@LJr;ifP>s#4xU|`ZfVsk98M$Pluxzq2o?=MPbV^l3|_icq+w&QclVTC zNfMAP(%VldB?30Nw9sC#KAm}HwN0Y%Wfegj!eH4fst-Gqbe8!47xV=5OOpw8YW})t zxwpSBW8hT7M<4zdNqk!R~#) z7f0J$ruJ`m325K{Ejcc1c0>2x7$$USbl@zW!=Anu)g)SF2|rI^uSDb@Fa1RrP^2N~ zxFeRPoU4dXkrH&GSl^kCgPpX~PQ=kqg&FO=tQjXEN01y!5#Rmhew58k`-GmK2-z@~ zdbtulg34~Z!mF~Wjox%~-l(2ZWX*#z#rP~^M9|CCCxxR*8BTl{uZo=M`x6HSQ48fI zl$Z-Hu1m%)hNz1*KS93ie(ZmV31P`MP%q_;yV%rBhCf|;&+If!k3HM)szn!myiZlF z6i6dj?qyyZid^8myPEC=LPMF5he{&%Nd|pnycYM!{PCbN z$rhoJy0YwmcWsceN)J-?leb_y+5^pf?@7cqIkaSisWv*meW0+&Y@r6pw}>19pOMM> ziyn&?LlK$Br!G&(uVd6pVIpquu~yB}^tPvA0g{xsIDS zp{^OE`2Llf&yNmz=fSd6VgFWG%X_t+`7f|(7yDYd^m>RpF?guB{uSTxbh5`j3I$wz zRQSN^1$I4(Rgo1Q4?tgiHigLn*mXf^S*h&+t)Y;<#kB_kg=#%aF2BwHVn;9Y0V1M` zTD5>$=s%2T(nr|vh+?0L91YZegD!5~G&!}nbaNy%w^>c}ansfIvDrtOZ?kG#R6OBm z-4IoR`R^`%AlRrT4W2 ze`vqs6!@7zjC#bW=gLXXLZk>$$)+rR+~nEF2p~5O-bY(=n@t>$lln+PK^Zk=w zL5?1<%E&V=@y>=#o^Duv)R8iuH?p90Q^a7VmE-|U)K;Q1@C-=Jsn%P+W->GFbSZG# zc$6Z|@kbVbOE)V~LfX-{ecg)9(L3_Gf!}8y>!EH4{jBafQqfrSML%q-;gG-b=~+vB zm>WtvhB1)|6GW2w$+^T2qKk}L=l>-{=#CkBBx7!qxPOrPVw;aLk9E>a(bPF~eKiii zz89JoRhcPDt;6PpBFH#g^BDl zJh-Y)tt}04oC4!B|Iiy}*vb$IsS$l@vAo3uzg=+eGS_A@+p+7LdFbj~Pw_8n&t?c} zItEZ5l_4ILFU^~lnp6jFl^wlTh*ZmXP|D*pQ`E#)qdTN}-F-Qx61t2Ht|o7LfXN<$xVEy2%a%U4k2P)@HT zCY-7IkVDf=zDj`iBMAc5%lR?%!%L&25fKpLb>Qmx4uv2?Kg`%4LG6*Yc?x{do|(+-i{t5^{N>Z?3d283|+X+6aKR7ojdJDc+ogHr*W z4h{H^iBe58s%PBF0(8S-^CbsG`pXfGu|H7qgAwVv@!iGiCD3^%$6Di_e@^_X!xN7G zl(<;hu;zzidxL{2e8qmtF zl?Gv*5})%Den#zygo4NDyWID*O|=k|y8cxxCzzWwNw9r9tc=?*^%W)l$J{w5lGp^fpcRoZAuONm{~%| zLiJ=?r^4LuRujzdq}FEc(L?TRkZF} z_y^4A0#)k`T8iV(QC{B@-*O=f-x9_`OCEithsDIHS>sX~{{&0MjbRu52Pz0-q2tQS zGZ{BSt|poZ!em25%Agi2o$*W2*+lI{aj8rhfv#9%D!S}5bS~h<6GF2zhBY@)S1J=V zsHoBUJArPyVnE}6iyHIZjEBp9AfKdwk4k%{9ECXTyJoV^ku2;c@j#8)sB2i1kBKGY0St#lE{FXe4(X%s(O=XcjWE)sImtKbb-dA z&$tD*u%&6H)eQPg!?cmU+F1gqDM#DAMue!z?Y7G9OSJoh-%brRYckA;-D{n zna>Fd8A3Gd)AdDEB42-XZvKymzhlWIn`;2k9;@LG1w#%fq6P5*^z##o;^J_+=y8}! zmx0A?4UB*NPt!YBfHAb2yx18(82sy8m1vNkOg+gO(n8MlpL1@<7mH^Cr3dTR^tNxbAVD3s zFUe|;pP;&XI6=|^n+4EFRYI4a%QL`W>&z@z&wyu*xytkMPadwWCf zI||`0+xvA^<&!}mgHX%ghU9bR*u0twI`$rCgQ2XFQ^mvz(A%=You&*6Ygnt#921ow z1|7_mLTI_wxM$T6rqZ$ur|%6M6aM5>b%?%mri+J5kx@`-eE$9_KX&n*ACwd1#!{bYv^$j+Bv~Ggbj*R8=vJ- zot6)8h6+;U$}Ow0Ct9^-_+l}1Qp#)YCYULVJ;KD^*KWK2)*VLLG@DBPhsy-HGS zT5C{CM_jB<+Fv-sD+piG*_0||mEh;jM6Wq&!tXWgM~H?)`u2H+?*qweS0=TsmMQsL zIdqP|`QIIL#}^vz2G3B%*(vedCHayZwtGqO+*0GB?E^NGg~;4AHoG;3IV#Pqe0jNB_U zM!`TebMXG)+tJbjlyzjH0UyZW2W{k$)=n|W1g(0}^w@q^AB41f+yqpiz$9JmvgoiH z(~C(UNst{&UPZ=8%1-Iq?krNesC3$2-lRjU@cd*XsMwOWL0Gbsr(CPT<7UicLRm|C z0A$d%#wJg{A`~jAO?N(Ra`e;=cpUBr>=e6>E3GV%*}h>+*3w>ETztvoj?3Piwu$YO zjeeox@c(GOogbYRYMQ{Ku?jEIh0mBiSPuT(V+@p;c1f94M~{w#F2gOi25Y^Xbr|wI z+L6|L=^Q{#Z$B_p%^zeBL?P81mvB#awRSLSB%QxhGxIX0CqlS?8f||%V(d51Cnwhb zOp$77g_QUE_cLqkQKnj$e(6CU5GHHh3eb!Inx8q#GOwpm%||x4WnbLbLoex&@}pzg z*Z*%zCQN^slB@KY#egp*MX8eibn6i5O!SoxOxBFNJwJ5=u+dq}SG zwOX6mORxI($1&hBVyY^Qns#uMAssBnChA)kbBki4E)W>JhJ)V~^A@>I#rw#8!UMbr zLJ`y}KO${Ez7I<4`_6{NHb$#jjvK{u^dUcH!0AJ_cF{sQWc%5`i(1H(r($zgWbfQz zb-qrkiujyPQIRYlmLMXWdZYKl)mixjlG01DM}CE{9VvM`p?E`$i1LP_S8>!SYl z(M(~V+@OOaKrE&f$Fu0|>Aa(Us2)|_Ki&Dtiecx~szn$4FmPtHu{PZ5I0};ml-MM5 z3*ZZ10TwJ@M_in8X2N2;7F;pmX2YDna=a&9vqq@(lv<6~jx2>lpCKE}&~lXOI;zPm z@!s6`U^Lfc&8@if}t0w&K5t_e5c?>*LK+L2>?^=SN~C zB=L{NV?0kEiDp#nKqAe7>f5j3TQ5XzCKIR)T92?F$=V=VUDOK9?0P3=u3T}E= zL2mhZuVj?Si3)1n%x>e+nF>U}OAJ};WLgRC=*WP==c!%}p(eJxV`0Q@4O`VE|6)SJ zyp7vP&g~II7MLf`@E&AiRsM}ksKObflH2gY^75@^#Aq1GGv?cmCPVYEc=Wre2Q+f zRl-SF1qjK2KRV6AYTSyp-;!WV_ky|UdXA`jT3vXKIss!=-3!*Qo=SBn#LuI4TKDP$qn#;< zqyFMrIp1Do!O~KwaGFnnDTh>X=phyD-=NDg(`yyY*ZfRlZ#DHIxyVB33E?B})N-!{mD6X>7d_=*# z@dm;}O@hOP}cf8)SvTIsRcCWcODJVLi-oIr^$tBNFkH z?z}UjxkAal(X9@;=zz&jf^`XSZvXy)p^K zIBX0|V%}lS_bv#aFDhzuxv+36mkAXo5Ro|NX$`b{*qAhBaKtC!giH6xVc%%Swf`}DJCZ1aER`Q18K-9{u?HXz77Z_d=U7&PD{9+gXP1l; z2x`VZOCl&d7&L%9rCUD+C6SgS;o&97vmR;HS_NMxE$`}#COSR!SJi4B2t8Uj&>CQw z>>{+!S@56*Rws1Ddv_y+ny&o+2JtJgDTKk9PpaZYQU!?#=wHPMvPfi=RLAdq&|Q2Y zLdvB_k+mE>d0Rh9RdnSBAqg-&$N?jtmn5x>jvJ=M+L*#+As{P(69chUCkK)3rM;@{ zcpjtjay%@rFpC+=j`YvhwpoFS)OmeC<;6O`Rq>MltnGaGzIB^<)_6M`$w+u&^smJC zF#jn89f>8IKt@V!BIwL>~BGI47!uq~ui4WyM%4oQLLv6~g#nb*g)Rcjq_6qyZOpc0n#a5t(C@MaZ^ zSCA=MaTy>Q=k91PVa(FwQb{4LAz=L=1y8d!a!dM_#M~|H->qyDRMh;Q=TS51DN(@u zC-_E(CWHzw^^r*5Gei#>VdplN@ zcsiY=aT-Y*iN~QL3~~44NnDU@4ttY&G8d;Lq1KL8(`v}ge<@iH2Dnv#WE0gB9El)RP!<3MO}BMqg5CTSpYKC75Ub-lt8C^ zYa+AdwfYh1Llj)QN{u&){}u7sbI0oWp(=#+Z&;M+ECq|>Xj)GQovIoQB!E_r0(jh> zlREd;ld8eIokEvi?JnHB(R=tRfwU^qCJqbq9z!+)!!qNKfMzf1e#~8Z3O&nH==?w2 z{S*2Mw0OJv{Xpck!irc%ZZYffM7#GRi~Up!v^LDtX(W>S(o$gSiu#rRGWDng9g`;4 zp76#Z(PLqOa7(UkDPeKgC}=?oYuJB^@y$Zw$8U(9V@6J!$aoS{&*Faodg_gEi|Qxj zqmtS+9m1pyIeql4INC(k7>oMj2U5@KD05SYgS!nPY5XcQROZBHBc`i*mwKb5DwCDC z`-Cq%7T_I}u@w}cmnH}okr15LO?rWYaCp<-1$>rd8wS_VTj~BsqBij6J`{5xF>WTt zKU@a)GIlO6lWaO>b2ew1Uoc2o;vK1}Lq{>jnX9)?^U9HUY3AHmsjZX_6WIj-U0(A8 zAy72hGTTDSludJ9?3+8{`ZxmD9L0-KiBxb7j~AZ-;hJ-O|V@gbqaqjRE55BJQ z!iJ&h_X@zbqm$cvH5E`B;I?NzX4E^Po@H{K{nQp5;gA|FY%*^qg#IQi{h$wnn$Fna z3Cy<)TsZ%AKRZXfM?M3I+ z{?Z-o^80&Xn0EC{daMR?LXPYnZRv@V*zYU620=yeiE6m5+-2}wh6NO}V*^7e*o`6! zV)j0VnrRU%kTPwN`a4*moVVH3(7AIq7{43<33D2)0R>UENfKh?LHUlQ*igACU`?F4 zZ>4Pu5W2>U)ldGmdNiv%iS?nIqFcjrAP%@o6A%_mdd3~+G)Ov>G+uHBPrTD@vY!z| zp~}wLAhzx85F>wO8=AsFF!oVjLQW6xG{1&8I;B5Dsalh4<67CsXY=u>D+dzX%fv$t zi{#^Q(#Q&3b@-gIt)K8rG9lVng;Qj!sI8`+eegt^1iF)Kc%vnuin z)kbSFXz`$Bl1Sn-hVF;+*?LFTcT&Pvc!oGup0&x6v4+71Qz**e)AUDp^ZGd>NTSZ7(O@O zZNtq6tqi;e{~oO2y6WUbtF7ml19s9-s6a?h%8cJn3y;15Mx>D( zyvWopX1Nl|4`E&QnOj{I)~Foq_gu%y#}EJU0W5iPOy@%_wXe-2%YKn3#fTZr_Jhy} z?d25LVsKUA8EUS#Ave(fbzhj41mHH$oFx8)Qipd17dx~d>I`wA-M2aD0vy;}D%MEO z%~k}$?dyq6HFQQGQc64Xt+G8Wc&h`eD%3vwU4J*n4m{=PPy?|bStfS0_CHLOJTc47 zc>aG<9%UHJYvDP4F;_M3m%%{8k8^623?}5nnV(0B#&bDB?_F0hKg1lTk<)FXd#oPF z0M9c4ea9*!!p;ryegq#*FVSs_Q*^lx*m)6GoBvmZ+hq0R{~5$kGkG~IDt6!sk@(ez zZrtl61AHNkD;h#$!6E!Y?T>;{X+n#KP~t~XrH1##jYWoNQl^dSbTgf@2@`vC4))M% z@yp{d+D<@FRWxvi1?I9D*cE?~8O>M+>N+PH5tc>z;>bVh!ukiWj9;|cRua&KlCB2E zYt4*ASy{q;@J;mUdd4xl~dI!~hn_Ko7{$|r&VeZM@T&S{I~czl7X z4NJ3l7(x+nP{QJcEnH5`QfT~lP-lX#S6H8g^@V=U!YwU03lvVW^1x z-w$)}sZ+#t_{DEo8*D~t#3cU(l)vZ0R&B=TJ@Cl?GVA-Nu)BQ!$Y;EboN>FU23O@( z(^F5W+edeK4t&B#DX5Pvi~}>ZS7u)D^_lidAL);y)2rR>?6}i|K_1tnGyY>Foi&$z zXLu`}tbd-#clmaup6Q~-k(4716yBa7!YA;$Q#+fs5xwHm^X@)b>5UsN1fDJ{zM=ab zL8__J_(qg*iNV$nfyq2cJi4k~pXSB1ZT6KnC38k1ml?X%wY)rhk;Z|eM557ed< z(+!sR<SBsPu2gk#t0zNF0JY*OC*>7)2ktgnE2EBsdR(f z2V(Poo=-KE-~>y_>Uim;P7A;`6Dk2sP@B|wb9-9)YW`Ldm`(6tAgC8t68l4*&r!+L z@FD}Na3;$DEwRj3J@F^{1l+leBRI2drYU>I$S8e&r+ZsOfSkZW*gvqxt__i5h{D!p zAu8=v;u0nWphuVdO$qnNNXwl=)oQY6x6!J95d~_Is+u=N74fAoirI2Oh65K5XgtP6 z69vA;my%^aAOPn0jM)Dy`W&MfxQKE(pAsRu3ZwcPa6u%-$Asrno>5$B^}}N|LynlW8uC32j$!giwr#9CB@MwYDJ?2#h|^DTiml_Lwza*PHuO zJl`#1dd>=oL-V_y9tRyhFGR24LyeAdEi~I0i*+P&)j(ry%M%B0kvC0Adm#Z7D?|Dm zEEwuFhun_@AZ$1767M*i(-%`s4CQ#t@UDc$siMDrTnF4|Ecw>|6#=ohh*=A+LJfQ2 zw1Tjg&tZ)s)6E_5@`ej1iIB5lF40Q1fg){2T&ZTW0HAu@zTuf*ZRfynRAOSwR-c@S zh*`5sNYUS6*S8Hu7U`d2N6s14+4_B(cLyje;ssO^8=mg1=`k#j*&L!7C5fnT#1e1u z_}979S=pdTq{X))h>-dAt4+;dK9^0WU{r0$g@@DAi_c_twYf9&paOj0>HN#R@^Gik zPOpQW^$nuTGIZWdy`pcCxlW9|BRh#>%As2sLtLvI+fu4}uzu&pDB%Duy>F)F7>8%B z6gS>kdKrM8&{5On(+PO}|4KeMgEc_nh?AjX>stGfnIH0()QrIKYZ<_4(L;!T#4x%h z4BCb;bEZ>(sZqB(J~L2SR0#8Z;N*E?OT5Bhc_3f@aeLlCg=+jAud!IJ7mk`R9ybg2 zn--FVBXlykeZG*P38aMSQv-G69z|jY61`f#4Z6pfJRk5q4Q!{JJEG zhz_svy~CpE=7F6Rm}kTkbl;+&oqV5czspNn9_om@UUi5$;JuB!W=T^Y*HK=Fm>%JZ zQKo7XFyrzCqxLV-wsL zmy)E&4~Gv7kEYhVt+Xb-__hYG?9e*O@Mk;cU_Qiks98l%Queg7C#`DKoRrn0k7QWv z{2)?@yH11!W}NO|7#kR6ond#qGAq$Lmo-;yF$$1q!&F>ocmrAfi~KngxZN5SeSn2UyP}inQB<4w)LGlPKTBbhnCktVK99N zR%>q{g$}MLf(LyXp)R0#voOaAI?=&p1Hf03rO;Pp=v3YU%6yd`-%)+%{=1IWviL_lG^`EteOCL{ ztqHTBdc`7SInAG;m|J^Cgr=x}?J^i3t@>fXAzs|~c!jOMJcWij%z@BBlic}BR;&Vk-jXIza)BNB(;qOWl-}swF#j{K4 zH#vHh%f+Jqh3}mkTZ`!edQAX{?H5;+0_4>NR?2W_e-{BH{6f^9{{09Rg=-Mf8w$oc z7IbMY#TKC42u|dG6lP6n>p@^piX?iN&GmG_nh_XGqB*MjJGrO5H=NiC z!j_Y24^7X*uIQUjFliaJIJ`U-UvTislqQ8!cziXyYlnBFk{SQjrUfNuFcx~Or`(f^ za&OU|do9UtR&-T~8j@gqv*HEZz`8)!oy9CgPt$F&&lm|JF;3qc(B7&gpu~O3lMI)d z2aw^IqSD4chE{m*%gAF6?)cV&dH4Iy(;3-E`-rCxe?V;{Tk*25cMGSx;v*nBfg;Sl z*y<%S+_)RSl;hqEUi9WfI{~4V1pd~>{lYlFgM(B~;~tzvCOGb;G5FzN4LxyL22Y0K zIF~oVGo-jbYe((|e>tbBrR@rFP58l7_r{k!Eq|x~Z ze~{>OLI#c)M`tsw@?PAmScO5MSJ3QTiotN%;R2>(Ww6tvp&e6) z-cr^4AsBjKGz}3)81MI$f(Te-!|qC>UOCj{bZitJj(i>ukbca!Igrc=X&G67w@wS- zBaPKl3M}d|OHqBVE*MEzPUSS<@>P}-C7O)*ssYZ8NOUCJE}#7kvO`me6Ma*}0v%cw zJ#EKR+}PwYOt}3R2(p)r*wDc9$Rj?InjbaLVzwirF&VquU!T-%COS$b=v|)sKmYE3 zR;T8kUj;yE%2R$`&JUDfi34uIn^H{Be@Ez37Hrk}dX02OjU^c0b2Kt`=mD2%L_k$g zvh7Q#y^n42dF#WFGgLz;PD5S6>Q&t94i6uocKo^78s?64RMM+4=dg&Ixa z{b|~Oet?k;6f^D4m?x3<4dXf;`s|BHha~ijW<6-8lwl5CzFWIR+&3k&2R%xn0Zy2( z^IYG5OrhRbxcvyb&5Px|+fody$wV1N9>b>seWL??zHdyyr7*MO!73Fw*WNV!b*t?0 zfa?+O-nZiD7FZ^Mqvm~80`*HT`RVpSs}F1A|92kLM8QMM8QSv<#iN0JCm+>p#0<4a zaet^XHx^uDMNqu;4h-i2WR-{`*QETT#7J0$K-1-_kkI)phRqh5g1bF!PD)aSLXfD6HcVn>C54(b0;TqVnbib^UpI-@U6AeBv}(hVAtg!SYTV- z2ffZnV(46Oi8sib(BSi$G+M{C^vLg$*qTOP=dZA0aFZ~S9v@?7Q4!|16oib<1(%Ii z>8fI1h0LQ(vJrzP(T@rF7e%>5$Q10&oa@+-f8l(ITraVQ<1dzZ&&|nE+0poZJ z(QywK`0dMXkOs9XDLth!748@B6PJyu-JH51YKcJgaK7}Pia(%DrjZK_nt@np7AOhu zNubzH(*518rKkQeLt4|2RCXu-SnG*R-aucbAW#z3Y%`{z65J&wXa72DCi;X?p;F^+5vJe==)9Kc?4qHrRux`dWwU7hFVmm4DPpaP2ZpMrPw{L=Qs9scA@)H0!cD3ivg)(SPqh;6+d&?wRIpI+w2DW%kLF#KFK{3m# zV!n7I^1jk-<;bJQ7s{U09V;KDk&m~CxuL?4o0Ycp^vH#WV)^D)c6%4$SQZXBy(={a zG;E$$uxMtxIfAfe>{*<>rtjxzcrT`o)0o*ya@Mb7Q~PWI0GHouh;9HOEZQe}_d?~* zV`pA80{t79+cRe38pAM9#L*~d!MB69o5YP8Xaw}W4jhkU$v6&a|Cz8~lH*E+m*0sg zuG6uOz#%Ls-aD*seBu#X)?+fhmnHJ^B?r1M*sp6ho}QWAj;*k#Z8 zEi{HrG(UWhNWgvebfYvn8X|PUFh?nuJxAUwAq=6)VaxPLysHSe&_g0D0Tp#@^8^-5 z3ttWkkR69%$1B@^%nJvUtKWEKckMN8k}i=rWxYSHn%=9Yr;7CYI=xu*=~dq1dS~X> z5C00ko#%BHMJAmz)n#V`X3;l?_U{#st^$vRX~iAx-G75NZrGfGGT%Ce^5ft z{dx^d7%%QLz{62}^u%GPy_{teelsU8JD+)EOu5|r*ka2RS_6?z#+V;B{)s7hdHL7v z_-C(aqNO5Jlli>=hMWC%_*h2a^uP2=5rpdutS35Vn^@t#FX!gX79s4bY2TBM zWeul{%Co#nanmxm@kiX@t%US7T<}0tZpx!wV?>$+jzG5T?i+^OX@5SU2}sQsrcsU2 z=7P&8wo+=caj@DTjgOc%kGWYmy5)^-+r?Ue1=fwuA6u%Tw5P6!{}dYW3ocY{DkoR} zHNghv7iVQ(PTF5Vpf1o@2z{2X3R%s!u!SZOy< zpGyh}&Ea9Gu?Lw>>X|*cwnzyV!2|u#K=4-GPc0m=eag+I+4C;*M zpAk|05MgnS!A%uL|5~%(kFlTjJ4J9RPw;rI(#VKA#iG+~FK-Ww1;F zJTGu~k%6q6scB}B7puz$jrP}M_H@%H(UGtkn^JIf$y6-NdyV%ebcOtoF=zpTBV8Ds&nT1NVDnYPq1kl_DVp}9aOkmj zGgC!6DY-!uL=O|Cbz2_nYs}UC*G#+Iw6_6kI;L<8KlYG%b75fS$P>G|D2W2C8Gs)P z%8&nayIT`Ai=0jEIy3=H0%FGX#^O=#Qd#B#f@6?bUVHY;zjRnTec$ksNP&H`YL&H| zV~_sYrZJirO38}r>O3~4a7W{+&2--zHKu0ReEg057* z(yGRC%yu|YHdGCuyWc+I6b~R{;baiL#@2VnE`VlT#%~>wUJ*j?NpHtkz+jHkVSB{} zj$Rj^uu=mhE5c6rTv4|XBSKriEJSqoFNZ8wy+HK#@GXOs17BJlE$|hxtg-!0cbo2h zZWeWNoil%B3|QOA)b-(a-%If&J$IU=^{#~fm1#KP@j#R&f4b!^1EH00GL?Sj;e_x6j2~U2x^X(Udq~lgiLq8d zLt2aW+xH;3(|9~JxM@-h8JGHtuDgd|?O<9I=C0-9*8ff4Gj6C1efkqH@+trnuVD&Ct0ty3^p^F7mrL+k;xEexCjt=Zm6Ft)_@ZZq~a`B zQCo45(f~+$p}B4rq!k=PQG-I;=_<)_?R-LE49Aubu#1Hof7Pc)!@T-IEQj&9pXW1`~pnTyqc6NEDjdx4>|dR{gX0Oh+lo58?8NrBE+vqZ035n)b6d zZw$WSIpgcvg5-?|m%Z2#Kxxx)&Ffv6&R3@OBi_C=)A4MRT|^HYDUTuvzzWkK{S@v? z=CX#W=LPfI?;QLj^HKh!yArRJ3Jh$2&?uwd)XhuPL1YPOW*~L2p0@OOCU2I)O(&q! z-|8JmTEx&izk+efa%2b8P%QksRWY0%)8?)afBChor^%ei872`!ULyL__l_Q~Za;*7KFy=JImN&w9*x*F|^t?-Oa0yvEz%5b# zy)}Hv6$Tnv8|L2bXlSzKwKY-s&|Y&6WQSOR!3)rj+k^RLs^s@;K|~4&Lz0)1KdjZC zrbPVcR#acK>KCp@fr|8fD%J%?RyPfhXjdBGkn}S!*zv6uc0@QW<@)~YCmO9@x3p{Z zf8CmJqknPF00N_FZC>Wbi`lytfFY*Wz1y6RSV|04sQ2_;lPC3A5!$!3b-MXaqMAp< zwRrVEOT)V^fr#~InW0|yU?7LJD+#)aLRg&6=YK1p7wxXs(NpFK4F6&<`Q+a)n{+W& z!A>%mx$$7awT>X!`?1;?-bj{)K42ifGv_QGc|xX{fF%O3tqEEJ5+kke zfoX)C@!vzSg1E;4nWWE%{|aXk8{1z3T$$7sD`54Q+Qa9QsT>xmt38$8@;8k1zeuZ~ zx59?}7#J;%Iequxgoh~c_;UWNsBA7|pJ;tBrJE8Es+~*ymsaSGMz!K2=Xb2}tswba zL=cPp7;dsEi6=JZjNa1t2NCuth^{v5Gwhp~3_4#JFJ(n%%fU@5TR`49%sOp zvJb~lghY={(CqSH29@9THrUnO){pfoA+lG&W^5Usd#7Miagyo(`ms zRs~Fcv5?bDCk>%lPyofBGN%O7z~C8;Wm9(U_KQ0ZR;d0YF<_XF`ox zg7OOTWSsuoCsp24(%1|mp;I{T?`bos0)FISuXz_voZ$4Mza>!bLSFA5H-&s@7Axhr z<9@vW1M)PDnq)mOyxjlMr$*C2AJ#vSgThaDc@@8&*ypP+TYD5&Neju59-@!mR+%~c z*Cn&cX~u`p6LN+&a7%dKViynaC@ZJVu2>=|F5>mcDhyIx!!+&HP;RFve@Da@TP^XT zbug^&Gx;^l@!1abS`@l(x*gjQ+@YE}8Gu8Sk;yk1Z+w5g4_HfhAx_m5$|_FK9T)Ma z1b{p=9-mN%rJ)6_a46Sxj2f54h9duoMcS{&~#HIk?{(bpRWQVB)on_b3hD$lBGb z{O1OWv#mE7fg?~39MNtYBN7%BZqj+U?Up+z=ZLlMEuc9@&$ZvjMHETeTRH!0T!de! zFfZKP)GLWX*Z&^Trn?+Nn)#=*kCtEVeJUZtjMQ(oZ|f6UP3#E95z3%Bt-dNu%Lkop z(1@i>9zl33viANwy_eRKx9DHOOo!%g##henS;XKfYV-)`8+il3LBI1e!-c{-E`n5^+#%+? zyshl-dHTT??}gO6wq5{Ut9jrw@;mzo%fib$KU|E>{LxQpxamVH9$1|ew>l;)}^5>VKI%}T)c9G)2RE>WAKT-u)-?&BI zO4ta8EMW)#6ypv539)cZ?VZp<=gv-6KIbo1ZI~V?@fXA?77Kuvn5+$}S#gCH7UV*B z7GZdr0OL(R{6S^}&uX>UV12^}p4HfWk#zfoNUn@#3hug1b&hA943 z4|eC4KkdT8XtuZXNalnBz=k(CJ;fBw4&c>2mlPQ=(G|Wm;fQm4rrRxQ8?NgE_3C9u zL&87otVi_`fTa$vICF!wRD}vn=*C#C3xJwM*qhl@yfH35nvE(MxEEczLa{V`vpyE4 zk!}+PN5lVKZenYR4m~19cL)zL# zwKLlCgKZjGo1$Hr6500^w$Y}JN|MC1<{M#`;9N7{MtQ47NdvF~3-21SW5?xo0`u+U z9bZYD7TyJ;CVe~>%yws*$?Kng4`*rY^xQfa$?|)8+A@)WN|-#p$}1)ev4P_Xv;~O**Gk0dAZE4koIBNw z7NKa;vcyMOPN2QECH@##xQaXmQ?K>4&p5gyocy2XpiVJ((;S|61l)w+aHD&|!=!Hl zW+J){kZGuP#aT^FH<>-##k3s8#;XVCn$N3(x(ElpMjjY>WZC-_Ltb3Ou&t1Qc#8-A_tDasc2{G5nMHPeTa z-76$>Lo+AAz()9@8fe3ta{bJtDqex>__=t7A9-cwz4FFwQ;tkLZ#1>EUUOT~n^ql z=;9{M?lVhwhnhLsF(XL?CL88How|-}xt&Ll0aL0(5lxJ82yRwxq!=)Lt_R_ePe2{b>%O4%XIxtZ;&G^*LY>*oKbjp z;Ix<;u53!X!2O#>28XE6&Ly@=)}kl?(9wbcKB6wsMHBKXM~}a<>lq{0JZ(>x=J7Gd zyZ=8Ski)1B1~UD_N;|q{%OcaUNdFquf{Xd_`?6}2!$?I}H)#z!@dJnfNU6?|Lx8fLpVNj)S)(Cly zJAckssc@x`q=45p)u(<%%yxwdK98v7Ib4|@#cM8D(hRzgGT0OOP^Ca(EG(OHrMj{( zz(sY6$~^eO{6YXShAaEzmI+p_m9b)8>;30>%+*4(d| zd1>cH&{@`I^|17LQ3|N0eG`yG5_xgJkLBT4u%s<)b3}|Y2hz5>$(I&gAugy$Y~!~I zk3kvz4`~G}CUA2E@#oCzYUkoW4PO23MJdtSIpHy;KBGlfywRjd(o{FaSXbcgroD-c z%&gO|sAhZ4*~4n_wvMW926OONA<4U9F}yQ*3GKE+8Z!_FO2{7Nyda~lH67e&$H&RA zI#ajUqFhC6H@z1lVYn;i6)$%Hl{tFvD#+`kLU` zzemRC>*qw`sKm~WSGIa%uZHjBJ)RHzHPPGZsu``n3?C*a zs@pKa1m=0_^cH&<6xiZzdz;cAu>oXFrj#7-WYqDwmkTO%$95&ggHLC;-(?Zvv$qz{ zcZaQe6^Gidt$=;AuW*1G9_ih%TtgEE6#xAFpO7V4i+nuU|6JM0dQs6$HXoVj5hyyvZ{(Fh{+GM~@g&xU}y@8s4@K4kj52f0!M1FOY43<#`uX@uKLcOhfJg z5hz^ZLB9RW`kf~bb=ZklN}JPjmTo3-%}_iP#~4H z_^`!b&XdIPIFMM4Bbn)|UjBd4f1OD&Pq|pSr{tuGNM_(7D)+pDOk2OQ>N_o9rR~S_ z@9)9dZn+*&zq?@3Uo8126b{ThpG--xSf+7vko4Iar9c#CQ=ll~Fd+)V-fgCJk3Kp@BN>Tq z=ekd1A@TUxOFPu-jE)a>$Z2+z4m4oBBI()LPtwB@NQU9PUm}ngV#BM~ZCrX^KBQ!Q zZmp+iq*LjCqBDtp+XznG)qmE1fEO?VP!^_2)vrqxuq@_{n?T+;5R#j%Yi~>UUV?R3#EWG`gka33rq&n?=-cVcfE!EC7 zeIL}jK309spPI<68gQQd)3pw9TcPX3EW>U*A`Mtby26m*C z0|83&zJ~r|W~;EKhXa$pL_WxlNug!D;+@?Iu3wvJTG_Kzz>=%so>bHQiV2vU<{Zi? z()zvO2rK6Kz4BV=TMHlUOaAB2Dfzv8&dYZn>7(Wr;Gr1_nsB<}B6@&EQwMKtC| z?`D(lbopWvRQfVCLfz_A=sFXlwE`3q(AiZ=(oHqhP;6Pq}5Hs0%iWI^E-ZS1V% zvV2~+UC~VcT30mJ5qb~67ddfvhH<}R)9aLUEtR&&RPT#S{9o4xVVx;#kNymOoMd|r zRr+Ao!@Pv=xVJ6;HF3N^p^$d<@+o`+-j#)c>bzOH9J||Ci?ref>V*=c+zwBdcA)4e zL7(l?d-{ZQYg&VoO+kz;l{?ESMFR%wH<@dcB%rgZ%C;Z#+HXT zCl=$BUXCm=zeA0A-^U4)Q6*Q&~TB|bmr^KQH+8_ENyZ6b_{2G1$j#0PSVk>p+HU$ ze4RE>brsHFmsQ;&=u+S<4`XrQ@ROCq%uL2zE85K8LzLcuskGYV&tp`djq|<&`da8E z1;++a&Odhzu_OZ{+RERaM%ey~ewz@lVmXtLEq#JHi1z_sN=gbQxfYLu4^vh~k&~fV zEf9U0XKOqX3;9w~J>^3GYUW@RZ#dQzAACQOk}Wq$hL{(NdIAg@Nfx6)xMc)I6y!*g zWm)!Gmwq$(F5NW`DUaamqr2np;Z#ob-q$gRjqi@LrKqmTif6}LALR7ImYI6zLEQZ% ze{cHkITPQI0enSkh%KA7MW{B>fr`!kPQ@*BCEX#@u2J6E7_tKfWKOgNYcID#^;uxC zZ+soF*t3FGeP7URjRF!BF8{c{StQf$saVD-B$j9xz`E>vzV7&%XkVm{dAmh+{~@ud z*Q<(tGSb7wM)SD0D4V(G81f)g(~dROlW;ALxCQzVn6IrL%H?NF@CjnU<~&V3-I0tM zPdWu7LO+)I5+E)PLJH#0$krG$f?cncyD!X>`4r~{sI131bT3WTQyMpI-iwe3I7HuD z#%B9x7j3=1fBQ&D-Ha=~54AP|tHg8-N5_mOT#xGj=e5DwKU72VX4kO)RB$=KaF?8^ z1QuL_qT4Ko#+xM&)gBQ!DsT93JjgMs8zgRO8SlyC?`=r$Hl!5+m;!le9ztLtZg_ti zrcK2)EPk7Vv5|%JQViZS*8m~54pHI(PPILN422iArB$ucUC#y%U>RR8Sl`*zi}ZA7 zEt3fLVTPk)%m%Ac&9ZGZiS*%E-l@l=Rvp>M)iZVqWWtHFH|ap(?{1sh$lOedv1sBbk5)+Y%NDmjy(L){YeTs;50% zw}fz#?@=lf%_o34^kV0d$~ML3>}#V7 zJ)@(K%U3}l-0j`($wEu|GRhqvk|NAW3xW{#|d9#^~VNtAZ4S(sF3W4vw;1mw4k-KFkk48HR$mI7EUtMINl*#&flVZtwJe=vk$lGK0%FWH<_@mG z_WZp6IxwZ0I1H=jg%S(ZMglfW*GwT5Ab___h-zHnIq0zDZU7`zAz#v$F_;+Xi?_1I zyxumh_7>M=q(;qLPpJebu~Q7{*CJ)~p%NiHd*8(Xf3%SYf;)G<{WogB|ATmQrTa3o zDEBzE4pi7{3H=EqEP%OpD#FR`8`2MnWm)p5`~kGM0U^n;*fwS5pg~p&G?pjIf`A34 zm-V~HrR&ucx!oVs#@u9_$T#5sBbSJM^r6NNWT z;DqsecC3*}twH@0>*~4HEWE*6=)F@DUgOkN;vfHb$SNbGhF0WN?ZbmPN=?SrG|>_t z_d#?CTely{>kFP3;eS431DHm_uf%u#MTYf8=qWe@FWtvW$v|t>O!J=nQyOMq9yXv` zjGJ-iUJ=ef-f+`sC}kh!tZV!)6@rg2H!bX$kjlc)N(9*FPCj}@UbXB>AG(4dHh@T7 zLRAS+rWw^tH~tQ9KM3BptH!5%Zil4tnT;koXyI{%Yh`0;an81%H7?ZBYAMC=jUKtc ztR|m#kp2__60Ez624{$JM@`4N7azxt>b2atMPG&>xf-ID@fr0~q`a%(^44f>}jsm{LBr!5c$L4hdGJVIu4h4SM-&V_dWF2|nYei>?v zY%XVF9IhYPn9beB7SIbR@dQ+_j}SRZG3lDz*!D4){3&s2PVqQW?t!>nRN0`9;>|-I zYX*KvLrYrgTU)PQc%boKI8iRj=3TR14n{vdl5n&e3%4x*H&=5#g0#x|Q{XqXTYV>| zSmR=7vxcyfv*Plu6qhg=H#+MOxvAHLtNgKH?@#UK>jbGMv%=+gxi8b^M>VUpiiH z01*F~^{M)xdu&X<11k}nxCV-w+;Pa|yRawWQyDNTqT%-hjRg6A*}Y%BsH`ign`%`X z3SDgoGuT9#y`uzyxw3x{;|^|^yvJEaVc73PwT`(WnP$-{rYPdEX(Nj5R-d2c7Ky}9 zRUf(d3_~6Yx7mqE*Z^8K^iL0Q6y#7NhLlmNM#zVd{b5;k=s|QGapRf%+rQ`WvA@9X zNUV=hek}?`jA6yT)1SaTkjv2^DETlo4sCY3ymC*rI@@q#|iZp{%{*m-JjI6@#7x02F@G*w(=s^fD@(qUQ=LVSDcgP+F|W z%m0ZgM(nh6()uLtRt~isx((7z1Xq-2VbdaMwN8~}LRwamHV>F^i^~EK+0y-A6RGf* z4$$qvLhTyTz_}^q;DGg?ma~_&f;@*1&d?_M0Wqz+k5rAH@Po*Ok5&Phn0r*7K=iFI zY%VGc#s;`G%TQ?#M(fo?I3v$}SpXj1^V)V1%OC9?Bw$T}NgaB5iehC^Nr2vA_g}9y zOi8FIO+pq`u7ck9^O78U8|NHu5TfnYL2Ot$n)Q_4RNu~wWcVI=55cC|Tg11iLo)9q~PF?-Ri~G#>$w#4ecgKEtQVHxiMnF2C$(k$g zzui~*t;V&1$5O2)ZpnA>j_4n*3JqEB62-yB_mS8XfCML7V^`7n<2iRmm`v6fEXqte zPOX~3=cH)TC&1+0$V=?v-@N+KIVFfUkucp&>VJ81*Z4>rguZT*0!YPxfB?W*9H7Ei zm=G()b(v*O)u%V^DN>VvK{3Pz(biKPm3p*)i23)$;rH-um#vWxg6H3N5@O==>^ue| z4O!Kde)5tTBIwYcx(IyK%iuEA=^hIS+7~v2Ck;b5U$C68pYtjQX^f6mbTrBPc-`Hv zEeC8{>?Bh6(gOudJ;@Y)1Cj7Z19YqvIAbK@%G^(C27A2trGZ-=;PMwIIa#X@X&{R2 zy=b81Af>=%4Lv6+9uwb2sjxj4DKFeaLDr!6u0b@YKw4j8eB#^Ku1>{D93({PY3(%? zu4r$ghF}wThh6Z?V?5>@Nll3CQ*2Z%$EHV3qu50Y1F4s4I!Kp^;973+5@tuNwcBY{ zm*U6N=4{5I4F>Xq6T#YYeu=$pLh@0YC1CD54L{oBgHnk%m^i2PNC*a-eG*Ly3P(-)^?;P-)3!wzIC5szLQO&4GJ1*dXws5u)v zaMesK@&eP2kTnG+)h$4BT2|-4!0gE-s>78tVt`HU z7(26S1lfr)5~JZ$*W_NUw|Zx(N9y@d6Z<#13&BYMIjInLCr%;^>0QuH>d@dEg9iC~VKNBE3c9^dQ;<;K9OO9Q zx!LvzrW%o0J$RiQJM8?A#q?QB1*n%dP`tCtOSZ#&WbSX(8P#i1Na;f1*(rBIWX=|+ zcCVTf%-+PU>~V(8oOSyzy*~z#Xo;AvO`JsNi(x~C81(|z{t&p@>7j+&pw4luGPnsN zyy>ItTjHitz?M8udz}F5N|0Cq4+?*<=nAcs2WjLZ4q;0IeGDY1T&zTN19WfbT%6!* zO~mzo%qb`EjEI9anC8@k{*+xdY<9mz54CcX{>MR}? zb2~&E>IXa$FhtM11$%0314p^{ic=fUzuiEPzu%1{x+~d@kXeLn3-%@8EWH<dv2qg1VhznCfj+8mAwbWOfDv)P3Sqs$dXNpfv&Y3umpG6 znRIT^i9?h|4u$-kK!61v&GdiJ6?In)0D_UmW>?&@ybcH|a!Luk3ni*hxSV;AZ2_Q6 z>uE3+QHR&D=n(4E(S(&(RjZGOXru>g>QF~w{?>DK%P|FO5%5pM5REYaZdPr;THOGE z=Fzx9=N%*N{{P!!x}&Tg*&zpFD8Rq4wv%B7^9MyZix!O-qs7_t#EIiJ!I0wsfGs@N zB-w-Hl6uA^GbFU9<`SqLLH^H8#{mdq3GTG!9su2SN-)L3Lsbqr^Ust^h_sdzTNI)g zprhnxXkgl|*=UzFX`s#FCirpntsR6rS3ZE_#e3!L}(%bssf?+Z8w)OD>s;b!h_wJ?^KY@ta4v;g6IlKx**>s6UbSI*FN4~N68 z4jZU}F+k!)NZ^=%x~S)NE1j8#r%p|`J`!RZDzbUy7gCXwTdx}rTH<)SOA>7ia8(C-k z*bQnaFU$=J`)|$`i>X2BpP%a^ZwAq!_HKLD6F?qs|Kx(&Y}Nc7=V^I$zHyU9TSNlxS^tJ(3*4J^V?e^@uO*UY5mW+W7iwh zxCss&YGVMo4YM+{y2Lvhi?jXf(;_bu{-0XX9j8zjGFBGZtrKO458n zPV0iaV%FBptu79~=e(|}?*X$tz$(P^C2XI7o6L7-+*Z%I-LOfcr zv>#U+Z%1sy*4&(^&n%ECpAsD8I@*OXAbZi9k!jm*1XV3-kABPI|CUoL!)f6+bURrI zkXv0K97_U9xpvtW+EU905qYp}nV|u$@KMFPJ^A`Lnf!~CWKQrK$6r8oDe%6m*&dFN z0_FpG*oy2UnNvhi?~sh~ybRGMdEjM2Adu1_`ws3&1EKm>YjI03oMryMOK}AB1ESz$ zqp+~mq8hK+u(#Nk@QXiP=d-A@cnq?nnI0RQh?Qd*L3f76Z)qUqm`WYZli@u6l~53x z>bo{U(V03=MZ~Nvl}`?>XiIcBZlX8md)f(NFNFC~-;#w5i5!<<*5P(H-g%TVRCtkX zlS`?YzU4R#|pO9(N5Jk>b$sK-R; zp$RL~tpZPWa|*Z0h>_Icy|s=%0mN*^-43PXvtnz8Xz;ihIW+ zZNe378n_eF`-Lows?gdNo}ysPr;04rj@o>Z!B<;UH>R|7*OTHFt|^RR(zPpYIu;cN z^$S^6DzRu1>DjW%=3jT`_=cHD1Z@8X6GbSa$3ts{YV5qZvvzq#{EdIJhaXP0%HEiJH>Lt**JMDj~cV!?om8r*FPiE?@3 zjVdvspED~=+95H?8u_CvSXOyA8YJ-1a?q}rKsIIUllSh8AYD1H=u=yOFxXdbrbQ+0 zo!Gjz%qRK&in2A`3IxAu1|{lyeP_9ywR{@(dK>*ZY$DCTc>va7!v2paQkXyBQS6ra zJaL_!7EUAiT{^~BEE1h^yu||TTBMOq%Hh$(NT`@}b%k)flHtfUY;w~8~+YW%K0QDf+@U0%>-8w}x z7Mh?wMp@8R&U#%@!n?QCf6#!QBQ5%*RaFl@$(6FC_`fQ|I&RuX==y)*c6$P@@C-*9Z>q+75t<2PD zXLXtv7m@H!KP=%bavOz(4P}7QaxWPQcmDcCHubj%(9O(2-Cp{#i&g)~e|ReT$rhv& z`ak2g2CDldXyZ&NPG|uC#JA{}oD`5W3OgX*BCM}U2gv>tSlr5<|84%lFeKv)SLdf+ z5|V?s^CzB+26oDwz9F9pWN0l!t&4Z}si1g=BmJrALRKW^sC&jI!|Kr$^e!e0Y9L3IPhyIj-&nzE#ABKwWoF`y6VHDlFb!>VPX5icm1%Meq=WZes&wDIaXB0BEu<;|D19v z-Hovo>hnbkO?~Qa&mFiRs30Kf?kyY*Sn9#9w$4}*H#cliWPaV~WzT%%2`|zc;qm=` zOY+bE8=H1CFas4&_zvL72NzFNSZ$O*%ro^tFp3Sxf1?W_%n09!s zTs6|)<~=py5wx`nS1gQ#+jX`tUmIprKavj=vpC$kWgUfBrSqV#+a>#M#sd>&0?mDw=KV z6uclQ86cb|TBwtojTj(=heRkh&M!0lak>0o$IlIU@_=x9m;?8PEqiSP7(q8y6}gjD z2hY2LlsSn>YWIj?8oBiPi%nwIt@5btK-jAM7t!C|3{-FtFhB~R^+T>u{V2`TlTTOk zF7!s9R35lhto`KaeSTX(96a<{`Ioe16L+BfC2n^&*je%p@()jBiNlNFq=;0t& z`io7KNT+f3;KYiBQ8GRPV7P%@CfsaJ-h0AUJ>b|bPTHfd$AW2{q$E%^DqiBWA8X|Y z!_VnFN;qz@o0wk>-QUDt$^Z&?l<-8%X%kD~-B>pOG30DTDI?jUIZcL)*c7J8aBm1I zTyD9agphMB`!6C`EssGjeo-bmkY!edG5l4-htj-W_lv~CV?yJLf{pG^4R{W`aMAe} zeeV0XJ{MO3?e6i1BGZ)a^F1Enp)EKfF4P60WDFfvX+mW`GRm^FDM;Q( z--xYZQ(0p)^A=|VGK0Kl?kan5A}n5@|M5t!81`S+i2)f++fBQkn2EY(0}Ydq@zySZ zpOJr-9i?B-&1;<$7BuET$fSlOOXOg1mOs&5NzDi7(QSn;9CL^e8yk1RiP3q98Nrq$ z8YS$;tbk)~lCXOKzJ`=Ljk&~R3ZP7ku?wVLlcROsWw-y<;z^?_Akr>Tn0ada*UC-M zjsmri+1>)zE7YaUoP;nyMq$;5qu{Q8d}wujEZTTYpnZCg#r$z)*bfrRQl|j$uLZE) zAvZrxIk_^fog(#m{`b`tY?wO?JMhN3ChUB-6DC`~BA`ncNkTpdb+K)?Cb-%VHXwe{ z`lMKR?I83UseFyP-&Ly4lL+i^q8E>_XcCKM7sB^SOFW3yP_H*&J?`jZd089suRZWC zvK(|%b*5im{njE!9|m6bm@bK{QJv};i;&7(e&vrVG#xHk{&i}-`NzUsW%Yew=^;75 z(&Z(@bmu#DlM+r^H+`EMrG#Z|gAK+X2ua+)RqQ?pRF+f&{eza#qznBG{_{$U%?FxW z^s1hK4{x|*eJa>z@y~Z>k7uqW5O0Gg>F5KugWvAATp7(yKbtRB*uFhY4Wc(TuR*U6 z6udcl{7{V@Qr^|5%twb(slA9A5as7&V6^6(eDH_jS3ytgMQ^y9 z?tUoK#h#X;4Y?ulnl7)$R)FAr|EO?5VtIHC=qMlN@m3H7I&N2N;gWH7&hdT z=O?Q|>g#Bi5nTu{B+$_f(8)hg;OJpZ{JVl9b?-QMpmnxCytqV(e*`T$59~}Wgj2){ z`~YJpf1T@3vAlyd19lsPuat|QD~V8S8jP9DsMqxSutF3$@HoYvT<+Mc5%QM+e86Q` z`B$B0ti@ccMqO*)%(H}(<3*_?X3>LgBtEvL58`SvwF92def<@Yi@)PGdixsNcQnm# zk@vo}Es2O|}Rw_FtN(S(ZDl1Zr4X zw&`iEMV*}Ef1*zJPI9d$KfYpPQwc_Q9Vs zVCoaE(Ed9{dc5N2f1)edbTG|x+s5Lk@Pb<*kk&G8e)Yl_{z<|3i#LZLUAqqjmm?Mc zvc9on(5U0MXkt`^Z|?8(_K-D_(*7LMLJ)KhC^8+I}nUWAe1>Zi3gsXP+ zau+|&fHV7vA2r2TG!}Wwz>>$L5bBM92XdGEXA)P>0StX8ot@2QQsJ?Kmqp@S&0>TP zsc|GunsbT9)Uc^auZf@0y_m|R!6*KTUx;;vhfDEMNV@q=xj5!UtipIEG=Y}vP8+%2 z?VL>Oe3NVPp(vT%gCOMV-Feq%@~u6EU&E+JjzN}ae%G{}$-uvg6rf!axCjZvyM;F# z1q;oOGcR-LWdym;7xKO0YK7uB7lp#!r8B?UMw6}{vJmUPXWN^#=&Qf;IZfDjvzt&v zCNN*&95ua?i`AB{1{D&CJK5(4h>`fl+E8ki`qB7Icz?N9gK$H#i&oUzKC#ST%3Sx5 zrU<1PlVjR)3;ovR?n|;PAsF&{gqU#VT^(plum$rG+xzJ`IW11t8JdqnqH(G^+9s?{ znHw+(R{j+n|K$?O-;l4j4sIC!+PjtSo9S&NOdtQzPz0nR+Rwk@-NmvNNVOgprQVtU z(XG_w|52)pn&?kB-6f$fBCDV!JnlIidp}3i(V+Uho+4A0LOoA1qa+qHZ4LAj*hHxIsOyXwy6E*DiqzFMQ-2?-2> zfzlb%xxXnyLlal8nT5%`H)+*byU9lc_3Wz<;9A}6zrR#n7m$uF8fL1 zo1u+4$`QD#q+|w{u{0fW7zV%>{q~2%O+n=stTdLMf%#4kEkjMKMYu4q zI0ke#Ku7uG@Ugdx{1hUSJklZTsMBYDmMKPbN;0MQfmU8_)jB<#Efk z>owIYb>Jki7tXvX;O4w;ce%>LhTk4-Tk@cIy@4pC9s*zQ7-20zt-d-U!u zUfY}3Dl}_gO0{abgwK_=h{~u9cFLV(gEfCg)_zZTYiQ>Ca339t zpI0C&aYVdKF{Ary-JUat?@i@Mr3`GvE*2{t_I&KXKYb6lYMrs>vjltK^|XKuQU#>) z`iM8_Kye(=cCj&Fm0-gEjhHbK#dJRJI`A{d?gOWOq#`|l9x zu9UoPjwwBt8>Q-yoO$aQccl!gm&4pTHDZ*NeYR3l~H8kYs2L6I5%(a zLEXA{fBRbj9@iFy?D>|Z>;{J_rib|#lf6P{@BE`oAK73V(K(FR*Y>iEX4E{@vTq9grhZ0g<|AKO%}YTD0iKlOwZe_ z2`2x;1+GcYo!!0fs08Orysxr%+r94Ne@_Kx9HcPR{uPkX?!?kuSO&;WR0^qpgH>jE zr6H(&a>T1{>JOAXkzQF(kk55MC{PdrwFUNRmF23f5*s+He6I69f_#6QyUmKAoxDvZ zA*2;{c;O^0?<7kVH;}NSv}Uuh&of|57$QqN}b;dpKU`G(;dz5g>i1G;U7M@!Bm6N%9 z25;>q?SFeU3YG{)RKTEfn|Ul?pJmyLpc6W_j71Pq z%~777-5A|CHW#fh`J$&1#ljvU>ZG8KIPkr-WrshmEO5IARcn-t_(zT+K^x#gFJPMa z`hh<>+Q3T#DAf?933v#M+olOZoRkf!5S=8MITvTZhm=Xf<|lIM=61dBtrMX&gK=Uk zDQ3Y76KjqbEJ|eCcUk7q7e?>@csBb0($&yKi03c6nkRL+rYZ}+76Glbd=2v$Uc2#M zj46;T0fOR`XKL}vBvFg99gb!3R|_|CNWDYpNNrHtIiXe^bM2nE6%*^<^>>T=!!AR> zcKdX9J45>(S9+Opp?e1Ths8DB4m%}z>kN_pAdJ-HgfP3ju4m8I&&^Eovq~tedtg&@ zg_c6%W5yV1OdkjV{SE7H2|D4?V(har$_6r^u{iAxU=A>UvTm(f`49j3%e=WMtVJ@i z1{KKK4Be?G%GyU78*I&$7#QS3jVq;#U;)VyvE^aJqQ*+ z)t8H`gD0wKF1asA{|TTUdf0^^20m|lo}%H~k)FTAKNyvxYcC7!e_0XwCvZ8>6Nr{k z-~8P&#>ezReJ3oEAkzUaF1~q-n8}D~SICZD+~HYknCE2plnH^>~2E zI(8+E*LdP;gXV8mMBr#8Jc$!FVLq%o7Ldcvwv_YOeJE7PlrK19j;j4@qH{f-g+g$M zdMZ#T-gT4x^)LBvCS+DlT!c=|HF=}cU*SxZX!~i{Pn<2$vacv-2blb;U(h++e7vL} z<&qH&L+%4I`mPOK@k&!J8na8Ezf~2uijiAr3H2Bpj=V?HK1R+-JOO9P?WCugjsb)^ zM`eXJ)~5B&m>jk0_hdSHBm?&X&Hyim-TRyi`WhO3@?x$-pxHzd!~9Kl-wcuuClC6# z6WKx{qfOjDI=IM&x;KSqdf+a-Rw?>fwCo#s`ANZQfQDZE0c_mKSx(|%8W|6z!~FsQ zRqMK_Q~r)l&#Soq{^^_QW}QxwnG4KWKFKD24ub#q?oxv}qOq0ufyX!H!Fi9(ry`AG z#|zpU*Y-H96|HL2eoMCjX|5J6M~XGnv%xhda=yVr5tku zC>8=lty|M3Pk=?6`d^q*TrsPr4c)6T3aa&-<@lJG*^@>bx^Qu2R`eS>ob*8;E1-rH zNR$E2NAgUWk{`Yowj9-_d7$)RK?iI)s@6-3AyM?%}>WLM;sr6kc2lQ-&rL@fyY+NaTW* zKaA2*_Lv)P%B}h8ZfN7;lVtby90D#&>-x;*T!C@h8D1MmO@&LBR9=Mt3h?S)N4Gf# zA_i>v1%J~MMJB>SRgzkDepZHPJUQZU8NL8mAo{1Cnc$?g@fYlWVBAcpR$RgcZ+_gGx^Ijc+)4ZJ&xCjRE z7hQ%JRf-$>%yurCODDmj2+MYphI-A1^{Dt7gKA$-&)oRo$n|Tx&hJrqy=poO?TvDR z_l#PN4mMsoqQP?J3^PGfBM_R{&o!jh($CsSzv3i*{$h+L^eoq&)*igF?<$YuD(58m zKzt6QG;zZd(0*vcJa9l>@&4`4gGF%~IRn z<7))RvGF`v2V+Q<1?YFC#|7)^P;6lcnn$kScXK}9Q;I{C#>*3mW?2tBH+9Ul)KrJD zCU^OO`i29gs%T%ZL!M{>4Ax}mKyDivv+KQTHr>j>^NxL9&F_D5H}S3~Uo9McHbe(43r33ua2UmhnVIT|0M>}P zm79F|5;|^G@8$R4{!bF>pEM6qrMp3VQ6!SYpc82sBXXd9I6TJeH(Pe*+tGUsqtyH7 z07cLho+YE3tL0!xDOW-8j*DZD2p{5<3}hP5YXQfvRbO*yr85NV+yGuo_aCxV3LWU3 zY(Mlys!51rCZ%%y+M_a`=Xj?;aWNbkMjMr6Hp z{RvS2+mfbv$*4uu%7@kt28Y6mSH!VP`d&?Zjz-0u^6%z2_hlrVxqHvlZMkjfsi+7O zbV(mC94GcrNX!@rLjoMs1{K?x($(s4flQZ3N7Sxzm%3N*tBHP@HffN}i_(uDDO1>b z#?jRQv2Ps9R7+DY= z;}aTcZBqeRT<372`k=nz@7LD|@~X!5fkZ$VE#6(rUd6D|)F<7-eL*yV1b#L^ts++p zm#A;;WDWeKf$!LBn!U+Bcu{g_)7V#gQ5e>>bA(P2Wyf7SQIC^ndhj@bld7)+uZIx< z`sXC`OKUh}-7_@hl;A00L6FH^>@&VX_SFkcXuXO_>2P)&so~xECx=`~F3^Y@km)Pc zO-b-Stg>+n)V!d(1IQ$hEGEI$alF>$ENc`vk++8MWKPx5beLY~Is1=A`*H@dtpHmB>G+z}DwQ>J zVAeVs*Ph8f_@e*MEdVnfu&^+nu)CyU7|;KMjbvlJE3-*6BiK38K5g<>Ol8! z90C^sVbgTRZD5HNL@DcZP{n^m7oMXd`Ll|?TLQbB_x zkj@R~BYy5W!PKg$pd?jf5_}U2x^bMyoO#;dp3m%<{XX^~cho1c3IGij|MO?O;2D;Y zvP{Hbaw%*($?fEdYmdFiDo|6IH8keG^F5SBM{ltFt2ILi6wP(-If}^zphn%4=lF{}PFrhT7fULSawA&@JLoWhkh1$N)PNF(1)$Ew4vg zPsJa9@6j+_UBZM)gSeO3A$+?4{|;r?&8*$qskN&Xvh`emE{(757}kb&60QO%{#R~= znSg8+D?|mHN*uoNVEu-=$0vrJvq{;Ml%-ZS z07zVF0Wm0R$Z%v={l&z7?T+{GWtU33B8yn*6P1frBOCw@C)UaVwz0t?2x`FD%;{p? za>@pm@x_kM3{}&Ybz(Oq;~z35P158&!veDkDc-Xy7sKxMI<5tH3i9NPfrJQ?V^C24(Rs=1eRQ)oOCL&= z^icsqH8BtjW2e&D@WAWhgDY{>PXbk!(lUB0DJ!oc?F=ahxfL0;IYFe+w14pbv>^_7 zd=h@KQtZb{oF?K8DEZ`y3iyPuS`t79b3*`>&RXu_>(tM;q(mRt+!MPV(#np^v~?}%L5 z)&t@FQc80%!Q+@1>>iZCR7TReKI=0iD7*PqH~VR@x07R9je4Jl1>g#9eLt*#JA;QF zL-9nI^?Xu4m|il{C9ik(cH1wBYifOddSo=>Vp|0jCCKFHZoG_4KmH zm%*w4iokU#?VrWIut{BVLliYMp>{dZn~NwCG@V;e`vvvmE=-z-edZ11tGIZ&gZ z>BI4FS#Q+5mj~Nm)ffYxm?yW#cvR>|I#`@ef)7!>A!1034wlC$S`@xcCipC%L}gMi z5m}BxiZ+yzkzD?hP5}hMhQ`{4J}J^ZU02oFZep+6cPgc&QZu0r$6OejtX12`n3Z^~ zV~YRQT3&QeOv3in@U#{-nTJ%oGZc;_T=yG_gkG#Z^9Rnggk^vjf_BRqQZ z>q;x=MBDF+Wp$V_5bJlCULLil7oT0tkBA;t`wzse+n>8$$sh6NaCBx3oVPT+9UTpW zL4&ZudaweiLJCDW`XrZL^#eMF!P&TqwsmD@8|RZ5D0noBYYfWGiBw%HIJZyLcSj?9 z;_?O~l8}!c&_M6Y{%z4pgizQNd~+9anwlTAye*_9P?Fq#<8zaEBn>(S|MYhaHbs$d zQJyJE;$p~Pg_8giejxbY6k29mJY`IoxXTN0LjT zvU?w-g^BCB!)*Gp=eez!*|@x5edM^~9?;p>2c_D%vvG>N>dr|sdmZt{Ni4YY`bw~K z?J+HWfv|yCnK4hIN}e#_y_tEtZy7SN-x@M?X^%D~+k_qAP9Uq**qaZA8=p9XRX033k?39eF0+S5~H; z^DDZ0Ohc$XdiXTuoso=mSEN^I>OhuKT-Ct!u_D5gQeN-muw->AO>w~y#>_`-8=7iscv}}Cf6>pERC|E_$(&#C4Aa*+f)lN# zhMH2%y`rzpIob_YdGhWY8dL%hOXTfr-8W&sba`$c;Jp4>#KJ}B)ij#tHpc*=N5C8+ zfZUgkpS1C}3bD6EryFV;@9{61VrB4NRt4UQs~S<9`pP32BGE%h0o!ZUvqYWpc9P*z zCzS+v<1#*Q0c{F;&>61`$1k5+xta%Inu# zMdXPe+IbXz^&bTt=Mo zo>O#x!59o<(ttm#LBrbS|4IEEaWm&J@}l`NFy7xSrvF^Yr^Wm;KJdzKD(<-h?gT`! znBf5F9Mq-=#T{%I`NDWOAnXu4*duCx6T!d2pgI>!|3|``q=)H&vl@Q=2kdXXz-@7GWZ7}mCL^EQS{sQ2m!RNa;~c*u;cat6z9Y$SR&Lyui$ znSse+3zYJOBA>H-%G=e)g!&qmw8j=AGxHn8+i+7&7MS;f3|G`705mk~(?H+04v2c$ z*Gwg5&u1=&Ue*=hjE8ts(=~1P6 z3;crX!@>#5_LDh1pT3NXE8E}=O6RNI4h`MhXf~~M&q_%xKv|UiM;%W=9Cy<3%;HhB z_ZgU}oeN#7FW4oUQi_F9Z_LvgO?l5nri@w}RulV5F>kxJYlnDl=dT*=y0uDG+8f|1_2;!wfyh z;xovDCZ5mqnbX})vNiY8hX+^EL!Tc;b&dm1jiNGNqnfqp<4Vx_hM594(IXLoSo2Va z@vpsG8hMJ;di5IETKjKSJ!Xoo?D~OEoXTokW5x^Ry6Npa-8|2#r7K$Wu^LkZLpu0X z>~J@Vg7^w2sE~xv0u{|x`?5$%m@?lq63hmHgC!@ECf?}Lx= zAE!D^jg5_Qr^ajTEY#)nI{?i;qLS z+f^IiCPgu`%Lzyr?=UCt=o_pc9n7rv7Rx3@fl0ALHAc^9wUJwfv>+SkHuf_cPTuF9 zzcmZ-GoA-YvW@W3eQ##8-ov+yrAQh13->wlstL~4LOKD^vDn^8F5aZ^SGdYU91H#wH~u2^um7@&o;hlOF_(x1Co(BwXg+YEa{c{1IDfebMnHS^ZAiV>H-#}=%>6Ng-i>MdcSS@OFK|Y;T6cFmnlu8 z|ILQ`4;|suG4Y-B68)adyJlNSm5%JGahW!jGMilUZ+<^i$6mmAw{GQrcRws(Gc{&r>SM!vLf#-SAL(aUR87 z1Xm+ANu(DjG9xZbFT$;|B~|T%@=PST`?Kv4XTStB4lpYK<)&52Cxwz_6EP;SZ#VNQOeP5y$~@Oi#+aNB5B-)@VOjZQDRW^FSRs8A_q z07G~{5|`gP^hz0U)qtTo5=(~ZdBJ~!5fX6ZG6=VuK0|l9pNj!{X3F_D=oJ_Wx7^UF zJe@@obJ)ExWn_3}G)E^*?Ti!OhUFlJ$G_=s?PPYb?GcArsn{XPcZbV|j;yU-Zx#F4 z@Bp>zBWyTC#r#IRjt1?8+DMUo8lT8;=bAJE#spI~@9`m1D{;FL=RI$W678}J*(=d- z7zj)EfOJBdr>P*kJl%<0{{M4sdBjdg3#*w%#)&63d;%y&_9BUdmu&Q7H;u1%M1K*| zAW+YPyR2T)$XX4ds|fVI8M=<7pb$%QE3#^1f=F*x2WUmVQJ~({hQKPW10z_5(U1Ux zaj=xcv?hno$Y&Pas|0(9Z-^Ajx1BQ45Z>Hj^+=)*Z5j+k>j-@4#4JcURe=pK2Uza1 z;K16@;3fXt33Dc9E1*?KIgqw$a0Wrmu+be_Bp^jWFYr zT>9CAP0n;1>f&rgAh~ST^Agg1l|)l@N$iAf<@YCN2n~XfOFzBF+@H|CPu*1Xr$!yu z@yy2`DWsnc?>)2FK3SLU(~pRbt5Ul~KOBFE0@}Tda(Z-d75@*|AKUMs9l)M^mGQa| z1lOL#rNNP4t467~GBFAKU;Z-P79p<%_ZRp4R)rt%w}=lJRo-V$2e*4da@#CT>Zr7} za%g0Ti$j=Zf@S|qs_)@Sy?&ie>GG*w@?Z=zi++jSR0Uj=tFp`h`4V@U z#nuEFHp0XBBk8Q=2}NjQjn@vGm5T@e)hMglt>5%eg4!W zD8bbf?&D7IMjdo{`ydE)h#|fXBgb{VSI0|dHHiHOHpHNFr3FL$2G+a2Z?wAO=!uKMI*3g2!$|27 zGT9UqmUH);S@YbQQ~sU|8_J5%!$k6`<{=j{b8%;^(yz=n^EeJu{{(lep}!mE}C>;0K*I2!_2{Z?}RA+Tt#tt-b`WE6O|! z5V-k|sxC*fWt7wMs+o$j);~YO@Ayc5k5nzC`miJ)iIOsBz8%znWez6+j{e5L9=MeUk+G%3=Tn`~av?i8fh{l${l zmI;_>y$-T_Xt7)esxjIIH2kkUMR(ZJ(+{U>k63y~(;m69a8LJJRk8m9d&XVmYVa16 z2&f)7G{T1-zQxVxHnDB?Q=(p?v#tb_Kt_MDwf~PecvKPC&kBdn^F6-DX-8pR-l^vX zhng*2HKB}z;ySTjxM|Vum#78YWq!7V1o{lN0Ne^OeFk(@XE11GdyPhty*0R?*pGi4 zac{ej(tq_{rY@9H1kC2uU5~*-K}1wZ@t$ZNRRIh_*yAO$uoQJ**5#$(#5TN3(wB9C zHLeBJ$bexFxbraSV`(vCN*t#mJMl9ATs?NyM?iTMp*-w)6$9!N3d4zRLgI@C_@C@I4R)AHRx2KllJgsD&ms#b zAY<8!*gYxvlP;-!$1@d|$Bdnai!lRxoLA7Q06AU!j#kVNCOK3%oL*%^eaxa2=(UT9DLl0uJ z;=f~)K#v~)WPC{klj4UW%{;-1=dw!1pS>g<^cAjQFS{Q$qbIW$MD%*|NqSPOCAUMu zRTIyMhMNeLdU9`8n&)FA&5u zH>?L95&xNY)Dw+cca4ltn@@&{P}RbLh>x*%HlB5n{Pilg<|az2Elpk;0`Z=j4YRez z{qwvKp4e~K8c)O-7X*{p20(JBp$8>T05|u{nH_HLY9D3LkA-~+>aMUz=JqH44VT62 z6RO`V9lGbhe1Di1DycsCYBfE+p*t974ELq;nYn5ezwHoyWf=loP0^`UWL)!kVf+zG zdn4$qIvEnvnIb!%n6cXE_sZ#?LTjD`?s)7Ncwg|y=n^!p*jyz-A?Y`goBy}UA}LT= z)|$i^ci57+95d=_miTY+ifV!i$S&((VJw%9neES@Y>SKrwSWQvvS^#+64{ss2xvgUg*^!^Sw%1BJan}RIw|{y{*id z)vlSZZG`(SKh**EE8(xYy0yUpK{KmF@ZyK)!6Y}RQ1CCo_G!_8K9yfs%t8&_X&QVp z@gUu@&w7p~q1+jau&IlDc{js+y~~>uF?Nwypeei6A&TXX(c*sD0%3_x(sU^9e^#Yb zHFtiKw`Rwqg=MSc3ni~oMz_ak^6o7}#lSL9n|BPP_P++N#+W0``dI+o0=b6-&n1UF zVDCYIiBu2J_GC51-F)JA`wUu2X0oLSX?|6CYk(Sh-q|n0fI+xOZ^V)a<8c^8oE_dC zCF1Q+URmux2+WxFl~%x!TPv-+nPEiLPmIPFQHgRpN^w32fu@2;QF$`8C*F*4AjjNW zyA%A;<|Hz?Kk*mACtPfh*6|54{n4gwVps$FUC@|X6ovQrx1E^~60*ePQU{NDlhHt0 z5g!W@dGcm$c(a3>HkHFk!uhrk9*xKj0)QqCJ&lU2h;*%!anwX4|h(S*ax@KNjcZIDvV1q|PwNS(oPXfg6ODL07;X5I48EDYHYS)NIT5l+G z)cK$@#eT!;fbZ{r`vTF87DxkSwRhX5*$Zfk5`n?C> z36{ZfTtvH?nd_3kQ*R!aAd_R`m={Xa2@y(a=9fdaSJZxnpEDz17u1&i4aRPc9uO_< zDiI-S_?gKqj)E289|+8I%TpdDXC3l6n}5JjL0wl7l?#ufbA2AB|Y3Ee$6o{%D-J_bWST1eL| z#}D);HTh`J8EANb4$l5cE}i@M+>McUE)p7#A9CBxrd+V5BP9kG2c}FR|Hul;PB3|I08NTyE z*uWfH@l9;rdnVgii7*QIkg&_`eSuavaoHV1zbyxqXwMnDeYK%BQ~n^!s)VX8%I z$ub{0m@j$8XgWE+D&@eeYy6egxaM>db{8_qs*b6hdP=NM<1n|K`R*6A$Fgq>~#AQ@w%5>tqWjvBAU}^0;buxcz$> zj+C5vw&)T@nxM4=+UaufJvKbAew6)%hxWIEs&k#*kuo1$PN(H@MknMef!u57{GCy` ziHNO&+!$-?j^X1ecD%2}TcODlSe)ue<#Sh8>A@;i_@u}QhXddAn=`9Z+1e*hINpKI z`0999EKm`;4pL&ZlISG44FDgzp&Qh5+bTCNkt&ifub7;4+tirM zMyx~&zJ*wLn9F9RU}_dXYNJm)k%Wz3U@ssp^{c*Nq~|alnccj+{NmNyVB}VF=g>PSFhK|7r2!8O*<(02dk&;Fsf*ySuCR=1fLWJ#@YXm8{cvn5^oGTE6Yq zLLvjKKJO%IXVz+vq=ZW3d7IGnh>W_wbEp?dS1y?b@{LN<7Iq`d)@C~n7*MP<68a9y z=q~=nkjamA*Q)#bdDl?QBt`#67$&~o^$x-k$?chl8WkWxsM_8Gd-@$3Rt00F7O|{a z3WMUo8b48J^nu;L`n_?8K0rmgD#b(sjvSgzU>eHFS#%8J#xr1Tm;hPk|G?*=PZxyI zrzcX=?fnn=37IlPwBA>|VA?tXI8?6Y{lsFKqg%4@@voabh4y_h(`O@Z<^#lI-*V9H zoyQ>1`8nd>h%eKSYi#MP4Cui1melZa4hM0QEiD-N57Lu#8s3yQH?kYml})>x0lI)fy2jx=P^40E0F39YqC1 zs^HXtkaJLBG9{Ydot)_a#DmIFKhRM3LQNSLpQF>Nmz|Y(Lc5Sc77;>nS0tyZ*`M-( zU8NK>Lu%A6M?$`@%NqgGgt6!ZNCRK?OgxIt?Zii~k1bU+GDS|`Zgug3#XjYpGBQAl zWoOCl^Yd3ay5^AoyDC6R;yH zH+&*A&Z-u}U|&ELIK8I(GNHE)^Vu2U1EPf|e}_wogk>JYk0-@Mx=|n71?F#C6&fOd zQ^?*1qAEsYELhEeNptqM$LMMEPHgDtk~RS7W8K^Fdu=8zI5 z2+;@;gLV@z!uPonwE?Nis>HL;+joDWKmqI(u;zNK7wIqX%{7h2mz%O%p&uJ8etsJM zVxd}65^0N#u_j-uG>Xw&F2wjuDL3g}j0DKVWUHp?%CyGv@XeyD{4fQT-?r3nby+8` zw#+8drk)L@-rY0qCIg9I!ozYOf8p}=<=i>dh>qI-;R;kqq1QQ`=OMJO1l2RYOwe(` zuA57^){bWSWo*bWcZE(r8wUrXs~{-ICa`wTabCX!dN3@!&dxlRy=Hwr`7dC9&$fM( z+gP%E#F;8D`!8$;XFHPfDmoiz2RCbF=SIT-GMpU)_^KI3%8S*|{K9pKJESFGgYj&`wUhCq6r=ysV>YQ4 z{nKf1(#^3KHGyK;h$^#0YQJcNH8(;$xJay{;{V-_8UZ97BP>#j-X9D`0-40qEy1$t z0K>Ran~|j=1M7R)OcJ1ohKuEye_bq0RHLJZh*Af z0$W;J?HQ&iu$!?&x_(B5+z4x1N6OLyv!W6SD#KE#ntC)3cr(x3W-V8K>qy;`{R?*n zHog=iI@18e)0Ic#TcgRj!Y-v&&Bg8}z~oTaWEu6ef-ueap3t-QzsR_9c0CPr!A)&d zlDq)lENTjz-{$ie#EpgD!t@ldJAMoQ7~jiI^$FUpYV7^&B&!EXAS}lYE9h_;+tl}m z1sCL$n>Xu9WxJJhO>ABGh@I*Cv{o*)>Ezg*A9+WuIMLYybOMQXgpsDQ)Mla6W6K5e zqsL9!RA3&n4u?tD(0W?}Pbc_7`((&j7QSAWn9XOKLVh98|F3(;>!BJ@S9p2Nl;$~I z!7O=^0gv?E}u z*+^-;Wa``UA{WP|r_aLX9o=P_@V-vVs`Zcw>uCT<6?-0$Du^|*Y*;HIdtYv63uh4t z7Fa^zBK`r22K`~sSO{&cuUckXZ;RN?rdODuep-n~&Ry%5bgrj$y*+gAN&D3Ve8SSU z$_oEw~K-qWH!18)Bt_M6GU;2pdk4BK|c9FP#_Fq%V+9f(UWv#RaXoyv&E zeMC(7f0k%V6k2I@^G6-6xOc$S1QdDP2Ipr0yRvo|rmxq5}y{U&lW zeB((GomN2&uhlc*5`1~IK=gM1HYL-e+vG}>{U|wie~}~9wmXQg(>H0eYv*NpFkxUK zSr|pw6njVjpu@Vs^y{D~q8EZ}RxO#r9}AJo|7n2_9X9XKFD0vUis07Bkfs05P7~wl z`Rk8JKQdn@mCL A{uLxMMC$+9m%BkR6kUUjrA75Xq~d%p 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 R^RoN|1pEX5001FSu#OA>=HdVV literal 0 HcmV?d00001 From 85755ea3dc2956b7090e9d5ff8e3c74349b988c7 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 23 Jul 2020 12:43:56 +0200 Subject: [PATCH 38/91] Enforce correct module for ZBBridge --- tasmota/tasmota_configurations.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index ac0b629f2..99fec781f 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -417,6 +417,11 @@ #undef CODE_IMAGE_STR #define CODE_IMAGE_STR "zbbridge" +#undef MODULE +#define MODULE SONOFF_ZB_BRIDGE // [Module] Select default module from tasmota_template.h +#undef FALLBACK_MODULE +#define FALLBACK_MODULE SONOFF_ZB_BRIDGE // [Module2] Select default module on fast reboot where USER_MODULE is user template + #undef USE_ARDUINO_OTA // Disable support for Arduino OTA #define USE_DOMOTICZ // Disable Domoticz #undef USE_HOME_ASSISTANT // Disable Home Assistant From 85ccdda5691fbba5a7395ede5f056ec2873ac52d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 23 Jul 2020 13:06:07 +0200 Subject: [PATCH 39/91] Fix MPU6050 temperature Fix MPU6050 temperature (#8964) --- tasmota/xsns_32_mpu6050.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xsns_32_mpu6050.ino b/tasmota/xsns_32_mpu6050.ino index 702d23224..c1f792ae7 100644 --- a/tasmota/xsns_32_mpu6050.ino +++ b/tasmota/xsns_32_mpu6050.ino @@ -181,7 +181,7 @@ void MPU_6050Show(bool json) { MPU_6050PerformReading(); - double tempConv = (MPU_6050_temperature / 340.0 + 35.53); + float tempConv = ConvertTemp(MPU_6050_temperature / 340.0 + 35.53); char temperature[33]; dtostrfd(tempConv, Settings.flag2.temperature_resolution, temperature); char axis_ax[33]; From 51b9740a5d4e18fd34876086b92e3625a3056a5b Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Thu, 23 Jul 2020 13:23:16 +0200 Subject: [PATCH 40/91] Add script usage flags --- tasmota/settings.h | 2 +- tasmota/xdrv_10_rules.ino | 5 +++++ tasmota/xdrv_10_scripter.ino | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/tasmota/settings.h b/tasmota/settings.h index 57aa35860..913309393 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -422,7 +422,7 @@ struct { uint8_t light_correction; // 49D uint8_t light_dimmer; // 49E uint8_t rule_enabled; // 49F - uint8_t rule_once; // 4A0 + uint8_t rule_once; // 4A0 bit 6+7 used by xdrv_10_scripter uint8_t light_fade; // 4A1 uint8_t light_speed; // 4A2 uint8_t light_scheme; // 4A3 diff --git a/tasmota/xdrv_10_rules.ino b/tasmota/xdrv_10_rules.ino index 782116fc0..47c789935 100644 --- a/tasmota/xdrv_10_rules.ino +++ b/tasmota/xdrv_10_rules.ino @@ -791,6 +791,11 @@ bool RulesProcess(void) void RulesInit(void) { + // indicates scripter not enabled + bitWrite(Settings.rule_once, 7, 0); + // and indicates scripter do not use compress + bitWrite(Settings.rule_once, 6, 0); + rules_flag.data = 0; for (uint32_t i = 0; i < MAX_RULE_SETS; i++) { if (0 == GetRuleLen(i)) { diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 922e75ebc..19f24e1aa 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -6619,6 +6619,8 @@ bool Xdrv10(uint8_t function) glob_script_mem.script_pram=(uint8_t*)Settings.script_pram[0]; glob_script_mem.script_pram_size=PMEM_SIZE; + // indicates scripter enabled (use rules[][] as single array) + bitWrite(Settings.rule_once, 7, 1); #ifdef USE_SCRIPT_COMPRESSION int32_t len_decompressed; sprt=(char*)calloc(UNISHOXRSIZE+8,1); @@ -6627,7 +6629,12 @@ bool Xdrv10(uint8_t function) glob_script_mem.script_size=UNISHOXRSIZE; len_decompressed = SCRIPT_DECOMPRESS(Settings.rules[0], strlen(Settings.rules[0]), glob_script_mem.script_ram, glob_script_mem.script_size); if (len_decompressed>0) glob_script_mem.script_ram[len_decompressed]=0; + // indicates scripter use compression + bitWrite(Settings.rule_once, 6, 1); //AddLog_P2(LOG_LEVEL_INFO, PSTR("decompressed script len %d"),len_decompressed); +#else // USE_SCRIPT_COMPRESSION + // indicates scripter does not use compression + bitWrite(Settings.rule_once, 6, 0); #endif // USE_SCRIPT_COMPRESSION #ifdef USE_BUTTON_EVENT From 5f386cc164e11d616a7238d5ad77109392bda3a7 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Thu, 23 Jul 2020 14:52:29 +0200 Subject: [PATCH 41/91] Fix MCP230xx telemetry JSON message Fix MCP230xx telemetry JSON message (#8965) --- tasmota/xsns_29_mcp230xx.ino | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tasmota/xsns_29_mcp230xx.ino b/tasmota/xsns_29_mcp230xx.ino index 208fbcdd8..c2e160476 100644 --- a/tasmota/xsns_29_mcp230xx.ino +++ b/tasmota/xsns_29_mcp230xx.ino @@ -330,12 +330,33 @@ void MCP230xx_Show(bool json) if (json) { uint8_t gpio = MCP230xx_readGPIO(0); ResponseAppend_P(PSTR(",\"MCP230XX\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i"), - (gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1); + (gpio>>0)&1, (gpio>>1)&1, (gpio>>2)&1, (gpio>>3)&1, (gpio>>4)&1, (gpio>>5)&1, (gpio>>6)&1, (gpio>>7)&1); + uint8_t gpiob = 0; if (2 == mcp230xx_type) { - gpio = MCP230xx_readGPIO(1); + gpiob = MCP230xx_readGPIO(1); ResponseAppend_P(PSTR(",\"D8\":%i,\"D9\":%i,\"D10\":%i,\"D11\":%i,\"D12\":%i,\"D13\":%i,\"D14\":%i,\"D15\":%i"), - (gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1); + (gpiob>>0)&1, (gpiob>>1)&1, (gpiob>>2)&1, (gpiob>>3)&1, (gpiob>>4)&1, (gpiob>>5)&1, (gpiob>>6)&1, (gpiob>>7)&1); } + +#ifdef USE_MCP230xx_OUTPUT + uint8_t outputcount = 0; + for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { + if (Settings.mcp230xx_config[pinx].pinmode >= 5) { outputcount++; } + } + if (outputcount) { + uint16_t gpiototal = ((uint16_t)gpiob << 8) | gpio; + ResponseAppend_P(PSTR(",\"MCP230_OUT\":{")); + char stt[7]; + for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { + if (Settings.mcp230xx_config[pinx].pinmode >= 5) { + sprintf(stt, ConvertNumTxt(((gpiototal>>pinx)&1), Settings.mcp230xx_config[pinx].pinmode)); + ResponseAppend_P(PSTR("\"OUT_D%i\":\"%s\","), pinx, stt); + } + } + ResponseAppend_P(PSTR("\"END\":1}")); + } +#endif // USE_MCP230xx_OUTPUT + ResponseJsonEnd(); } } @@ -714,6 +735,7 @@ void MCP230xx_UpdateWebData(void) #endif // USE_MCP230xx_DISPLAYOUTPUT +/* #ifdef USE_MCP230xx_OUTPUT void MCP230xx_OutputTelemetry(void) @@ -743,6 +765,7 @@ void MCP230xx_OutputTelemetry(void) } #endif // USE_MCP230xx_OUTPUT +*/ void MCP230xx_Interrupt_Counter_Report(void) { ResponseTime_P(PSTR(",\"MCP230_INTTIMER\":{")); @@ -806,9 +829,11 @@ bool Xsns29(uint8_t function) if (mcp230xx_int_retainer_en) { // We have pins configured for interrupt retain reporting MCP230xx_Interrupt_Retain_Report(); } +/* #ifdef USE_MCP230xx_OUTPUT MCP230xx_OutputTelemetry(); #endif // USE_MCP230xx_OUTPUT +*/ } break; case FUNC_JSON_APPEND: From 8883ad4c29fd0ddc30abb3f9dff2f5e928f832fb Mon Sep 17 00:00:00 2001 From: bovirus <1262554+bovirus@users.noreply.github.com> Date: Fri, 24 Jul 2020 06:38:44 +0200 Subject: [PATCH 42/91] Update Italian language --- tasmota/language/it_IT.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index 4f74a9477..c45dc094f 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -1,7 +1,7 @@ /* it-IT.h - localization for Italian - Italy for Tasmota - Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola + Copyright (C) 2020 Gennaro Tortone - some mods by Antonio Fragola - rev. 24.07.2020 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 @@ -625,7 +625,7 @@ #define D_SENSOR_HJL_CF "BL0937 - CF" #define D_SENSOR_MCP39F5_TX "MCP39F5 - TX" #define D_SENSOR_MCP39F5_RX "MCP39F5 - RX" -#define D_SENSOR_MCP39F5_RST "MCP39F5 Rst" +#define D_SENSOR_MCP39F5_RST "MCP39F5 - Reset" #define D_SENSOR_CSE7766_TX "CSE7766 - TX" #define D_SENSOR_CSE7766_RX "CSE7766 - RX" #define D_SENSOR_PN532_TX "PN532 - TX" @@ -644,10 +644,10 @@ #define D_SENSOR_HRE_DATA "HRE - Dati" #define D_SENSOR_ADE7953_IRQ "ADE7953 - IRQ" #define D_SENSOR_BUZZER "Cicalino" -#define D_SENSOR_OLED_RESET "Ripristino OLED" +#define D_SENSOR_OLED_RESET "OLED - Reset" #define D_SENSOR_ZIGBEE_TXD "Zigbee - TX" #define D_SENSOR_ZIGBEE_RXD "Zigbee - RX" -#define D_SENSOR_ZIGBEE_RST "Zigbee Rst" +#define D_SENSOR_ZIGBEE_RST "Zigbee - Reset" #define D_SENSOR_SOLAXX1_TX "SolaxX1 - TX" #define D_SENSOR_SOLAXX1_RX "SolaxX1- RX" #define D_SENSOR_IBEACON_TX "iBeacon - TX" @@ -801,7 +801,7 @@ #define D_AS3935_DISTANCE "distanza:" #define D_AS3935_DISTURBER "disturbatore:" #define D_AS3935_VRMS "µVrms:" -#define D_AS3935_APRX "apross.:" +#define D_AS3935_APRX "appross.:" #define D_AS3935_AWAY "lontano" #define D_AS3935_LIGHT "illuminazione" #define D_AS3935_OUT "illuminazione fuori intervallo" From 959a8bb2347cf4e9ae41f5e73f44e8f17a2fe856 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Fri, 24 Jul 2020 12:17:19 +0200 Subject: [PATCH 43/91] disable serial log and enable I2C --- tasmota/tasmota_configurations.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index 99fec781f..da1248f6e 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -422,6 +422,9 @@ #undef FALLBACK_MODULE #define FALLBACK_MODULE SONOFF_ZB_BRIDGE // [Module2] Select default module on fast reboot where USER_MODULE is user template +#undef SERIAL_LOG_LEVEL +#define SERIAL_LOG_LEVEL LOG_LEVEL_NONE // [SerialLog] (LOG_LEVEL_NONE, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_DEBUG, LOG_LEVEL_DEBUG_MORE) + #undef USE_ARDUINO_OTA // Disable support for Arduino OTA #define USE_DOMOTICZ // Disable Domoticz #undef USE_HOME_ASSISTANT // Disable Home Assistant @@ -474,7 +477,7 @@ #undef USE_COUNTER // Disable counters #define USE_ADC_VCC // Display Vcc in Power status. Disable for use as Analog input on selected devices #undef USE_DS18x20 // Disable DS18x20 sensor -#undef USE_I2C // Disable all I2C sensors and devices +//#undef USE_I2C // Enable I2C, zbbridge uses i2c EEprom #undef USE_SPI // Disable all SPI devices #undef USE_DISPLAY // Disable Display support #undef USE_MHZ19 // Disable support for MH-Z19 CO2 sensor @@ -497,6 +500,7 @@ #undef USE_OPENTHERM // Disable support for OpenTherm (+15k code) #undef USE_ENERGY_SENSOR // Disable energy sensors +#undef USE_ADE7953 // Disable ADE7953 Energy monitor as used on Shelly 2.5 (I2C address 0x38) (+1k5) #undef USE_PZEM004T // Disable PZEM004T energy sensor #undef USE_PZEM_AC // Disable PZEM014,016 Energy monitor #undef USE_PZEM_DC // Disable PZEM003,017 Energy monitor From 3acae81fc0ed5081330aa6454ce0b59e3e11356c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 24 Jul 2020 15:30:21 +0200 Subject: [PATCH 44/91] Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` - Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` - Add command ``DzSend ,`` to send values or state to Domoticz --- RELEASENOTES.md | 2 + tasmota/CHANGELOG.md | 2 + tasmota/xdrv_07_domoticz.ino | 157 +++++++++++++++++++---------------- 3 files changed, 91 insertions(+), 70 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 490280e79..e2170880c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -64,6 +64,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT - Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset`` - Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message +- Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` - Fix escape of non-JSON received serial data (#8329) - Fix exception or watchdog on rule re-entry (#8757) - Add command ``Rule0`` to change global rule parameters @@ -74,6 +75,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add command ``SetOption99 0/1`` to enable zero cross detection on PWM dimmer - Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 +- Add command ``DzSend ,`` to send values or state to Domoticz - Add command ``Module2`` to configure fallback module on fast reboot (#8464) - Add command (``S``)``SerialSend6`` \ (#8937) - Add commands ``LedPwmOn 0..255``, ``LedPwmOff 0..255`` and ``LedPwmMode1 0/1`` to control led brightness by George (#8491) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 31231a6ad..d30040e93 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -5,6 +5,8 @@ - Remove Arduino ESP8266 Core support for versions before 2.7.1 - Change to limited support of Arduino IDE as an increasing amount of features cannot be compiled with Arduino IDE - Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message +- Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` +- Add command ``DzSend ,`` to send values or state to Domoticz - Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command (``S``)``SerialSend6`` \ (#8937) diff --git a/tasmota/xdrv_07_domoticz.ino b/tasmota/xdrv_07_domoticz.ino index 556997bb9..4f26a2c8a 100644 --- a/tasmota/xdrv_07_domoticz.ino +++ b/tasmota/xdrv_07_domoticz.ino @@ -21,18 +21,20 @@ #define XDRV_07 7 -#define D_PRFX_DOMOTICZ "Domoticz" +//#define D_PRFX_DOMOTICZ "Domoticz" +#define D_PRFX_DOMOTICZ "Dz" #define D_CMND_IDX "Idx" #define D_CMND_KEYIDX "KeyIdx" #define D_CMND_SWITCHIDX "SwitchIdx" #define D_CMND_SENSORIDX "SensorIdx" #define D_CMND_UPDATETIMER "UpdateTimer" +#define D_CMND_DZSEND "Send" const char kDomoticzCommands[] PROGMEM = D_PRFX_DOMOTICZ "|" // Prefix - D_CMND_IDX "|" D_CMND_KEYIDX "|" D_CMND_SWITCHIDX "|" D_CMND_SENSORIDX "|" D_CMND_UPDATETIMER ; + D_CMND_IDX "|" D_CMND_KEYIDX "|" D_CMND_SWITCHIDX "|" D_CMND_SENSORIDX "|" D_CMND_UPDATETIMER "|" D_CMND_DZSEND ; void (* const DomoticzCommand[])(void) PROGMEM = { - &CmndDomoticzIdx, &CmndDomoticzKeyIdx, &CmndDomoticzSwitchIdx, &CmndDomoticzSensorIdx, &CmndDomoticzUpdateTimer }; + &CmndDomoticzIdx, &CmndDomoticzKeyIdx, &CmndDomoticzSwitchIdx, &CmndDomoticzSensorIdx, &CmndDomoticzUpdateTimer, &CmndDomoticzSend }; const char DOMOTICZ_MESSAGE[] PROGMEM = "{\"idx\":%d,\"nvalue\":%d,\"svalue\":\"%s\",\"Battery\":%d,\"RSSI\":%d}"; @@ -44,6 +46,8 @@ const char kDomoticzSensors[] PROGMEM = D_DOMOTICZ_TEMP "|" D_DOMOTICZ_TEMP_HUM "|" D_DOMOTICZ_TEMP_HUM_BARO "|" D_DOMOTICZ_POWER_ENERGY "|" D_DOMOTICZ_ILLUMINANCE "|" D_DOMOTICZ_COUNT "|" D_DOMOTICZ_VOLTAGE "|" D_DOMOTICZ_CURRENT "|" D_DOMOTICZ_AIRQUALITY "|" D_DOMOTICZ_P1_SMART_METER "|" D_DOMOTICZ_SHUTTER ; +const char kDomoticzCommand[] PROGMEM = "switchlight|switchscene"; + char domoticz_in_topic[] = DOMOTICZ_IN_TOPIC; int domoticz_update_timer = 0; @@ -55,8 +59,7 @@ bool domoticz_update_flag = true; bool domoticz_is_shutter = false; #endif // USE_SHUTTER -int DomoticzBatteryQuality(void) -{ +int DomoticzBatteryQuality(void) { // Battery 0%: ESP 2.6V (minimum operating voltage is 2.5) // Battery 100%: ESP 3.6V (maximum operating voltage is 3.6) // Battery 101% to 200%: ESP over 3.6V (means over maximum operating voltage) @@ -76,16 +79,14 @@ int DomoticzBatteryQuality(void) return quality; } -int DomoticzRssiQuality(void) -{ +int DomoticzRssiQuality(void) { // RSSI range: 0% to 10% (12 means disable RSSI in Domoticz) return WifiGetRssiAsQuality(WiFi.RSSI()) / 10; } #ifdef USE_SONOFF_IFAN -void MqttPublishDomoticzFanState(void) -{ +void MqttPublishDomoticzFanState(void) { if (Settings.flag.mqtt_enabled && Settings.domoticz_relay_idx[1]) { // SetOption3 - Enable MQTT char svalue[8]; // Fanspeed value @@ -98,8 +99,7 @@ void MqttPublishDomoticzFanState(void) } } -void DomoticzUpdateFanState(void) -{ +void DomoticzUpdateFanState(void) { if (domoticz_update_flag) { MqttPublishDomoticzFanState(); } @@ -107,8 +107,7 @@ void DomoticzUpdateFanState(void) } #endif // USE_SONOFF_IFAN -void MqttPublishDomoticzPowerState(uint8_t device) -{ +void MqttPublishDomoticzPowerState(uint8_t device) { if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT if (device < 1) { device = 1; } if ((device > devices_present) || (device > MAX_DOMOTICZ_IDX)) { return; } @@ -138,16 +137,14 @@ void MqttPublishDomoticzPowerState(uint8_t device) } } -void DomoticzUpdatePowerState(uint8_t device) -{ +void DomoticzUpdatePowerState(uint8_t device) { if (domoticz_update_flag) { MqttPublishDomoticzPowerState(device); } domoticz_update_flag = true; } -void DomoticzMqttUpdate(void) -{ +void DomoticzMqttUpdate(void) { if (domoticz_subscribe && (Settings.domoticz_update_timer || domoticz_update_timer)) { domoticz_update_timer--; if (domoticz_update_timer <= 0) { @@ -175,8 +172,7 @@ void DomoticzMqttUpdate(void) } } -void DomoticzMqttSubscribe(void) -{ +void DomoticzMqttSubscribe(void) { uint8_t maxdev = (devices_present > MAX_DOMOTICZ_IDX) ? MAX_DOMOTICZ_IDX : devices_present; for (uint32_t i = 0; i < maxdev; i++) { if (Settings.domoticz_relay_idx[i]) { @@ -217,8 +213,7 @@ void DomoticzMqttSubscribe(void) } */ -bool DomoticzMqttData(void) -{ +bool DomoticzMqttData(void) { domoticz_update_flag = true; if (strncasecmp_P(XdrvMailbox.topic, PSTR(DOMOTICZ_OUT_TOPIC), strlen(DOMOTICZ_OUT_TOPIC)) != 0) { @@ -359,15 +354,19 @@ bool DomoticzMqttData(void) /*********************************************************************************************/ -bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg) -{ +void DomoticzSendSwitch(uint32_t type, uint32_t index, uint32_t state) { + char stemp[16]; // "switchlight" or "switchscene" + Response_P(PSTR("{\"command\":\"%s\",\"idx\":%d,\"switchcmd\":\"%s\"}"), + GetTextIndexed(stemp, sizeof(stemp), type, kDomoticzCommand), index, (state) ? (POWER_TOGGLE == state) ? "Toggle" : "On" : "Off"); // Domoticz case sensitive + MqttPublish(domoticz_in_topic); +} + +bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg) { bool result = false; if (device <= MAX_DOMOTICZ_IDX) { if ((Settings.domoticz_key_idx[device -1] || Settings.domoticz_switch_idx[device -1]) && (svalflg)) { - Response_P(PSTR("{\"command\":\"switchlight\",\"idx\":%d,\"switchcmd\":\"%s\"}"), - (key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], (state) ? (POWER_TOGGLE == state) ? "Toggle" : "On" : "Off"); - MqttPublish(domoticz_in_topic); + DomoticzSendSwitch(0, (key) ? Settings.domoticz_switch_idx[device -1] : Settings.domoticz_key_idx[device -1], state); result = true; } } @@ -391,46 +390,46 @@ bool DomoticzSendKey(uint8_t key, uint8_t device, uint8_t state, uint8_t svalflg * \*********************************************************************************************/ -uint8_t DomoticzHumidityState(float h) -{ - return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1; +void DomoticzSendData(uint32_t sensor_idx, uint32_t idx, char *data) { + if (DZ_AIRQUALITY == sensor_idx) { + Response_P(PSTR("{\"idx\":%d,\"nvalue\":%s,\"Battery\":%d,\"RSSI\":%d}"), + idx, data, DomoticzBatteryQuality(), DomoticzRssiQuality()); + } else { + uint8_t nvalue = 0; +#ifdef USE_SHUTTER + if (DZ_SHUTTER == sensor_idx) { + uint8_t position = atoi(data); + nvalue = position < 2 ? 0 : (position == 100 ? 1 : 2); + } +#endif // USE_SHUTTER + Response_P(DOMOTICZ_MESSAGE, + idx, nvalue, data, DomoticzBatteryQuality(), DomoticzRssiQuality()); + } + MqttPublish(domoticz_in_topic); } -void DomoticzSensor(uint8_t idx, char *data) -{ +void DomoticzSensor(uint8_t idx, char *data) { if (Settings.domoticz_sensor_idx[idx]) { char dmess[128]; // {"idx":26700,"nvalue":0,"svalue":"22330.1;10234.4;22000.5;10243.4;1006;3000","Battery":100,"RSSI":10} memcpy(dmess, mqtt_data, sizeof(dmess)); - if (DZ_AIRQUALITY == idx) { - Response_P(PSTR("{\"idx\":%d,\"nvalue\":%s,\"Battery\":%d,\"RSSI\":%d}"), - Settings.domoticz_sensor_idx[idx], data, DomoticzBatteryQuality(), DomoticzRssiQuality()); - } else { - uint8_t nvalue = 0; -#ifdef USE_SHUTTER - if (DZ_SHUTTER == idx) { - uint8_t position = atoi(data); - nvalue = position < 2 ? 0 : (position == 100 ? 1 : 2); - } -#endif // USE_SHUTTER - Response_P(DOMOTICZ_MESSAGE, - Settings.domoticz_sensor_idx[idx], nvalue, data, DomoticzBatteryQuality(), DomoticzRssiQuality()); - } - MqttPublish(domoticz_in_topic); + DomoticzSendData(idx, Settings.domoticz_sensor_idx[idx], data); memcpy(mqtt_data, dmess, sizeof(dmess)); } } -void DomoticzSensor(uint8_t idx, uint32_t value) -{ +uint8_t DomoticzHumidityState(float h) { + return (!h) ? 0 : (h < 40) ? 2 : (h > 70) ? 3 : 1; +} + +void DomoticzSensor(uint8_t idx, uint32_t value) { char data[16]; snprintf_P(data, sizeof(data), PSTR("%d"), value); DomoticzSensor(idx, data); } //void DomoticzTempHumPressureSensor(float temp, float hum, float baro = -1); -void DomoticzTempHumPressureSensor(float temp, float hum, float baro) -{ +void DomoticzTempHumPressureSensor(float temp, float hum, float baro) { char temperature[FLOATSZ]; dtostrfd(temp, 2, temperature); char humidity[FLOATSZ]; @@ -449,15 +448,13 @@ void DomoticzTempHumPressureSensor(float temp, float hum, float baro) } } -void DomoticzSensorPowerEnergy(int power, char *energy) -{ +void DomoticzSensorPowerEnergy(int power, char *energy) { char data[16]; snprintf_P(data, sizeof(data), PSTR("%d;%s"), power, energy); DomoticzSensor(DZ_POWER_ENERGY, data); } -void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char *return2, int power) -{ +void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char *return2, int power) { //usage1 = energy usage meter tariff 1, This is an incrementing counter //usage2 = energy usage meter tariff 2, This is an incrementing counter //return1 = energy return meter tariff 1, This is an incrementing counter @@ -478,8 +475,7 @@ void DomoticzSensorP1SmartMeter(char *usage1, char *usage2, char *return1, char * Commands \*********************************************************************************************/ -void CmndDomoticzIdx(void) -{ +void CmndDomoticzIdx(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) { if (XdrvMailbox.payload >= 0) { Settings.domoticz_relay_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; @@ -489,8 +485,7 @@ void CmndDomoticzIdx(void) } } -void CmndDomoticzKeyIdx(void) -{ +void CmndDomoticzKeyIdx(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) { if (XdrvMailbox.payload >= 0) { Settings.domoticz_key_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; @@ -499,8 +494,7 @@ void CmndDomoticzKeyIdx(void) } } -void CmndDomoticzSwitchIdx(void) -{ +void CmndDomoticzSwitchIdx(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_DOMOTICZ_IDX)) { if (XdrvMailbox.payload >= 0) { Settings.domoticz_switch_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; @@ -509,8 +503,7 @@ void CmndDomoticzSwitchIdx(void) } } -void CmndDomoticzSensorIdx(void) -{ +void CmndDomoticzSensorIdx(void) { if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= DZ_MAX_SENSORS)) { if (XdrvMailbox.payload >= 0) { Settings.domoticz_sensor_idx[XdrvMailbox.index -1] = XdrvMailbox.payload; @@ -519,14 +512,41 @@ void CmndDomoticzSensorIdx(void) } } -void CmndDomoticzUpdateTimer(void) -{ +void CmndDomoticzUpdateTimer(void) { if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload < 3601)) { Settings.domoticz_update_timer = XdrvMailbox.payload; } ResponseCmndNumber(Settings.domoticz_update_timer); } +void CmndDomoticzSend(void) { + // DzSend1 , - {\"idx\":,\"nvalue\":0,\"svalue\":\"\",\"Battery\":xx,\"RSSI\":yy} + // DzSend2 , - USE_SHUTTER only - {\"idx\":,\"nvalue\":,\"svalue\":\"\",\"Battery\":xx,\"RSSI\":yy} + // DzSend3 , - {\"idx\":,\"nvalue\":,\"Battery\":xx,\"RSSI\":yy} + // DzSend4 , - {\"command\":\"switchlight\",\"idx\":,\"switchcmd\":\"\"} + // DzSend5 , - {\"command\":\"switchscene\",\"idx\":,\"switchcmd\":\"\"} + + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= 5)) { + if (XdrvMailbox.data_len > 0) { + if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry + char *data; + uint32_t index = strtoul(strtok_r(XdrvMailbox.data, ",", &data), nullptr, 10); + if ((index > 0) && (data != nullptr)) { + if (XdrvMailbox.index > 3) { + uint32_t state = strtoul(data, nullptr, 10); // 0, 1 or 2 + DomoticzSendSwitch(XdrvMailbox.index -4, index, state); + } else { + uint32_t type = DZ_TEMP; + if (2 == XdrvMailbox.index) { type = DZ_SHUTTER; } + else if (3 == XdrvMailbox.index) { type = DZ_AIRQUALITY; } + DomoticzSendData(type, index, data); + } + } + } + } + } +} + /*********************************************************************************************\ * Presentation \*********************************************************************************************/ @@ -554,8 +574,7 @@ const char HTTP_FORM_DOMOTICZ_SENSOR[] PROGMEM = const char HTTP_FORM_DOMOTICZ_TIMER[] PROGMEM = "" D_DOMOTICZ_UPDATE_TIMER " (" STR(DOMOTICZ_UPDATE_TIMER) ")"; -void HandleDomoticzConfiguration(void) -{ +void HandleDomoticzConfiguration(void) { if (!HttpCheckPriviledgedAccess()) { return; } AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_DOMOTICZ); @@ -596,8 +615,7 @@ void HandleDomoticzConfiguration(void) WSContentStop(); } -void DomoticzSaveSettings(void) -{ +void DomoticzSaveSettings(void) { char stemp[20]; char ssensor_indices[6 * MAX_DOMOTICZ_SNS_IDX]; char tmp[100]; @@ -635,8 +653,7 @@ void DomoticzSaveSettings(void) * Interface \*********************************************************************************************/ -bool Xdrv07(uint8_t function) -{ +bool Xdrv07(uint8_t function) { bool result = false; if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT From 0467ffc62a2e33a69408d66b9ce0bdb61f0d56a8 Mon Sep 17 00:00:00 2001 From: bettman66 Date: Sat, 25 Jul 2020 09:21:56 +0200 Subject: [PATCH 45/91] millennium error --- tasmota/xdrv_16_tuyamcu.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xdrv_16_tuyamcu.ino b/tasmota/xdrv_16_tuyamcu.ino index 82bc4ef7f..a01881ac1 100644 --- a/tasmota/xdrv_16_tuyamcu.ino +++ b/tasmota/xdrv_16_tuyamcu.ino @@ -808,7 +808,7 @@ void TuyaSetTime(void) { uint16_t payload_len = 8; uint8_t payload_buffer[8]; payload_buffer[0] = 0x01; - payload_buffer[1] = (uint8_t)RtcTime.year; + payload_buffer[1] = RtcTime.year - 2000; payload_buffer[2] = RtcTime.month; payload_buffer[3] = RtcTime.day_of_month; payload_buffer[4] = RtcTime.hour; From 38179062aed0e8fe3a2224079790aba5c574f0d5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 25 Jul 2020 14:52:37 +0200 Subject: [PATCH 46/91] Refactor TuyaMcu year --- tasmota/xdrv_16_tuyamcu.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xdrv_16_tuyamcu.ino b/tasmota/xdrv_16_tuyamcu.ino index a01881ac1..b4b9a5ff4 100644 --- a/tasmota/xdrv_16_tuyamcu.ino +++ b/tasmota/xdrv_16_tuyamcu.ino @@ -808,7 +808,7 @@ void TuyaSetTime(void) { uint16_t payload_len = 8; uint8_t payload_buffer[8]; payload_buffer[0] = 0x01; - payload_buffer[1] = RtcTime.year - 2000; + payload_buffer[1] = RtcTime.year %100; payload_buffer[2] = RtcTime.month; payload_buffer[3] = RtcTime.day_of_month; payload_buffer[4] = RtcTime.hour; From 781cb4d9c77744bccd58ef9a6380766235ea5b3c Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 25 Jul 2020 15:40:42 +0200 Subject: [PATCH 47/91] Zigbee EZSP improvements and reduced logging --- tasmota/i18n.h | 2 + tasmota/tasmota_template.h | 11 +- tasmota/xdrv_23_zigbee_0_constants.ino | 6 -- tasmota/xdrv_23_zigbee_7_statemachine.ino | 2 +- tasmota/xdrv_23_zigbee_8_parsers.ino | 117 ++++++++++++++++++++++ tasmota/xdrv_23_zigbee_9_serial.ino | 57 +++++++---- 6 files changed, 162 insertions(+), 33 deletions(-) diff --git a/tasmota/i18n.h b/tasmota/i18n.h index a91ede963..6b97badd5 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -514,6 +514,7 @@ #define D_CMND_ZIGBEE_EZSP_SEND "EZSPSend" #define D_CMND_ZIGBEE_EZSP_SEND_RAW "EZSPSendRaw" #define D_JSON_ZIGBEE_STATE "ZbState" + #define D_JSON_ZIGBEE_ROUTE_ERROR "ZbRouteError" #define D_JSON_ZIGBEEZNPRECEIVED "ZbZNPReceived" #define D_JSON_ZIGBEE_EZSP_RECEIVED "ZbEZSPReceived" #define D_JSON_ZIGBEEZNPSENT "ZbZNPSent" @@ -549,6 +550,7 @@ #define D_JSON_ZIGBEE_UNBIND "ZbUnbind" #define D_CMND_ZIGBEE_BIND_STATE "BindState" #define D_JSON_ZIGBEE_BIND_STATE "ZbBindState" +#define D_JSON_ZIGBEE_PARENT "ZbParent" #define D_CMND_ZIGBEE_PING "Ping" #define D_JSON_ZIGBEE_PING "ZbPing" #define D_JSON_ZIGBEE_IEEE "IEEEAddr" diff --git a/tasmota/tasmota_template.h b/tasmota/tasmota_template.h index 8c62a236b..1c38f0420 100644 --- a/tasmota/tasmota_template.h +++ b/tasmota/tasmota_template.h @@ -2283,21 +2283,22 @@ const mytmplt kModules[MAXMODULE] PROGMEM = { 0, 0, 0, 0 }, { // SONOFF_ZB_BRIDGE - Sonoff Zigbee Bridge (ESP8266) - GPIO_LED1_INV, // GPIO00 Led (0 = On, 1 = Off) - Status + GPIO_LED1_INV, // GPIO00 Green Led (0 = On, 1 = Off) - Traffic between ESP and EFR GPIO_ZIGBEE_TX, // GPIO01 Zigbee Serial control 0, // GPIO02 GPIO_ZIGBEE_RX, // GPIO03 Zigbee Serial control - GPIO_ZIGBEE_RST, // GPIO04 ZIgbee Reset - 0, + GPIO_ZIGBEE_RST, // GPIO04 Zigbee Reset + 0, // GPIO05 EFR32 Bootloader mode (drive Low for Gecko Bootloader, inactive or high for Zigbee EmberZNet) // GPIO06 (SD_CLK Flash) // GPIO07 (SD_DATA0 Flash QIO/DIO/DOUT) // GPIO08 (SD_DATA1 Flash QIO/DIO/DOUT) 0, // GPIO09 (SD_DATA2 Flash QIO) 0, // GPIO10 (SD_DATA3 Flash QIO) // GPIO11 (SD_CMD Flash) - 0, + GPIO_I2C_SDA, // GPIO12 I2C SDA - connected to 512KB EEPROM GPIO_LEDLNK_INV, // GPIO13 Blue Led (0 = On, 1 = Off) - Link status - 0, 0, + GPIO_I2C_SCL, // GPIO14 I2C SCL - connected to 512KB EEPROM + 0, // GPIO15 connected to IO15 pad, also used for logging GPIO_KEY1, // GPIO16 Button 0 } diff --git a/tasmota/xdrv_23_zigbee_0_constants.ino b/tasmota/xdrv_23_zigbee_0_constants.ino index ea087e70f..c24e5c091 100644 --- a/tasmota/xdrv_23_zigbee_0_constants.ino +++ b/tasmota/xdrv_23_zigbee_0_constants.ino @@ -1105,12 +1105,6 @@ enum ZCL_Global_Commands { #define ZF(s) static const char ZS_ ## s[] PROGMEM = #s; #define Z(s) ZS_ ## s -typedef struct Z_StatusLine { - uint32_t status; // no need to use uint8_t since it uses 32 bits anyways - const char * status_msg; -} Z_StatusLine; - - // ZDP Enumeration, see Zigbee spec 2.4.5 String getZDPStatusMessage(uint8_t status) { static const char StatusMsg[] PROGMEM = "SUCCESS|INV_REQUESTTYPE|DEVICE_NOT_FOUND|INVALID_EP|NOT_ACTIVE|NOT_SUPPORTED" diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index f04c0ca34..f46b34f7c 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -710,7 +710,7 @@ ZBM(ZBS_SET_POLICY_02, EZSP_setPolicy, 0x00 /*high*/, EZSP_UNICAST_REPLIES_PO ZBM(ZBS_SET_POLICY_03, EZSP_setPolicy, 0x00 /*high*/, EZSP_POLL_HANDLER_POLICY, EZSP_POLL_HANDLER_IGNORE) // 55000330 ZBM(ZBS_SET_POLICY_04, EZSP_setPolicy, 0x00 /*high*/, EZSP_MESSAGE_CONTENTS_IN_CALLBACK_POLICY, - EZSP_MESSAGE_TAG_AND_CONTENTS_IN_CALLBACK) // 55000441 + EZSP_MESSAGE_TAG_ONLY_IN_CALLBACK) // 55000440 ZBM(ZBS_SET_POLICY_05, EZSP_setPolicy, 0x00 /*high*/, EZSP_TC_KEY_REQUEST_POLICY, EZSP_ALLOW_TC_KEY_REQUESTS_AND_SEND_CURRENT_KEY) // 55000551 ZBM(ZBS_SET_POLICY_06, EZSP_setPolicy, 0x00 /*high*/, EZSP_APP_KEY_REQUEST_POLICY, diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 58d4e330b..7f1c98e0a 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -115,6 +115,43 @@ int32_t EZ_NetworkParameters(int32_t res, class SBuffer &buf) { return res; } +// +// Handle a "incomingRouteErrorHandler" incoming message +// +int32_t EZ_RouteError(int32_t res, const class SBuffer &buf) { + uint8_t status = buf.get8(2); + uint16_t shortaddr = buf.get16(3); + + Response_P(PSTR("{\"" D_JSON_ZIGBEE_ROUTE_ERROR "\":{" + "\"ShortAddr\":\"0x%04X\",\"" D_JSON_ZIGBEE_STATUS "\":%d,\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"0x%s\"}}"), + shortaddr, status, ""); + + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); + + return -1; +} + +// +// Handle a "permitJoining" incoming message +// +int32_t EZ_PermitJoinRsp(int32_t res, const class SBuffer &buf) { + uint8_t status = buf.get8(2); + + Response_P(PSTR("{\"" D_JSON_ZIGBEE_STATE "\":{" + "\"Status\":%d,\"Message\":\"%s"), + (0 == status) ? ZIGBEE_STATUS_PERMITJOIN_OPEN_60 : ZIGBEE_STATUS_PERMITJOIN_CLOSE, + (0 == status) ? PSTR("Pairing mode enabled") : PSTR("Pairing mode error") + ); + if (status) { + ResponseAppend_P("0x%02X", status); + } + ResponseAppend_P(PSTR("\"}}")); + + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); + + return -1; +} + #endif // USE_ZIGBEE_EZSP /*********************************************************************************************\ @@ -785,6 +822,72 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { return -1; } +// +// Handle Parent Annonce Rsp incoming message +// +// rsp: true = ZDO_Parent_annce_rsp, false = ZDO_Parent_annce +int32_t Z_ParentAnnceRsp(int32_t res, const class SBuffer &buf, bool rsp) { +#ifdef USE_ZIGBEE_ZNP +// uint16_t shortaddr = buf.get16(2); +// uint8_t status = buf.get8(4); +// uint8_t bind_total = buf.get8(5); +// uint8_t bind_start = buf.get8(6); +// uint8_t bind_len = buf.get8(7); +// const size_t prefix_len = 8; +#endif // USE_ZIGBEE_ZNP +#ifdef USE_ZIGBEE_EZSP + size_t prefix_len; + uint8_t status; + uint8_t num_children; + uint16_t shortaddr = buf.get16(buf.len()-2); + if (rsp) { + status = buf.get8(0); + num_children = buf.get8(1); + prefix_len = 2; + } else { + status = 0; + num_children = buf.get8(0); + prefix_len = 1; + } +#endif // USE_ZIGBEE_EZSP + + const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); + + Response_P(PSTR("{\"" D_JSON_ZIGBEE_PARENT "\":{\"" D_JSON_ZIGBEE_DEVICE "\":\"0x%04X\""), shortaddr); + if (friendlyName) { + ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_NAME "\":\"%s\""), friendlyName); + } + if (rsp) { + ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d" + ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" + ), status, getZigbeeStatusMessage(status).c_str()); + } + ResponseAppend_P(PSTR(",\"Children\":%d" + ",\"ChildInfo\":[" + ), num_children); + + uint32_t idx = prefix_len; + for (uint32_t i = 0; i < num_children; i++) { + if (idx + 8 > buf.len()) { break; } // overflow, frame size is between 14 and 21 + + uint64_t child_ieee = buf.get64(idx); + idx += 8; + + if (i > 0) { + ResponseAppend_P(PSTR(",")); + } + char hex[20]; + Uint64toHex(child_ieee, hex, 64); + ResponseAppend_P(PSTR("\"0x%s\""), hex); + } + + ResponseAppend_P(PSTR("]}}")); + + MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_BIND_STATE)); + + return -1; +} + /*********************************************************************************************\ * Send specific ZNP messages \*********************************************************************************************/ @@ -1051,6 +1154,14 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { return Z_UnbindRsp(res, zdo_buf); case ZDO_Mgmt_Bind_rsp: return Z_MgmtBindRsp(res, zdo_buf); + case ZDO_Parent_annce: + return Z_ParentAnnceRsp(res, zdo_buf, false); + case ZDO_Parent_annce_rsp: + return Z_ParentAnnceRsp(res, zdo_buf, true); + default: + // TODO move later to LOG_LEVEL_DEBUG + AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: Internal ZDO message 0x%04X sent from 0x%04X %s"), clusterid, srcaddr, wasbroadcast ? PSTR("(broadcast)") : ""); + break; } } else { bool defer_attributes = false; // do we defer attributes reporting to coalesce @@ -1106,6 +1217,12 @@ int32_t EZ_Recv_Default(int32_t res, const class SBuffer &buf) { case EZSP_trustCenterJoinHandler: return EZ_ReceiveTCJoinHandler(res, buf); break; + case EZSP_incomingRouteErrorHandler: + return EZ_RouteError(res, buf); + break; + case EZSP_permitJoining: + return EZ_PermitJoinRsp(res, buf); + break; } return -1; } diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index bfec8c3bb..1715d6763 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -118,7 +118,7 @@ void ZigbeeInputLoop(void) { char hex_char[(zigbee_buffer->len() * 2) + 2]; ToHex_P((unsigned char*)zigbee_buffer->getBuffer(), zigbee_buffer->len(), hex_char, sizeof(hex_char)); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric()); + // AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric()); // buffer received, now check integrity if (zigbee_buffer->len() != zigbee_frame_len) { // Len is not correct, log and reject frame @@ -163,7 +163,7 @@ void ZigbeeInputLoop(void) { yield(); uint8_t zigbee_in_byte = ZigbeeSerial->read(); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x%02X len=%d"), zigbee_in_byte, zigbee_buffer->len()); + // AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x%02X len=%d"), zigbee_in_byte, zigbee_buffer->len()); // if (0 == zigbee_buffer->len()) { // make sure all variables are correctly initialized // escape = false; @@ -175,13 +175,13 @@ void ZigbeeInputLoop(void) { } if (ZIGBEE_EZSP_ESCAPE == zigbee_in_byte) { - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: Escape byte received")); + // AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: Escape byte received")); escape = true; continue; } if (ZIGBEE_EZSP_CANCEL == zigbee_in_byte) { - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x1A, cancel byte received, discarding %d bytes"), zigbee_buffer->len()); + // AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: ZbInput byte=0x1A, cancel byte received, discarding %d bytes"), zigbee_buffer->len()); zigbee_buffer->setLen(0); // empty buffer escape = false; frame_complete = false; @@ -215,7 +215,7 @@ void ZigbeeInputLoop(void) { char hex_char[frame_len * 2 + 2]; ToHex_P((unsigned char*)zigbee_buffer->getBuffer(), zigbee_buffer->len(), hex_char, sizeof(hex_char)); - AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric()); + // AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "Bytes follow_read_metric = %0d"), ZigbeeSerial->getLoopReadMetric()); if ((frame_complete) && (frame_len >= 3)) { // frame received and has at least 3 bytes (without EOF), checking CRC // AddLog_P2(LOG_LEVEL_INFO, PSTR(D_JSON_ZIGBEE_EZSP_RECEIVED ": received raw frame %s"), hex_char); @@ -253,12 +253,7 @@ void ZigbeeInputLoop(void) { } ToHex_P((unsigned char*)ezsp_buffer.getBuffer(), ezsp_buffer.len(), hex_char, sizeof(hex_char)); - Response_P(PSTR("{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "2\":\"%s\"}"), hex_char); - if (Settings.flag3.tuya_serial_mqtt_publish) { - MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR)); - } else { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); // TODO move to LOG_LEVEL_DEBUG when stable - } + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE "{\"" D_JSON_ZIGBEE_EZSP_RECEIVED "2\":\"%s\"}"), hex_char); // now process the message ZigbeeProcessInputRaw(ezsp_buffer); } @@ -491,7 +486,7 @@ void ZigbeeEZSPSendRaw(const uint8_t *msg, size_t len, bool send_cancel) { // Now send a MQTT message to report the sent message char hex_char[(len * 2) + 2]; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEE_EZSP_SENT_RAW " %s"), + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR(D_LOG_ZIGBEE D_JSON_ZIGBEE_EZSP_SENT_RAW " %s"), ToHex_P(msg, len, hex_char, sizeof(hex_char))); } @@ -500,7 +495,7 @@ void ZigbeeEZSPSendRaw(const uint8_t *msg, size_t len, bool send_cancel) { void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len) { char hex_char[len*2 + 2]; ToHex_P(msg, len, hex_char, sizeof(hex_char)); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "ZbEZSPSend %s"), hex_char); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_ZIGBEE "ZbEZSPSend %s"), hex_char); SBuffer cmd(len+3); // prefix with seq number (1 byte) and frame control bytes (2 bytes) @@ -517,7 +512,7 @@ void ZigbeeEZSPSendCmd(const uint8_t *msg, size_t len) { void ZigbeeEZSPSendDATA_frm(bool send_cancel, uint8_t to_frm, uint8_t from_ack) { SBuffer *buf = EZSP_Serial.to_packets[to_frm]; if (!buf) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Buffer for packet %d is not allocated"), EZSP_Serial.to_send); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: Buffer for packet %d is not allocated"), EZSP_Serial.to_send); return; } @@ -534,7 +529,7 @@ void ZigbeeEZSPSendDATA(const uint8_t *msg, size_t len) { buf->add8(0x00); // placeholder for control_byte buf->addBuffer(msg, len); // - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: adding packet to_send, to_ack:%d, to_send:%d, to_end:%d"), + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: adding packet to_send, to_ack:%d, to_send:%d, to_end:%d"), EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end); uint8_t to_frm = EZSP_Serial.to_end; if (EZSP_Serial.to_packets[to_frm]) { @@ -579,7 +574,27 @@ int32_t ZigbeeProcessInputEZSP(class SBuffer &buf) { if (Settings.flag3.tuya_serial_mqtt_publish) { MqttPublishPrefixTopicRulesProcess_P(TELE, PSTR(D_RSLT_SENSOR)); } else { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); // TODO move to LOG_LEVEL_DEBUG when stable + // demote less interesting messages to LOG_LEVEL_DEBUG + uint32_t log_level = LOG_LEVEL_INFO; + switch (buf.get16(0)) { + case EZSP_version: // 0000 + case EZSP_addEndpoint: // 0200 + case EZSP_setConcentrator: // 1000 + case EZSP_networkInit: // 1700 + case EZSP_stackStatusHandler: // 1900 + case EZSP_permitJoining: // 2200 + case EZSP_getEui64: // 2600 + case EZSP_getNodeId: // 2700 + case EZSP_sendUnicast: // 3400 + case EZSP_sendBroadcast: // 3600 + case EZSP_messageSentHandler: // 3F00 + case EZSP_setConfigurationValue: // 5300 + case EZSP_setPolicy: // 5500 + case EZSP_setMulticastTableEntry: // 6400 + log_level = LOG_LEVEL_DEBUG; + break; + } + AddLog_P2(log_level, PSTR(D_LOG_ZIGBEE "%s"), mqtt_data); // TODO move to LOG_LEVEL_DEBUG when stable } // Pass message to state machine @@ -589,14 +604,14 @@ int32_t ZigbeeProcessInputEZSP(class SBuffer &buf) { // Check if we advanced in the ACKed frames, and free from memory packets acknowledged void EZSP_HandleAck(uint8_t new_ack) { if (EZSP_Serial.to_ack != new_ack) { // new ack receveid - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: new ack/data received, was %d now %d"), EZSP_Serial.to_ack, new_ack); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: new ack/data received, was %d now %d"), EZSP_Serial.to_ack, new_ack); uint32_t i = EZSP_Serial.to_ack; do { if (EZSP_Serial.to_packets[i]) { delete EZSP_Serial.to_packets[i]; EZSP_Serial.to_packets[i] = nullptr; } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: freeing packet %d from memory"), i); + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: freeing packet %d from memory"), i); i = (i + 1) & 0x07; } while (i != new_ack); EZSP_Serial.to_ack = new_ack; @@ -617,10 +632,10 @@ int32_t ZigbeeProcessInputRaw(class SBuffer &buf) { } else if (frame_type == 0xA0) { // NAK - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Received NAK %d, to_ack:%d, to_send:%d, to_end:%d"), + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: Received NAK %d, to_ack:%d, to_send:%d, to_end:%d"), ack_num, EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end); EZSP_Serial.to_send = ack_num; - AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: NAK, resending packet %d"), ack_num); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: NAK, resending packet %d"), ack_num); } else if (control_byte == 0xC1) { // RSTACK @@ -844,7 +859,7 @@ void ZigbeeOutputLoop(void) { #ifdef USE_ZIGBEE_EZSP // while (EZSP_Serial.to_send != EZSP_Serial.to_end) { if (EZSP_Serial.to_send != EZSP_Serial.to_end) { // we send only one packet per tick to lower the chance of NAK - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Something to_send, to_ack:%d, to_send:%d, to_end:%d"), + AddLog_P2(LOG_LEVEL_DEBUG_MORE, PSTR("ZIG: Something to_send, to_ack:%d, to_send:%d, to_end:%d"), EZSP_Serial.to_ack, EZSP_Serial.to_send, EZSP_Serial.to_end); // we have a frame waiting to be sent ZigbeeEZSPSendDATA_frm(true, EZSP_Serial.to_send, EZSP_Serial.from_ack); From 520558d3817b458ec9d8e3384eeafe0d9cd3c2d9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 25 Jul 2020 17:08:11 +0200 Subject: [PATCH 48/91] Fix no sensor issue --- tasmota/xsns_interface.ino | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tasmota/xsns_interface.ino b/tasmota/xsns_interface.ino index b6abce101..0c85854de 100644 --- a/tasmota/xsns_interface.ino +++ b/tasmota/xsns_interface.ino @@ -868,6 +868,11 @@ void XsnsSensorState(void) bool XsnsNextCall(uint8_t Function, uint8_t &xsns_index) { + if (0 == xsns_present) { + xsns_index = 0; + return false; + } + xsns_index++; if (xsns_index == xsns_present) { xsns_index = 0; } From 806a862cac21ace0b6c77dacb03460565b2d0b62 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sat, 25 Jul 2020 18:25:06 +0200 Subject: [PATCH 49/91] Add EFR32 upload framework --- tasmota/xdrv_01_webserver.ino | 45 ++++++++-- tasmota/xdrv_23_zigbee_9a_upload.ino | 121 +++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 7 deletions(-) create mode 100644 tasmota/xdrv_23_zigbee_9a_upload.ino diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index b94a2a902..384b38c6f 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -44,7 +44,7 @@ const uint16_t HTTP_OTA_RESTART_RECONNECT_TIME = 28000; // milliseconds - Allow uint8_t *efm8bb1_update = nullptr; #endif // USE_RF_FLASH -enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT }; +enum UploadTypes { UPL_TASMOTA, UPL_SETTINGS, UPL_EFM8BB1, UPL_TASMOTACLIENT, UPL_EFR32 }; static const char * HEADER_KEYS[] = { "User-Agent", }; @@ -2627,20 +2627,26 @@ void HandleUploadDone(void) WSContentSend_P(PSTR("%06x'>" D_SUCCESSFUL "
"), WebColor(COL_TEXT_SUCCESS)); WSContentSend_P(HTTP_MSG_RSTRT); ShowWebSource(SRC_WEBGUI); + restart_flag = 2; // Always restart to re-enable disabled features during update +#if defined(USE_ZIGBEE) && defined(USE_ZIGBEE_EZSP) + if (ZigbeeUploadOtaReady()) { + restart_flag = 0; // Hold restart as firmware still needs to be written to MCU EFR32 + } +#endif // USE_ZIGBEE and USE_ZIGBEE_EZSP #ifdef USE_TASMOTA_CLIENT if (TasmotaClient_GetFlagFlashing()) { - restart_flag = 0; - } else { // It was a normal firmware file, or we are ready to restart device - restart_flag = 2; + restart_flag = 0; // Hold restart as code still needs to be trasnferred to Atmega } -#else - restart_flag = 2; // Always restart to re-enable disabled features during update -#endif +#endif // USE_TASMOTA_CLIENT } SettingsBufferFree(); WSContentSend_P(PSTR("
")); WSContentSpaceButton(BUTTON_MAIN); WSContentStop(); + +#if defined(USE_ZIGBEE) && defined(USE_ZIGBEE_EZSP) + ZigbeeUploadXmodem(); +#endif // USE_ZIGBEE and USE_ZIGBEE_EZSP #ifdef USE_TASMOTA_CLIENT if (TasmotaClient_GetFlagFlashing()) { TasmotaClient_Flash(); @@ -2707,6 +2713,15 @@ void HandleUploadLoop(void) Web.config_block_count = 0; } else { +#if defined(USE_ZIGBEE) && defined(USE_ZIGBEE_EZSP) + if ((SONOFF_ZB_BRIDGE == my_module_type) && (upload.buf[0] == 0xEB)) { // Check if this is a Zigbee bridge FW file + Update.end(); // End esp8266 update session + Web.upload_file_type = UPL_EFR32; + + Web.upload_error = ZigbeeUploadInit(); // 15 + if (Web.upload_error != 0) { return; } + } else +#endif // USE_ZIGBEE and USE_ZIGBEE_EZSP #ifdef USE_RF_FLASH if ((SONOFF_BRIDGE == my_module_type) && (upload.buf[0] == ':')) { // Check if this is a RF bridge FW file Update.end(); // End esp8266 update session @@ -2750,6 +2765,15 @@ void HandleUploadLoop(void) Web.config_block_count++; } } +#if defined(USE_ZIGBEE) && defined(USE_ZIGBEE_EZSP) + else if (UPL_EFR32 == Web.upload_file_type) { + // Write buffers to MCU EFR32 + if (!ZigbeeUploadWriteBuffer(upload.buf, upload.currentSize)) { + Web.upload_error = 9; // File too large + return; + } + } +#endif // USE_ZIGBEE and USE_ZIGBEE_EZSP #ifdef USE_RF_FLASH else if (UPL_EFM8BB1 == Web.upload_file_type) { if (efm8bb1_update != nullptr) { // We have carry over data since last write, i. e. a start but not an end @@ -2844,6 +2868,13 @@ void HandleUploadLoop(void) return; } } +#if defined(USE_ZIGBEE) && defined(USE_ZIGBEE_EZSP) + else if (UPL_EFR32 == Web.upload_file_type) { + // Zigbee FW upload to ESP8266 flash is done + ZigbeeUploadDone(); // Signal upload done and ready for delayed upload to MCU EFR32 + Web.upload_file_type = UPL_TASMOTA; + } +#endif #ifdef USE_RF_FLASH else if (UPL_EFM8BB1 == Web.upload_file_type) { // RF FW flash done diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino new file mode 100644 index 000000000..1e1ff935f --- /dev/null +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -0,0 +1,121 @@ +/* + xdrv_23_zigbee_9_serial.ino - zigbee: serial communication with MCU + + Copyright (C) 2020 Theo Arends and Stephan Hadinger + + 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. + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_ZIGBEE + +#ifdef USE_ZIGBEE_EZSP +/*********************************************************************************************\ + * MCU EFR32 firmware upload using xmodem + * + * Step 1 - Upload MCU firmware in ESP8266 flash free space (current size is about 200k) + * Step 2 - Upload MCU firmware from ESP8266 flash to MCU EFR32 using XMODEM protocol + * Step 3 - Restart +\*********************************************************************************************/ + +const uint8_t PIN_ZIGBEE_BOOTLOADER = 5; + +struct ZBUPLOAD { + uint32_t ota_size = 0; + uint32_t sector_cursor = 0; + uint32_t sector_counter = 0; + bool ota_ready = false; +} ZbUpload; + +bool ZigbeeUploadOtaReady(void) { + return ZbUpload.ota_ready; +} + +uint32_t ZigbeeUploadFlashStart(void) { + return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; +} + +uint8_t ZigbeeUploadInit(void) { + if (!PinUsed(GPIO_ZIGBEE_RST) && (ZigbeeSerial == nullptr)) { return 1; } // Wrong pin configuration - No file selected + + ZbUpload.sector_counter = ZigbeeUploadFlashStart(); + ZbUpload.sector_cursor = 0; + ZbUpload.ota_size = 0; + ZbUpload.ota_ready = false; + return 0; +} + +bool ZigbeeUploadWriteBuffer(uint8_t *buf, size_t size) { + // Read complete file into ESP8266 flash + // Current files are about 200k + if (0 == ZbUpload.sector_cursor) { // Starting a new sector write so we need to erase it first + ESP.flashEraseSector(ZbUpload.sector_counter); + } + ZbUpload.sector_cursor++; + ESP.flashWrite((ZbUpload.sector_counter * SPI_FLASH_SEC_SIZE) + ((ZbUpload.sector_cursor-1) * 2048), (uint32_t*)buf, size); + ZbUpload.ota_size += size; + if (2 == ZbUpload.sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase + ZbUpload.sector_cursor = 0; + ZbUpload.sector_counter++; + if (ZbUpload.sector_counter > (SPIFFS_END + 12)) { + return false; // File too large - Not enough free space + } + } + return true; +} + +void ZigbeeUploadDone(void) { + ZbUpload.ota_ready = true; +} + +void ZigbeeUploadSetBootloader(uint8_t state) { + pinMode(PIN_ZIGBEE_BOOTLOADER, OUTPUT); + digitalWrite(PIN_ZIGBEE_BOOTLOADER, state); // Toggle Gecko bootloader + digitalWrite(Pin(GPIO_ZIGBEE_RST), 0); + delay(100); // Need to experiment to find a value as low as possible + digitalWrite(Pin(GPIO_ZIGBEE_RST), 1); // Reboot MCU EFR32 +} + +void ZigbeeUploadXmodem(void) { + if (!ZbUpload.ota_ready) { return; } + + // Copy uploaded OTA file from ESP8266 flash to MCU EFR32 using xmodem + uint32_t sector_counter = ZigbeeUploadFlashStart() * SPI_FLASH_SEC_SIZE; + + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Upload start 0x%08X, size 0x%08X"), sector_counter, ZbUpload.ota_size); + + // TODO - implement XMODEM upload + +// ZigbeeUploadSetBootloader(1); // Reboot MCU EFR32 which returns below text + // Gecko Bootloader v1.A.3 + // 1. upload gbl + // 2. run + // 3. ebl info + // BL > + // Use ZigbeeInputLoop to flush received data + + // Send option 1 to prepare for xmodem upload +// ZigbeeSerial->write('1'); +// ZigbeeSerial->write(0x0d); +// ZigbeeSerial->write(0x0a); + + // Start xmodem upload + + ZbUpload.ota_ready = false; +// ZigbeeUploadSetBootloader(0); // Disable bootloader and reset MCU + restart_flag = 2; // Restart to disable bootloader and use new firmware +} + +#endif // USE_ZIGBEE_EZSP + +#endif // USE_ZIGBEE From 267a49b140fc9e05b593de1d19df7da220afc9c4 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sun, 26 Jul 2020 13:54:24 +0200 Subject: [PATCH 50/91] Fix compilation error for Zigbee ZNP --- tasmota/xdrv_23_zigbee_8_parsers.ino | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 7f1c98e0a..05b0b4b37 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -822,20 +822,12 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { return -1; } +#ifdef USE_ZIGBEE_EZSP // // Handle Parent Annonce Rsp incoming message // // rsp: true = ZDO_Parent_annce_rsp, false = ZDO_Parent_annce -int32_t Z_ParentAnnceRsp(int32_t res, const class SBuffer &buf, bool rsp) { -#ifdef USE_ZIGBEE_ZNP -// uint16_t shortaddr = buf.get16(2); -// uint8_t status = buf.get8(4); -// uint8_t bind_total = buf.get8(5); -// uint8_t bind_start = buf.get8(6); -// uint8_t bind_len = buf.get8(7); -// const size_t prefix_len = 8; -#endif // USE_ZIGBEE_ZNP -#ifdef USE_ZIGBEE_EZSP +int32_t EZ_ParentAnnceRsp(int32_t res, const class SBuffer &buf, bool rsp) { size_t prefix_len; uint8_t status; uint8_t num_children; @@ -849,7 +841,6 @@ int32_t Z_ParentAnnceRsp(int32_t res, const class SBuffer &buf, bool rsp) { num_children = buf.get8(0); prefix_len = 1; } -#endif // USE_ZIGBEE_EZSP const char * friendlyName = zigbee_devices.getFriendlyName(shortaddr); @@ -887,6 +878,7 @@ int32_t Z_ParentAnnceRsp(int32_t res, const class SBuffer &buf, bool rsp) { return -1; } +#endif // USE_ZIGBEE_EZSP /*********************************************************************************************\ * Send specific ZNP messages @@ -1155,9 +1147,9 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { case ZDO_Mgmt_Bind_rsp: return Z_MgmtBindRsp(res, zdo_buf); case ZDO_Parent_annce: - return Z_ParentAnnceRsp(res, zdo_buf, false); + return EZ_ParentAnnceRsp(res, zdo_buf, false); case ZDO_Parent_annce_rsp: - return Z_ParentAnnceRsp(res, zdo_buf, true); + return EZ_ParentAnnceRsp(res, zdo_buf, true); default: // TODO move later to LOG_LEVEL_DEBUG AddLog_P2(LOG_LEVEL_INFO, PSTR("ZIG: Internal ZDO message 0x%04X sent from 0x%04X %s"), clusterid, srcaddr, wasbroadcast ? PSTR("(broadcast)") : ""); From 30d0f050c7a2f5984542d2cd90e4454a40ae663a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 26 Jul 2020 18:55:31 +0200 Subject: [PATCH 51/91] POC Zigbee EFR32 xmodem upload POC Zigbee EFR32 xmodem upload (#8583) --- tasmota/xdrv_01_webserver.ino | 3 - tasmota/xdrv_23_zigbee_9a_upload.ino | 335 +++++++++++++++++++++++---- tasmota/xdrv_23_zigbee_A_impl.ino | 9 +- 3 files changed, 298 insertions(+), 49 deletions(-) diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 384b38c6f..1f878ae6b 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -2644,9 +2644,6 @@ void HandleUploadDone(void) WSContentSpaceButton(BUTTON_MAIN); WSContentStop(); -#if defined(USE_ZIGBEE) && defined(USE_ZIGBEE_EZSP) - ZigbeeUploadXmodem(); -#endif // USE_ZIGBEE and USE_ZIGBEE_EZSP #ifdef USE_TASMOTA_CLIENT if (TasmotaClient_GetFlagFlashing()) { TasmotaClient_Flash(); diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino index 1e1ff935f..c2bb2dc11 100644 --- a/tasmota/xdrv_23_zigbee_9a_upload.ino +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -28,30 +28,315 @@ * Step 3 - Restart \*********************************************************************************************/ +#define XM_SOH 0x01 +#define XM_STX 0x02 +#define XM_EOT 0x04 +#define XM_ENQ 0x05 +#define XM_ACK 0x06 +#define XM_LF 0x0a +#define XM_CR 0x0d +#define XM_DLE 0x10 +#define XM_XON 0x11 +#define XM_XOFF 0x13 +#define XM_NAK 0x15 +#define XM_CAN 0x18 +#define XM_EOF 0x1a + +enum ZbUploadSteps { ZBU_IDLE, ZBU_INIT, ZBU_PROMPT, ZBU_SYNC, ZBU_UPLOAD, ZBU_DONE, ZBU_COMPLETE }; + const uint8_t PIN_ZIGBEE_BOOTLOADER = 5; struct ZBUPLOAD { uint32_t ota_size = 0; uint32_t sector_cursor = 0; uint32_t sector_counter = 0; - bool ota_ready = false; + uint32_t byte_counter = 0; + char *buffer; + uint8_t ota_step = ZBU_IDLE; } ZbUpload; -bool ZigbeeUploadOtaReady(void) { - return ZbUpload.ota_ready; -} +/*********************************************************************************************\ + * Flash +\*********************************************************************************************/ uint32_t ZigbeeUploadFlashStart(void) { return (ESP.getSketchSize() / SPI_FLASH_SEC_SIZE) + 2; } +uint32_t ZigbeeUploadAvailable(void) { + int available = ZbUpload.ota_size - ZbUpload.byte_counter; + if (available < 0) { available = 0; } + return available; +} + +char ZigbeeUploadFlashRead(void) { + if (0 == ZbUpload.byte_counter) { + if (!(ZbUpload.buffer = (char *)malloc(SPI_FLASH_SEC_SIZE))) { + return (-1); // Not enough (memory) space + } + ZbUpload.sector_counter = ZigbeeUploadFlashStart(); + } + + uint32_t index = ZbUpload.byte_counter % SPI_FLASH_SEC_SIZE; + if (0 == index) { + ESP.flashRead(ZbUpload.sector_counter * SPI_FLASH_SEC_SIZE, (uint32_t*)ZbUpload.buffer, SPI_FLASH_SEC_SIZE); + ZbUpload.sector_counter++; + } + + char data = ZbUpload.buffer[index]; + ZbUpload.byte_counter++; + + if (ZbUpload.byte_counter > ZbUpload.ota_size) { + data = XM_EOF; +// if (ZbUpload.buffer) { free(ZbUpload.buffer); } // Don't in case of retries + } + return data; +} + +/*********************************************************************************************\ + * XModem protocol +\*********************************************************************************************/ + +// Number of seconds until giving up hope of receiving sync packets from host. +const uint8_t XMODEM_SYNC_TIMEOUT = 30; +// Number of times we try to send a packet to the host until we give up sending.. +const uint8_t XMODEM_MAX_RETRY = 30; +// Packet size +const uint8_t XMODEM_PACKET_SIZE = 128; + +struct XMODEM { + uint32_t timeout = 0; + uint32_t filepos = 0; + int crcBuf = 0; + uint8_t packetNo = 1; + uint8_t checksumBuf = 0; + bool oldChecksum; +} XModem; + +// Send out a byte of payload data, includes checksumming +void XModemOutputByte(uint8_t out_char) { + XModem.checksumBuf += out_char; + + XModem.crcBuf = XModem.crcBuf ^ (int) out_char << 8; + for (uint32_t i = 0; i < 8; i++) { + if (XModem.crcBuf & 0x8000) { + XModem.crcBuf = XModem.crcBuf << 1 ^ 0x1021; + } else { + XModem.crcBuf = XModem.crcBuf << 1; + } + } + + ZigbeeSerial->write(out_char); +} + +// Wait for the remote to acknowledge or cancel. +// Returns the received char if no timeout occured or a CAN was received. In this cases, it returns -1. +char XModemWaitACK(void) +{ + char in_char; + do { + uint8_t i = 0; + while (!ZigbeeSerial->available()) { + delayMicroseconds(100); + i++; + if (i > 200) { return -1; } + } + in_char = ZigbeeSerial->read(); + if (in_char == XM_CAN) { return XM_CAN; } + } while ((in_char != XM_NAK) && (in_char != XM_ACK) && (in_char != 'C')); + return in_char; +} + +bool XModemSendPacket(uint32_t packet_no) { + XModem.filepos = ZbUpload.byte_counter; + + // Sending a packet will be retried + uint32_t retries = 0; + char in_char; + do { + // Seek to start of current data block, + // will advance through the file as block will be acked.. + ZbUpload.byte_counter = XModem.filepos; + + // Reset checksum stuff + XModem.checksumBuf = 0x00; + XModem.crcBuf = 0x00; + + // Try to send packet, so header first + ZigbeeSerial->write(XM_SOH); + ZigbeeSerial->write(packet_no); + ZigbeeSerial->write(~packet_no); + for (uint32_t i = 0; i < XMODEM_PACKET_SIZE; i++) { + in_char = ZigbeeUploadFlashRead(); + XModemOutputByte(in_char); + } + // Send out checksum, either CRC-16 CCITT or classical inverse of sum of bytes. + // Depending on how the received introduced himself + if (XModem.oldChecksum) { + ZigbeeSerial->write((char)XModem.checksumBuf); + } else { + ZigbeeSerial->write((char)(XModem.crcBuf >> 8)); + ZigbeeSerial->write((char)(XModem.crcBuf & 0xFF)); + } + in_char = XModemWaitACK(); + if (XM_CAN == in_char) { return false; } + retries++; + if (retries > XMODEM_MAX_RETRY) { return false; } + } while (in_char != XM_ACK); + return true; +} + +bool XModemSendEOT(void) { + // Send EOT and wait for ACK + uint32_t retries = 0; + char in_char; + do { + ZigbeeSerial->write(XM_EOT); + in_char = XModemWaitACK(); + retries++; + // When timed out, leave immediately + if (retries == XMODEM_SYNC_TIMEOUT) { return false; } + } while (in_char != XM_ACK); + return true; +} + +/*********************************************************************************************\ + * Step 2 - Upload MCU firmware from ESP8266 flash to MCU EFR32 using XMODEM protocol + * + * https://www.silabs.com/documents/public/application-notes/an760-using-legacy-standalone-bootloader.pdf +\*********************************************************************************************/ + +void ZigbeeUploadSetBootloader(uint8_t state) { + pinMode(PIN_ZIGBEE_BOOTLOADER, OUTPUT); + digitalWrite(PIN_ZIGBEE_BOOTLOADER, state); // Toggle Gecko bootloader + digitalWrite(Pin(GPIO_ZIGBEE_RST), 0); + delay(100); // Need to experiment to find a value as low as possible + digitalWrite(Pin(GPIO_ZIGBEE_RST), 1); // Reboot MCU EFR32 +} + +void ZigbeeUploadBootloaderDone(void) { + ZbUpload.ota_step = ZBU_COMPLETE; // Never return to zero without a restart to get a sane Zigbee environment + ZigbeeUploadSetBootloader(0); // Disable bootloader and reset MCU - should happen or restart + restart_flag = 2; // Restart to disable bootloader and use new firmware +} + +bool ZigbeeUploadBootloaderPrompt(void) { + // Scripts that interact with the bootloader should use only the “BL >” prompt to determine + // when the bootloader is ready for input. While current menu options should remain functionally + // unchanged, the menu title and options text is liable to change, and new options might be added. + while (ZigbeeSerial->available()) { + yield(); + char bootloader_byte = ZigbeeSerial->read(); + switch (ZbUpload.byte_counter) { + case 0: + if ('B' == bootloader_byte) { ZbUpload.byte_counter++; } break; + case 1: + if ('L' == bootloader_byte) { ZbUpload.byte_counter++; } break; + case 2: + if (' ' == bootloader_byte) { ZbUpload.byte_counter++; } break; + case 3: + if ('>' == bootloader_byte) { ZbUpload.byte_counter++; } + } + } + return (4 == ZbUpload.byte_counter); +} + +bool ZigbeeUploadXmodem(void) { + if (!ZbUpload.ota_step) { return false; } + + switch (ZbUpload.ota_step) { + case ZBU_INIT: { // Init ESF32 bootloader + ZbUpload.ota_step = ZBU_PROMPT; + + uint32_t sector_counter = ZigbeeUploadFlashStart() * SPI_FLASH_SEC_SIZE; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Upload 0x%08X, size 0x%08X"), sector_counter, ZbUpload.ota_size); + + ZigbeeUploadSetBootloader(1); // Reboot MCU EFR32 which returns below text + break; + } + case ZBU_PROMPT: { // Wait for prompt and select option upload ebl + if (!ZigbeeSerial->available()) { + // The target device’s bootloader sends output over its serial port after it receives a carriage return + // from the source device + ZigbeeSerial->write(XM_CR); + delay(1); + } else { + // After the bootloader receives a carriage return from the target device, it displays a menu + // Gecko Bootloader v1.A.3 + // 1. upload gbl + // 2. run + // 3. ebl info + // BL > + if (ZigbeeUploadBootloaderPrompt()) { + ZigbeeSerial->flush(); + ZigbeeSerial->write('1'); // upload ebl + XModem.timeout = millis() + (XMODEM_SYNC_TIMEOUT * 1000); + ZbUpload.ota_step = ZBU_SYNC; + } + } + break; + } + case ZBU_SYNC: { // Handle file upload using XModem - sync + if (millis() > XModem.timeout) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Initial sync failed")); + ZigbeeUploadBootloaderDone(); + return true; + } + // Wait for either C or NACK as a sync packet. + // Determines protocol details, checksum algorithm. + if (ZigbeeSerial->available()) { + char xmodem_sync = ZigbeeSerial->read(); + if ((xmodem_sync == 'C') || (xmodem_sync == XM_NAK)) { + // Determine which checksum algorithm to use + XModem.oldChecksum = (xmodem_sync == XM_NAK); + XModem.packetNo = 1; + ZbUpload.byte_counter = 0; + ZbUpload.ota_step = ZBU_UPLOAD; + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Sync received")); + } + } + break; + } + case ZBU_UPLOAD: { // Handle file upload using XModem - upload + if (ZigbeeUploadAvailable()) { + if (!XModemSendPacket(XModem.packetNo)) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Packet send failed")); + ZigbeeUploadBootloaderDone(); + return true; + } + XModem.packetNo++; + } else { + if (!XModemSendEOT()) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: EOT failed")); + ZigbeeUploadBootloaderDone(); + return true; + } + ZbUpload.ota_step = ZBU_DONE; + } + break; + } + case ZBU_DONE: { // Clean up and restart to disable bootloader and use new firmware + ZigbeeUploadBootloaderDone(); + } + } + return true; +} + +/*********************************************************************************************\ + * Step 1 - Upload MCU firmware in ESP8266 flash free space (current size is about 200k) +\*********************************************************************************************/ + +bool ZigbeeUploadOtaReady(void) { + return (ZBU_INIT == ZbUpload.ota_step); +} + uint8_t ZigbeeUploadInit(void) { if (!PinUsed(GPIO_ZIGBEE_RST) && (ZigbeeSerial == nullptr)) { return 1; } // Wrong pin configuration - No file selected ZbUpload.sector_counter = ZigbeeUploadFlashStart(); ZbUpload.sector_cursor = 0; ZbUpload.ota_size = 0; - ZbUpload.ota_ready = false; + ZbUpload.ota_step = ZBU_IDLE; return 0; } @@ -75,45 +360,7 @@ bool ZigbeeUploadWriteBuffer(uint8_t *buf, size_t size) { } void ZigbeeUploadDone(void) { - ZbUpload.ota_ready = true; -} - -void ZigbeeUploadSetBootloader(uint8_t state) { - pinMode(PIN_ZIGBEE_BOOTLOADER, OUTPUT); - digitalWrite(PIN_ZIGBEE_BOOTLOADER, state); // Toggle Gecko bootloader - digitalWrite(Pin(GPIO_ZIGBEE_RST), 0); - delay(100); // Need to experiment to find a value as low as possible - digitalWrite(Pin(GPIO_ZIGBEE_RST), 1); // Reboot MCU EFR32 -} - -void ZigbeeUploadXmodem(void) { - if (!ZbUpload.ota_ready) { return; } - - // Copy uploaded OTA file from ESP8266 flash to MCU EFR32 using xmodem - uint32_t sector_counter = ZigbeeUploadFlashStart() * SPI_FLASH_SEC_SIZE; - - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Upload start 0x%08X, size 0x%08X"), sector_counter, ZbUpload.ota_size); - - // TODO - implement XMODEM upload - -// ZigbeeUploadSetBootloader(1); // Reboot MCU EFR32 which returns below text - // Gecko Bootloader v1.A.3 - // 1. upload gbl - // 2. run - // 3. ebl info - // BL > - // Use ZigbeeInputLoop to flush received data - - // Send option 1 to prepare for xmodem upload -// ZigbeeSerial->write('1'); -// ZigbeeSerial->write(0x0d); -// ZigbeeSerial->write(0x0a); - - // Start xmodem upload - - ZbUpload.ota_ready = false; -// ZigbeeUploadSetBootloader(0); // Disable bootloader and reset MCU - restart_flag = 2; // Restart to disable bootloader and use new firmware + ZbUpload.ota_step = ZBU_INIT; } #endif // USE_ZIGBEE_EZSP diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 6b23590cc..a631432fc 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -1240,13 +1240,18 @@ bool Xdrv23(uint8_t function) } break; case FUNC_LOOP: +#ifdef USE_ZIGBEE_EZSP + if (ZigbeeUploadXmodem()) { + return false; + } +#endif if (ZigbeeSerial) { ZigbeeInputLoop(); ZigbeeOutputLoop(); // send any outstanding data } - if (zigbee.state_machine) { + if (zigbee.state_machine) { ZigbeeStateMachine_Run(); - } + } break; #ifdef USE_WEBSERVER case FUNC_WEB_SENSOR: From 0875b6bab026c6ba992281b2765e4a9651fac169 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 27 Jul 2020 09:03:53 +0200 Subject: [PATCH 52/91] Tasmota Stage Core 2.7.3.2 includes Arduino backport #7488 backport #7487 backport #7486 backport #7464 backport #7434 backport #7433 Security fix and malloc fix --- platformio_override_sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 48298c782..500281096 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -88,7 +88,7 @@ extra_scripts = ${scripts_defaults.extra_scripts} [tasmota_stage] ; *** Esp8266 core for Arduino version Tasmota stage platform = espressif8266@2.5.1 -platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.1/esp8266-2.7.3.1.zip +platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.2/esp8266-2.7.3.2.zip build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} From a6fe5f859b546c9f0dd2517d555c4fdcb1988558 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 27 Jul 2020 11:01:20 +0200 Subject: [PATCH 53/91] POC2 Zigbee EFR32 xmodem upload POC2 Zigbee EFR32 xmodem upload (#8583) - Swap reset states - Speed up XMODEM upload by changing current loop sleep - Add more debug messages --- tasmota/xdrv_23_zigbee_9a_upload.ino | 40 +++++++++++++++++++--------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino index c2bb2dc11..e5296152e 100644 --- a/tasmota/xdrv_23_zigbee_9a_upload.ino +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -106,6 +106,7 @@ const uint8_t XMODEM_PACKET_SIZE = 128; struct XMODEM { uint32_t timeout = 0; + uint32_t delay = 0; uint32_t filepos = 0; int crcBuf = 0; uint8_t packetNo = 1; @@ -216,8 +217,11 @@ void ZigbeeUploadSetBootloader(uint8_t state) { void ZigbeeUploadBootloaderDone(void) { ZbUpload.ota_step = ZBU_COMPLETE; // Never return to zero without a restart to get a sane Zigbee environment - ZigbeeUploadSetBootloader(0); // Disable bootloader and reset MCU - should happen or restart - restart_flag = 2; // Restart to disable bootloader and use new firmware + ZigbeeUploadSetBootloader(1); // Disable bootloader and reset MCU - should happen or restart + if (1 == ssleep) { + ssleep = Settings.sleep; // Restore loop sleep + } + restart_flag = 2; // Restart to disable bootloader and use new firmware } bool ZigbeeUploadBootloaderPrompt(void) { @@ -246,20 +250,27 @@ bool ZigbeeUploadXmodem(void) { switch (ZbUpload.ota_step) { case ZBU_INIT: { // Init ESF32 bootloader + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Init bootloader")); + ZigbeeUploadSetBootloader(0); // Reboot MCU EFR32 which returns below text + XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EBL prompt + XModem.delay = millis() + 500; ZbUpload.ota_step = ZBU_PROMPT; - - uint32_t sector_counter = ZigbeeUploadFlashStart() * SPI_FLASH_SEC_SIZE; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ZIG: Upload 0x%08X, size 0x%08X"), sector_counter, ZbUpload.ota_size); - - ZigbeeUploadSetBootloader(1); // Reboot MCU EFR32 which returns below text break; } case ZBU_PROMPT: { // Wait for prompt and select option upload ebl - if (!ZigbeeSerial->available()) { + if (millis() > XModem.timeout) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Bootloader timeout")); + ZigbeeUploadBootloaderDone(); + return true; + } + else if (!ZigbeeSerial->available()) { // The target device’s bootloader sends output over its serial port after it receives a carriage return // from the source device - ZigbeeSerial->write(XM_CR); - delay(1); + if (millis() > XModem.delay) { + ZigbeeSerial->write('a'); + ZigbeeSerial->write(XM_CR); + XModem.delay = millis() + 500; + } } else { // After the bootloader receives a carriage return from the target device, it displays a menu // Gecko Bootloader v1.A.3 @@ -268,8 +279,12 @@ bool ZigbeeUploadXmodem(void) { // 3. ebl info // BL > if (ZigbeeUploadBootloaderPrompt()) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Init sync")); ZigbeeSerial->flush(); ZigbeeSerial->write('1'); // upload ebl + if (ssleep > 0) { + ssleep = 1; // Speed up loop used for xmodem upload + } XModem.timeout = millis() + (XMODEM_SYNC_TIMEOUT * 1000); ZbUpload.ota_step = ZBU_SYNC; } @@ -278,7 +293,7 @@ bool ZigbeeUploadXmodem(void) { } case ZBU_SYNC: { // Handle file upload using XModem - sync if (millis() > XModem.timeout) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Initial sync failed")); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Sync timeout")); ZigbeeUploadBootloaderDone(); return true; } @@ -292,7 +307,7 @@ bool ZigbeeUploadXmodem(void) { XModem.packetNo = 1; ZbUpload.byte_counter = 0; ZbUpload.ota_step = ZBU_UPLOAD; - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Sync received")); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Init packet send")); } } break; @@ -311,6 +326,7 @@ bool ZigbeeUploadXmodem(void) { ZigbeeUploadBootloaderDone(); return true; } + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Complete")); ZbUpload.ota_step = ZBU_DONE; } break; From e8beeba651dbc6c49b5e3a4dcaf87c892a21ccd4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 27 Jul 2020 11:05:44 +0200 Subject: [PATCH 54/91] Remove obsolete debug info --- tasmota/xdrv_23_zigbee_9a_upload.ino | 1 - 1 file changed, 1 deletion(-) diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino index e5296152e..560445279 100644 --- a/tasmota/xdrv_23_zigbee_9a_upload.ino +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -267,7 +267,6 @@ bool ZigbeeUploadXmodem(void) { // The target device’s bootloader sends output over its serial port after it receives a carriage return // from the source device if (millis() > XModem.delay) { - ZigbeeSerial->write('a'); ZigbeeSerial->write(XM_CR); XModem.delay = millis() + 500; } From 2012eaccf4c28aaacb85a62175334fae2b72ab6f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 27 Jul 2020 15:43:24 +0200 Subject: [PATCH 55/91] POC3 Zigbee EFR32 xmodem upload POC3 Zigbee EFR32 xmodem upload (#8583) - Extend ACK timeout after EOT --- tasmota/xdrv_23_zigbee_9a_upload.ino | 143 ++++++++++++++++----------- 1 file changed, 87 insertions(+), 56 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino index 560445279..5280ea472 100644 --- a/tasmota/xdrv_23_zigbee_9a_upload.ino +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -1,5 +1,5 @@ /* - xdrv_23_zigbee_9_serial.ino - zigbee: serial communication with MCU + xdrv_23_zigbee_9a_upload.ino - zigbee: serial xmodem upload to MCU Copyright (C) 2020 Theo Arends and Stephan Hadinger @@ -40,9 +40,9 @@ #define XM_XOFF 0x13 #define XM_NAK 0x15 #define XM_CAN 0x18 -#define XM_EOF 0x1a +#define XM_SUB 0x1a -enum ZbUploadSteps { ZBU_IDLE, ZBU_INIT, ZBU_PROMPT, ZBU_SYNC, ZBU_UPLOAD, ZBU_DONE, ZBU_COMPLETE }; +enum ZbUploadSteps { ZBU_IDLE, ZBU_INIT, ZBU_PROMPT, ZBU_SYNC, ZBU_UPLOAD, ZBU_EOT, ZBU_COMPLETE, ZBU_DONE, ZBU_FINISH }; const uint8_t PIN_ZIGBEE_BOOTLOADER = 5; @@ -87,7 +87,9 @@ char ZigbeeUploadFlashRead(void) { ZbUpload.byte_counter++; if (ZbUpload.byte_counter > ZbUpload.ota_size) { - data = XM_EOF; + // When the source device reaches the last XModem data block, it should be padded to 128 bytes + // of data using SUB (ASCII 0x1A) characters. + data = XM_SUB; // if (ZbUpload.buffer) { free(ZbUpload.buffer); } // Don't in case of retries } return data; @@ -143,7 +145,7 @@ char XModemWaitACK(void) if (i > 200) { return -1; } } in_char = ZigbeeSerial->read(); - if (in_char == XM_CAN) { return XM_CAN; } + if (XM_CAN == in_char) { return XM_CAN; } } while ((in_char != XM_NAK) && (in_char != XM_ACK) && (in_char != 'C')); return in_char; } @@ -187,20 +189,6 @@ bool XModemSendPacket(uint32_t packet_no) { return true; } -bool XModemSendEOT(void) { - // Send EOT and wait for ACK - uint32_t retries = 0; - char in_char; - do { - ZigbeeSerial->write(XM_EOT); - in_char = XModemWaitACK(); - retries++; - // When timed out, leave immediately - if (retries == XMODEM_SYNC_TIMEOUT) { return false; } - } while (in_char != XM_ACK); - return true; -} - /*********************************************************************************************\ * Step 2 - Upload MCU firmware from ESP8266 flash to MCU EFR32 using XMODEM protocol * @@ -215,15 +203,6 @@ void ZigbeeUploadSetBootloader(uint8_t state) { digitalWrite(Pin(GPIO_ZIGBEE_RST), 1); // Reboot MCU EFR32 } -void ZigbeeUploadBootloaderDone(void) { - ZbUpload.ota_step = ZBU_COMPLETE; // Never return to zero without a restart to get a sane Zigbee environment - ZigbeeUploadSetBootloader(1); // Disable bootloader and reset MCU - should happen or restart - if (1 == ssleep) { - ssleep = Settings.sleep; // Restore loop sleep - } - restart_flag = 2; // Restart to disable bootloader and use new firmware -} - bool ZigbeeUploadBootloaderPrompt(void) { // Scripts that interact with the bootloader should use only the “BL >” prompt to determine // when the bootloader is ready for input. While current menu options should remain functionally @@ -246,26 +225,28 @@ bool ZigbeeUploadBootloaderPrompt(void) { } bool ZigbeeUploadXmodem(void) { - if (!ZbUpload.ota_step) { return false; } - switch (ZbUpload.ota_step) { - case ZBU_INIT: { // Init ESF32 bootloader + case ZBU_IDLE: { // *** Upload disabled + return false; + } + case ZBU_INIT: { // *** Init ESF32 bootloader AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Init bootloader")); - ZigbeeUploadSetBootloader(0); // Reboot MCU EFR32 which returns below text + ZigbeeUploadSetBootloader(0); // Reboot MCU EFR32 which returns below text XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EBL prompt XModem.delay = millis() + 500; + ZbUpload.byte_counter = 0; ZbUpload.ota_step = ZBU_PROMPT; break; } - case ZBU_PROMPT: { // Wait for prompt and select option upload ebl + case ZBU_PROMPT: { // *** Wait for prompt and select option upload ebl if (millis() > XModem.timeout) { AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Bootloader timeout")); - ZigbeeUploadBootloaderDone(); + ZbUpload.ota_step = ZBU_DONE; return true; } else if (!ZigbeeSerial->available()) { - // The target device’s bootloader sends output over its serial port after it receives a carriage return - // from the source device + // The target device’s bootloader sends output over its serial port after it receives a + // carriage return from the source device if (millis() > XModem.delay) { ZigbeeSerial->write(XM_CR); XModem.delay = millis() + 500; @@ -280,9 +261,9 @@ bool ZigbeeUploadXmodem(void) { if (ZigbeeUploadBootloaderPrompt()) { AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Init sync")); ZigbeeSerial->flush(); - ZigbeeSerial->write('1'); // upload ebl + ZigbeeSerial->write('1'); // upload ebl if (ssleep > 0) { - ssleep = 1; // Speed up loop used for xmodem upload + ssleep = 1; // Speed up loop used for xmodem upload } XModem.timeout = millis() + (XMODEM_SYNC_TIMEOUT * 1000); ZbUpload.ota_step = ZBU_SYNC; @@ -290,17 +271,16 @@ bool ZigbeeUploadXmodem(void) { } break; } - case ZBU_SYNC: { // Handle file upload using XModem - sync + case ZBU_SYNC: { // *** Handle file upload using XModem - sync if (millis() > XModem.timeout) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Sync timeout")); - ZigbeeUploadBootloaderDone(); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: SYNC timeout")); + ZbUpload.ota_step = ZBU_DONE; return true; } - // Wait for either C or NACK as a sync packet. - // Determines protocol details, checksum algorithm. + // Wait for either C or NACK as a sync packet. Determines protocol details, checksum algorithm. if (ZigbeeSerial->available()) { char xmodem_sync = ZigbeeSerial->read(); - if ((xmodem_sync == 'C') || (xmodem_sync == XM_NAK)) { + if (('C' == xmodem_sync) || (XM_NAK == xmodem_sync)) { // Determine which checksum algorithm to use XModem.oldChecksum = (xmodem_sync == XM_NAK); XModem.packetNo = 1; @@ -311,27 +291,78 @@ bool ZigbeeUploadXmodem(void) { } break; } - case ZBU_UPLOAD: { // Handle file upload using XModem - upload + case ZBU_UPLOAD: { // *** Handle file upload using XModem - upload if (ZigbeeUploadAvailable()) { if (!XModemSendPacket(XModem.packetNo)) { AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Packet send failed")); - ZigbeeUploadBootloaderDone(); + ZbUpload.ota_step = ZBU_DONE; return true; } XModem.packetNo++; } else { - if (!XModemSendEOT()) { - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: EOT failed")); - ZigbeeUploadBootloaderDone(); - return true; - } - AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Complete")); - ZbUpload.ota_step = ZBU_DONE; + // Once the last block is ACKed by the target, the transfer should be finalized by an + // EOT (ASCII 0x04) packet from the source. Once this packet is confirmed via XModem ACK + // from the target, the device will reboot, causing the new firmware to be launched. + ZigbeeSerial->write(XM_EOT); + XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EOT ACK + ZbUpload.ota_step = ZBU_EOT; } break; } - case ZBU_DONE: { // Clean up and restart to disable bootloader and use new firmware - ZigbeeUploadBootloaderDone(); + case ZBU_EOT: { // *** Send EOT and wait for ACK + // The ACK for the last XModem data packet may take much longer (1-3 seconds) than prior + // data packets to be received. This is due to the CRC32 checksum being performed across + // the received EBL file data prior to sending the ACK. The source device must ensure that + // its XModem state machine waits a sufficient amount of time to allow this checksum process + // to occur without timing out on the response just before the EOT is sent. + if (millis() > XModem.timeout) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: EOT ACK timeout")); + ZbUpload.ota_step = ZBU_DONE; + return true; + } + if (ZigbeeSerial->available()) { + char xmodem_ack = XModemWaitACK(); + if (XM_ACK == xmodem_ack) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: " D_SUCCESSFUL)); + XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EBL prompt + ZbUpload.byte_counter = 0; +// ZbUpload.ota_step = ZBU_COMPLETE; + ZbUpload.ota_step = ZBU_DONE; // Skip prompt for now + } + } + break; + } +/* + case ZBU_COMPLETE: { // *** Wait for Serial upload complete EBL prompt + if (millis() > XModem.timeout) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Bootloader timeout")); + ZbUpload.ota_step = ZBU_DONE; + return true; + } else { + // After an image successfully uploads, the XModem transaction completes and the bootloader displays + // ‘Serial upload complete’ before redisplaying the menu + // Serial upload complete + // BL > + if (ZigbeeUploadBootloaderPrompt()) { + ZbUpload.ota_step = ZBU_DONE; + } + } + break; + } +*/ + case ZBU_DONE: { // *** Clean up and restart to disable bootloader and use new firmware + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: " D_RESTARTING)); + ZigbeeUploadSetBootloader(1); // Disable bootloader and reset MCU - should happen at restart + if (1 == ssleep) { + ssleep = Settings.sleep; // Restore loop sleep + } + restart_flag = 2; // Restart to disable bootloader and use new firmware + ZbUpload.ota_step = ZBU_FINISH; // Never return to zero without a restart to get a sane Zigbee environment + break; + } + case ZBU_FINISH: { // *** Wait for restart making sure not to start Zigbee serial again + // Wait for restart + break; } } return true; @@ -367,7 +398,7 @@ bool ZigbeeUploadWriteBuffer(uint8_t *buf, size_t size) { if (2 == ZbUpload.sector_cursor) { // The web upload sends 2048 bytes at a time so keep track of the cursor position to reset it for the next flash sector erase ZbUpload.sector_cursor = 0; ZbUpload.sector_counter++; - if (ZbUpload.sector_counter > (SPIFFS_END + 12)) { + if (ZbUpload.sector_counter > (SPIFFS_END -2)) { return false; // File too large - Not enough free space } } From 0abe6c6a2bc48d42e5b29f56e8596109ab5a1286 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 27 Jul 2020 18:31:14 +0200 Subject: [PATCH 56/91] Zigbee EFR32 xmodem upload Zigbee EFR32 xmodem upload (#8583) - Now checks for upload complete - Add optional define ZIGBEE_BOOTLOADER_SOFTWARE_RESET_FIRST for software reset first --- tasmota/xdrv_23_zigbee_9a_upload.ino | 83 ++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/tasmota/xdrv_23_zigbee_9a_upload.ino b/tasmota/xdrv_23_zigbee_9a_upload.ino index 5280ea472..7c2feed26 100644 --- a/tasmota/xdrv_23_zigbee_9a_upload.ino +++ b/tasmota/xdrv_23_zigbee_9a_upload.ino @@ -28,21 +28,19 @@ * Step 3 - Restart \*********************************************************************************************/ +//#define ZIGBEE_BOOTLOADER_SOFTWARE_RESET_FIRST + #define XM_SOH 0x01 -#define XM_STX 0x02 #define XM_EOT 0x04 -#define XM_ENQ 0x05 #define XM_ACK 0x06 -#define XM_LF 0x0a #define XM_CR 0x0d -#define XM_DLE 0x10 -#define XM_XON 0x11 -#define XM_XOFF 0x13 #define XM_NAK 0x15 #define XM_CAN 0x18 #define XM_SUB 0x1a -enum ZbUploadSteps { ZBU_IDLE, ZBU_INIT, ZBU_PROMPT, ZBU_SYNC, ZBU_UPLOAD, ZBU_EOT, ZBU_COMPLETE, ZBU_DONE, ZBU_FINISH }; +enum ZbUploadSteps { ZBU_IDLE, ZBU_INIT, + ZBU_SOFTWARE_RESET, ZBU_SOFTWARE_SEND, ZBU_HARDWARE_RESET, ZBU_PROMPT, + ZBU_SYNC, ZBU_UPLOAD, ZBU_EOT, ZBU_COMPLETE, ZBU_DONE, ZBU_FINISH }; const uint8_t PIN_ZIGBEE_BOOTLOADER = 5; @@ -53,6 +51,7 @@ struct ZBUPLOAD { uint32_t byte_counter = 0; char *buffer; uint8_t ota_step = ZBU_IDLE; + uint8_t bootloader = 0; } ZbUpload; /*********************************************************************************************\ @@ -195,6 +194,14 @@ bool XModemSendPacket(uint32_t packet_no) { * https://www.silabs.com/documents/public/application-notes/an760-using-legacy-standalone-bootloader.pdf \*********************************************************************************************/ +void ZigbeeUploadSetSoftwareBootloader() { + // https://github.com/arendst/Tasmota/issues/8583#issuecomment-663967883 + SBuffer buf(4); + buf.add16(EZSP_launchStandaloneBootloader); + buf.add8(0x01); + ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len()); // Send software bootloader init +} + void ZigbeeUploadSetBootloader(uint8_t state) { pinMode(PIN_ZIGBEE_BOOTLOADER, OUTPUT); digitalWrite(PIN_ZIGBEE_BOOTLOADER, state); // Toggle Gecko bootloader @@ -229,6 +236,57 @@ bool ZigbeeUploadXmodem(void) { case ZBU_IDLE: { // *** Upload disabled return false; } +#ifdef ZIGBEE_BOOTLOADER_SOFTWARE_RESET_FIRST + case ZBU_INIT: { // *** Init ESF32 bootloader + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Init bootloader")); + ZbUpload.ota_step = ZBU_SOFTWARE_RESET; + return false; // Keep Zigbee serial active + } + case ZBU_SOFTWARE_RESET: { + SBuffer buf(4); + buf.add16(EZSP_launchStandaloneBootloader); + buf.add8(0x01); + ZigbeeEZSPSendCmd(buf.getBuffer(), buf.len()); // Send software bootloader init + XModem.timeout = millis() + (10 * 1000); // Allow 10 seconds to send Zigbee command + ZbUpload.ota_step = ZBU_SOFTWARE_SEND; + return false; // Keep Zigbee serial active + } + case ZBU_SOFTWARE_SEND: { + if (millis() > XModem.timeout) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Bootloader software reset send timeout")); + ZbUpload.ota_step = ZBU_HARDWARE_RESET; + return true; + } + if (EZSP_Serial.to_send == EZSP_Serial.to_end) { + ZbUpload.bootloader = ZBU_SOFTWARE_RESET; + XModem.timeout = millis() + (10 * 1000); // Allow 10 seconds to receive EBL prompt + XModem.delay = millis() + 500; + ZbUpload.byte_counter = 0; + ZbUpload.ota_step = ZBU_PROMPT; + } + break; + } + case ZBU_HARDWARE_RESET: { + ZbUpload.bootloader = ZBU_HARDWARE_RESET; + ZigbeeUploadSetBootloader(0); // Reboot MCU EFR32 which returns below text + XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EBL prompt + XModem.delay = millis() + 500; + ZbUpload.byte_counter = 0; + ZbUpload.ota_step = ZBU_PROMPT; + break; + } + case ZBU_PROMPT: { // *** Wait for prompt and select option upload ebl + if (millis() > XModem.timeout) { + if (ZBU_SOFTWARE_RESET == ZbUpload.bootloader) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Bootloader software reset timeout")); + ZbUpload.ota_step = ZBU_HARDWARE_RESET; + } else { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Bootloader hardware reset timeout")); + ZbUpload.ota_step = ZBU_DONE; + } + return true; + } +#else // No ZIGBEE_BOOTLOADER_SOFTWARE_RESET_FIRST case ZBU_INIT: { // *** Init ESF32 bootloader AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Init bootloader")); ZigbeeUploadSetBootloader(0); // Reboot MCU EFR32 which returns below text @@ -244,6 +302,7 @@ bool ZigbeeUploadXmodem(void) { ZbUpload.ota_step = ZBU_DONE; return true; } +#endif // ZIGBEE_BOOTLOADER_SOFTWARE_RESET_FIRST else if (!ZigbeeSerial->available()) { // The target device’s bootloader sends output over its serial port after it receives a // carriage return from the source device @@ -326,13 +385,12 @@ bool ZigbeeUploadXmodem(void) { AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: " D_SUCCESSFUL)); XModem.timeout = millis() + (30 * 1000); // Allow 30 seconds to receive EBL prompt ZbUpload.byte_counter = 0; -// ZbUpload.ota_step = ZBU_COMPLETE; - ZbUpload.ota_step = ZBU_DONE; // Skip prompt for now + ZbUpload.ota_step = ZBU_COMPLETE; +// ZbUpload.ota_step = ZBU_DONE; // Skip prompt for now } } break; } -/* case ZBU_COMPLETE: { // *** Wait for Serial upload complete EBL prompt if (millis() > XModem.timeout) { AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: Bootloader timeout")); @@ -342,6 +400,10 @@ bool ZigbeeUploadXmodem(void) { // After an image successfully uploads, the XModem transaction completes and the bootloader displays // ‘Serial upload complete’ before redisplaying the menu // Serial upload complete + // Gecko Bootloader v1.A.3 + // 1. upload gbl + // 2. run + // 3. ebl info // BL > if (ZigbeeUploadBootloaderPrompt()) { ZbUpload.ota_step = ZBU_DONE; @@ -349,7 +411,6 @@ bool ZigbeeUploadXmodem(void) { } break; } -*/ case ZBU_DONE: { // *** Clean up and restart to disable bootloader and use new firmware AddLog_P2(LOG_LEVEL_DEBUG, PSTR("XMD: " D_RESTARTING)); ZigbeeUploadSetBootloader(1); // Disable bootloader and reset MCU - should happen at restart From b1f98f57112b47caa021120ed2edba96bfabe77d Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 28 Jul 2020 09:25:48 +0200 Subject: [PATCH 57/91] Add tasmota-zbbridge support --- RELEASENOTES.md | 1 + platformio.ini | 1 + platformio_override_sample.ini | 1 + 3 files changed, 3 insertions(+) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index e2170880c..468f761c6 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -44,6 +44,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - **tasmota-sensors.bin** = The Sensors version adds more useful sensors. - **tasmota-ir** = The InfraRed Receiver and transmitter version allowing all available protocols provided by library IRremoteESP8266 but without most other features. - **tasmota-display.bin** = The Display version without Energy Monitoring but adds display support. +- **tasmota-zbbridge.bin** = The dedicated Sonoff Zigbee Bridge version. - **tasmota-minimal.bin** = The Minimal version allows intermediate OTA uploads to support larger versions and does NOT change any persistent parameter. This version **should NOT be used for initial installation**. [List](MODULES.md) of embedded modules. diff --git a/platformio.ini b/platformio.ini index c68991444..e7284356b 100644 --- a/platformio.ini +++ b/platformio.ini @@ -26,6 +26,7 @@ default_envs = ; tasmota-knx ; tasmota-sensors ; tasmota-display +; tasmota-zbbridge ; tasmota-ir ; tasmota-BG ; tasmota-BR diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 500281096..5ea714612 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -23,6 +23,7 @@ default_envs = ; tasmota-knx ; tasmota-sensors ; tasmota-display +; tasmota-zbbridge ; tasmota-ir ; tasmota32 ; tasmota32-webcam From beb4b6b3fe71e381b4d6cf7ed656ca04637de9f2 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 28 Jul 2020 09:29:26 +0200 Subject: [PATCH 58/91] Update MODULES.md --- MODULES.md | 153 +++++++++++++++++++++++++++-------------------------- 1 file changed, 77 insertions(+), 76 deletions(-) diff --git a/MODULES.md b/MODULES.md index e16dec401..1ca8ab473 100644 --- a/MODULES.md +++ b/MODULES.md @@ -2,81 +2,82 @@ The following hardware modules are supported. -Module | Description -------------------|----------------------- -01 Sonoff Basic | Sonoff Basic Wifi Smart Switch -02 Sonoff RF | Sonoff RF Wifi Smart Switch with RF (434MHz) receiver -03 Sonoff SV | Sonoff SV Safe Voltage Wifi Smart Switch -04 Sonoff TH | Sonoff TH10/TH16 Wifi Smart Switch with Sensor connection -05 Sonoff Dual | Sonoff Dual Wifi Smart Switch -06 Sonoff Pow | Sonoff Pow Wifi Smart Switch with Energy Monitoring -07 Sonoff 4CH | Sonoff 4CH 4-gang Wifi Smart Switch -08 Sonoff S2X | Sonoff S20/S26 Wifi Smart Socket -09 Slampher | Sonoff Slampher Wifi Smart Light Bulb Socket with RF (434MHz) receiver -10 Sonoff Touch | Sonoff Touch Wifi Light Switch -11 Sonoff LED | Sonoff Led Wifi Led Pack (Retired) -12 1 Channel | 1 Channel Inching/Self Locking Wifi Switch 5V/12V -13 4 Channel | 4 Channel Inching/Self Locking Wifi Switch (Retired) -14 Motor C/AC | Motor Clockwise/Antoclockwise Wifi Switch (Retired) -15 ElectroDragon | Electrodragon Wifi IoT Board -16 EXS Relay(s) | Electronic Experience Store 1 or 2-gang Wifi Module -17 WiOn | WiOn Wifi Smart Socket -18 Generic | Any ESP8266/ESP8285 device like WeMos and NodeMCU -19 Sonoff Dev | Sonoff Dev Wifi Development Board -20 H801 | H801 Wifi 5 Channel LED Controller -21 Sonoff SC | Sonoff SC Wifi Environmental Monitor -22 Sonoff BN-SZ | Sonoff BN-SZ01 Wifi Ceiling Led (Retired) -23 Sonoff 4CH Pro | Sonoff 4CH Pro 4-gang Wifi Smart Switch -24 Huafan SS | HuaFan Wifi Smart Socket -25 Sonoff Bridge | Sonoff RF (434MHz) transceive to Wifi Bridge -26 Sonoff B1 | Sonoff B1 Wifi RGBWW Led Bulb -27 AiLight | Ai-Thinker RGBW Led Bulb -28 Sonoff T1 1CH | Sonoff T1 1-gang Wifi Light Switch -29 Sonoff T1 2CH | Sonoff T1 2-gang Wifi Light Switch -30 Sonoff T1 3CH | Sonoff T1 3-gang Wifi Light Switch -31 Supla Espablo | 2-gang Wifi Module -32 Witty Cloud | Witty Cloud ESP8266 Wifi Development Board -33 Yunshan Relay | ESP8266 Wifi Network Relay Module -34 MagicHome | MagicHome, Flux-light and some Arilux LC10 RGB(W) Led Controller -35 Luani HVIO | Luani ESP8266 Wifi I/O Module -36 KMC 70011 | KMC Wifi Smart Socket with Energy Monitoring -37 Arilux LC01 | Arilux AL-LC01 RGB Led Controller -38 Arilux LC11 | Arilux AL-LC11 RGBWW Led Controller -39 Sonoff Dual R2 | Sonoff Dual R2 Wifi Smart Switch -40 Arilux LC06 | Arilux AL-LC06 RGB(WW) Led Controller -41 Sonoff S31 | Sonoff S31 Wifi Smart Socket with Energy Monitoring -42 Zengge WF017 | Zengge WF017 Wifi RGB(W) Led Controller -43 Sonoff Pow R2 | Sonoff Pow R2 Wifi Smart Switch with Energy Monitoring -44 Sonoff iFan02 | Sonoff iFan02 Wifi Smart Ceiling Fan with Light -45 BlitzWolf SHP | BlitzWolf BW-SHP2, BW-SHP6, HomeCube SP1, Gosund SP111, Teckin SP22 Wifi Smart Switch with Energy Monitoring -46 Shelly 1 | Shelly 1 Open Source Wifi Relay Module -47 Shelly 2 | Shelly 2 Wifi 2-gang Relay Module with Energy Monitoring -48 Xiaomi Philips | Xiaomi Philips Wifi WW Led Bulb -49 Neo Coolcam | Neo Coolcam Wifi Smart Socket -50 ESP Switch | ESP Switch 4-gang Wifi Switch with Leds -51 OBI Socket | OBI Wifi Smart Socket -52 Teckin | Teckin SP22 Wifi Smart Switch with Energy Monitoring -53 AplicWDP303075 | Aplic WDP 303075 CSL Wifi Smart Switch with Energy Monitoring -54 TuyaMCU | Devices with an MCU using Tuya communication protocol for control -55 Gosund SP1 v23 | Gosund SP1 v2.3 Wifi Smart Switch with Energy Monitoring -56 ARMTR Dimmer | ARMtronix Wifi dimmer for Incandescent Lights and Led -57 SK03 Outdoor | SK03 Outdoor Wifi Smart Switch with Energy Monitoring -58 PS-16-DZ | PS-16-DZ Wifi dimmer for Incandescent Lights and Led -59 Teckin US | Teckin SP20 and ZooZee SA102 Wifi Smart Switch with Energy Monitoring -60 Manzoku strip | Manzoku Wifi Smart Power Strip with four Relays -61 OBI Socket 2 | OBI 2 Wifi Smart Socket -62 YTF IR Bridge | YTF Universal IR Bridge -63 Digoo DG-SP202 | Digoo DG-SP202 Dual Wifi Smart Switch with Energy Monitoring -64 KA10 | Smanergy KA10 Wifi Smart Wall Switch with Energy Monitoring -65 Luminea ZX2820 | Luminea ZX2820 Wifi Smart Switch with Energy Monitoring -66 Mi Desk Lamp | Mi Desk Lamp with rotary switch and Wifi -67 SP10 | Tuya SP10 Wifi Smart Switch with Energy Monitoring -68 WAGA CHCZ02MB | WAGA life CHCZ02MB Wifi Smart Switch with Energy Monitoring -69 SYF05 | Sunyesmart SYF05 RGBWW Wifi Led Bulb -70 Sonoff L1 | Sonoff L1 light strip -71 Sonoff iFan03 | Sonoff iFan03 Wifi Smart Ceiling Fan with Light -72 EXS Dimmer | EXS Wifi Dimmer v4 -73 PWM Dimmer | Martin Jerry/acenx/Tessan/NTONPOWER SD0x PWM Dimmer Switches -74 Sonoff D1 | Sonoff D1 Wifi and RF Dimmer +Module | Description +-------------------|----------------------- +01 Sonoff Basic | Sonoff Basic Wifi Smart Switch +02 Sonoff RF | Sonoff RF Wifi Smart Switch with RF (434MHz) receiver +03 Sonoff SV | Sonoff SV Safe Voltage Wifi Smart Switch +04 Sonoff TH | Sonoff TH10/TH16 Wifi Smart Switch with Sensor connection +05 Sonoff Dual | Sonoff Dual Wifi Smart Switch +06 Sonoff Pow | Sonoff Pow Wifi Smart Switch with Energy Monitoring +07 Sonoff 4CH | Sonoff 4CH 4-gang Wifi Smart Switch +08 Sonoff S2X | Sonoff S20/S26 Wifi Smart Socket +09 Slampher | Sonoff Slampher Wifi Smart Light Bulb Socket with RF (434MHz) receiver +10 Sonoff Touch | Sonoff Touch Wifi Light Switch +11 Sonoff LED | Sonoff Led Wifi Led Pack (Retired) +12 1 Channel | 1 Channel Inching/Self Locking Wifi Switch 5V/12V +13 4 Channel | 4 Channel Inching/Self Locking Wifi Switch (Retired) +14 Motor C/AC | Motor Clockwise/Antoclockwise Wifi Switch (Retired) +15 ElectroDragon | Electrodragon Wifi IoT Board +16 EXS Relay(s) | Electronic Experience Store 1 or 2-gang Wifi Module +17 WiOn | WiOn Wifi Smart Socket +18 Generic | Any ESP8266/ESP8285 device like WeMos and NodeMCU +19 Sonoff Dev | Sonoff Dev Wifi Development Board +20 H801 | H801 Wifi 5 Channel LED Controller +21 Sonoff SC | Sonoff SC Wifi Environmental Monitor +22 Sonoff BN-SZ | Sonoff BN-SZ01 Wifi Ceiling Led (Retired) +23 Sonoff 4CH Pro | Sonoff 4CH Pro 4-gang Wifi Smart Switch +24 Huafan SS | HuaFan Wifi Smart Socket +25 Sonoff Bridge | Sonoff RF (434MHz) transceive to Wifi Bridge +26 Sonoff B1 | Sonoff B1 Wifi RGBWW Led Bulb +27 AiLight | Ai-Thinker RGBW Led Bulb +28 Sonoff T1 1CH | Sonoff T1 1-gang Wifi Light Switch +29 Sonoff T1 2CH | Sonoff T1 2-gang Wifi Light Switch +30 Sonoff T1 3CH | Sonoff T1 3-gang Wifi Light Switch +31 Supla Espablo | 2-gang Wifi Module +32 Witty Cloud | Witty Cloud ESP8266 Wifi Development Board +33 Yunshan Relay | ESP8266 Wifi Network Relay Module +34 MagicHome | MagicHome, Flux-light and some Arilux LC10 RGB(W) Led Controller +35 Luani HVIO | Luani ESP8266 Wifi I/O Module +36 KMC 70011 | KMC Wifi Smart Socket with Energy Monitoring +37 Arilux LC01 | Arilux AL-LC01 RGB Led Controller +38 Arilux LC11 | Arilux AL-LC11 RGBWW Led Controller +39 Sonoff Dual R2 | Sonoff Dual R2 Wifi Smart Switch +40 Arilux LC06 | Arilux AL-LC06 RGB(WW) Led Controller +41 Sonoff S31 | Sonoff S31 Wifi Smart Socket with Energy Monitoring +42 Zengge WF017 | Zengge WF017 Wifi RGB(W) Led Controller +43 Sonoff Pow R2 | Sonoff Pow R2 Wifi Smart Switch with Energy Monitoring +44 Sonoff iFan02 | Sonoff iFan02 Wifi Smart Ceiling Fan with Light +45 BlitzWolf SHP | BlitzWolf BW-SHP2, BW-SHP6, HomeCube SP1, Gosund SP111, Teckin SP22 Wifi Smart Switch with Energy Monitoring +46 Shelly 1 | Shelly 1 Open Source Wifi Relay Module +47 Shelly 2 | Shelly 2 Wifi 2-gang Relay Module with Energy Monitoring +48 Xiaomi Philips | Xiaomi Philips Wifi WW Led Bulb +49 Neo Coolcam | Neo Coolcam Wifi Smart Socket +50 ESP Switch | ESP Switch 4-gang Wifi Switch with Leds +51 OBI Socket | OBI Wifi Smart Socket +52 Teckin | Teckin SP22 Wifi Smart Switch with Energy Monitoring +53 AplicWDP303075 | Aplic WDP 303075 CSL Wifi Smart Switch with Energy Monitoring +54 TuyaMCU | Devices with an MCU using Tuya communication protocol for control +55 Gosund SP1 v23 | Gosund SP1 v2.3 Wifi Smart Switch with Energy Monitoring +56 ARMTR Dimmer | ARMtronix Wifi dimmer for Incandescent Lights and Led +57 SK03 Outdoor | SK03 Outdoor Wifi Smart Switch with Energy Monitoring +58 PS-16-DZ | PS-16-DZ Wifi dimmer for Incandescent Lights and Led +59 Teckin US | Teckin SP20 and ZooZee SA102 Wifi Smart Switch with Energy Monitoring +60 Manzoku strip | Manzoku Wifi Smart Power Strip with four Relays +61 OBI Socket 2 | OBI 2 Wifi Smart Socket +62 YTF IR Bridge | YTF Universal IR Bridge +63 Digoo DG-SP202 | Digoo DG-SP202 Dual Wifi Smart Switch with Energy Monitoring +64 KA10 | Smanergy KA10 Wifi Smart Wall Switch with Energy Monitoring +65 Luminea ZX2820 | Luminea ZX2820 Wifi Smart Switch with Energy Monitoring +66 Mi Desk Lamp | Mi Desk Lamp with rotary switch and Wifi +67 SP10 | Tuya SP10 Wifi Smart Switch with Energy Monitoring +68 WAGA CHCZ02MB | WAGA life CHCZ02MB Wifi Smart Switch with Energy Monitoring +69 SYF05 | Sunyesmart SYF05 RGBWW Wifi Led Bulb +70 Sonoff L1 | Sonoff L1 light strip +71 Sonoff iFan03 | Sonoff iFan03 Wifi Smart Ceiling Fan with Light +72 EXS Dimmer | EXS Wifi Dimmer v4 +73 PWM Dimmer | Martin Jerry/acenx/Tessan/NTONPOWER SD0x PWM Dimmer Switches +74 Sonoff D1 | Sonoff D1 Wifi and RF Dimmer +75 Sonoff ZbBridge | Sonoff Zigbee bridge Over 1000 additional devices are supported using [templates](TEMPLATES.md). From 59be0ce72967162257c3e90323c59d00d8cf2d54 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 29 Jul 2020 09:55:15 +0200 Subject: [PATCH 59/91] Prep release 8.4.0 --- TEMPLATES.md | 64 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/TEMPLATES.md b/TEMPLATES.md index d39a55b92..ff354aab7 100644 --- a/TEMPLATES.md +++ b/TEMPLATES.md @@ -42,9 +42,11 @@ BrilliantSmart 20696 9W 900lm {"NAME":"Brilliant20696","GPIO":[0,0,0,0,0,0,0,0, BrilliantSmart 20697 9W 900lm {"NAME":"Brilliant20696","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Bulbrite Solana A19 Edison Filament {"NAME":"BulbBrite01","GPIO":[0,0,0,0,0,0,0,0,37,0,38,0,0],"FLAG":0,"BASE":18} Bulbrite Solana G25 5.5W 600lm Filament {"NAME":"BulbBrite01","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} +Bulbrite Solana ST18 16W 140lm Filament {"NAME":"BulbBrite02","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Calex G125 7,5W 1055lm {"NAME":"Calex G125 E27","GPIO":[0,0,0,0,0,140,0,0,38,0,37,142,141],"FLAG":0,"BASE":18} Calex G125 7.5W 1055lm Globe {"NAME":"Calex G125 E27","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Connect Smart GU5.3 5W {"NAME":"Connect CSH-GU53WW5W","GPIO":[0,0,0,0,37,38,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} +Connect SmartHome 10W 900lm {"NAME":"Connect CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} Deltaco SH-LE14W 470lm {"NAME":"SH-LE14W","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Deltaco SH-LE27W 810lm {"NAME":"SH-LE27W","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} DORESshop A60 720lm Filament {"NAME":"DORESshop-A60","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} @@ -58,8 +60,10 @@ Hama 806lm {"NAME":"Hama 00176550","GPIO":[0,0,0,0,0,37,0,0,0,38,0 Hykker SL-0392 650lm {"NAME":"Hykker 7W","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Iotton 9W 700lm {"NAME":"Iotton Light","GPIO":[0,0,0,0,37,38,0,0,0,0,0,0,0],"FLAG":0,"BASE":18} Kogan 10W Cool & Warm White 1050lm {"NAME":"Kogan 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,47,0,0,0],"FLAG":0,"BASE":48} -Kogan 4.5W 330lm CCT {"NAME":"Kogan White/Wa","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} +Kogan 4.5W 330lm 110C {"NAME":"Kogan White/Wa","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Kogan 5W {"NAME":"Kogan Co/Wa","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} +Laser 10W 1000lm {"NAME":"Laser 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} +Laser 10W 1000lm {"NAME":"Laster 10W CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":48} LE lampUX 380lm Candle {"NAME":"LE Bulb","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} LE LampUX 4.5W 410lm {"NAME":"LE LampUX","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":48} ledscom.de 4.5W 430lm {"NAME":"GX53","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":0} @@ -70,7 +74,7 @@ Lumiman A19 7.5W 800lm {"NAME":"Lumiman LM520","GPIO":[0,0,0,0,0,37,0,0,38,0,0 Luminea ZX-2831 {"NAME":"Luminea CCT","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} LVWIT A60 6.5W 806lm Filament {"NAME":"LVWIT-E27-WiFi-6.5","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Merkury MI-BW905-999W 700lm {"NAME":"MI-BW905-999W","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} -Mimoodz 1050lm {"NAME":"ID Components","GPIO":[0,0,0,0,21,22,0,0,23,24,25,26,27],"FLAG":0,"BASE":18} +Mimoodz A21 10.5W 1050lm {"NAME":"Mimoodz","GPIO":[0,0,0,0,21,22,0,0,23,24,25,26,27],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbCCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbCCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbCCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} @@ -82,11 +86,12 @@ Nedis A60 800lm {"NAME":"WIFILW10WTE27","GPIO":[0,0,0,0,0,37,0,0,38,0,0 Nedis C10 350lm {"NAME":"WIFILW10WTE14","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Nedis G125 5.5W 350lm Twisted Filament {"NAME":"WIFILF10GDG125","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Nedis PAR16 330lm {"NAME":"Nedis WIFILW30","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} -Nedis PAR16 4.5W 330lm {"NAME":"WIFILW30","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} +Nedis PAR16 4.5W 330lm 110C {"NAME":"WIFILW30","GPIO":[0,0,0,0,0,37,0,0,38,0,0,0,0],"FLAG":0,"BASE":18} Philips Zhirui Candle 250lm {"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,38,0,0,37,0],"FLAG":0,"BASE":48} Phillips Zhirui 450lm {"NAME":"Xiaomi Philips","GPIO":[0,0,0,0,0,0,0,0,38,0,0,37,0],"FLAG":0,"BASE":48} SmartDGM L-WT9W1 9W 800lm {"NAME":"L-WT9W1","GPIO":[0,0,0,0,0,37,0,0,9,38,0,0,0],"FLAG":0,"BASE":18} Swisstone SH 330 806lm {"NAME":"SwisstoneSH330","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} +V-Tac PAR16 4.5W 300lm 110C {"NAME":"V-TAC VT-5174","GPIO":[0,0,0,0,0,0,0,0,38,0,37,0,0],"FLAG":0,"BASE":18} Vestaiot BR30 800lm {"NAME":"Vesta BR30 CCT","GPIO":[0,0,0,0,0,37,0,0,0,38,0,0,0],"FLAG":0,"BASE":18} Wipro Garnet NS9100 810lm {"NAME":"WiproSmartBulb","GPIO":[0,0,0,0,38,0,0,0,37,0,0,0,0],"FLAG":0,"BASE":18} Wyze WLPA19 A19 800lm {"NAME":"Wyze Bulb","GPIO":[0,0,0,0,0,0,0,0,0,37,38,0,0],"FLAG":0,"BASE":48} @@ -108,6 +113,7 @@ Teekar SYS-CS 01 {"NAME":"Teekar-Tag","GPIO":[56,0,157,18,22,11,0,0,0,21 Teepao {"NAME":"Taopao","GPIO":[255,255,255,18,22,19,0,0,255,21,255,255,17],"FLAG":1,"BASE":18} WF-CS01 {"NAME":"Tuya Shutter","GPIO":[157,0,54,10,22,19,0,0,17,21,53,23,52],"FLAG":0,"BASE":18} WF-CS02 {"NAME":"WF-CS02 Tuya","GPIO":[157,0,53,11,23,18,0,0,17,21,54,22,52],"FLAG":0,"BASE":18} +Zemismart {"NAME":"Zemismart","GPIO":[157,0,0,11,54,10,0,0,9,21,23,22,0],"FLAG":0,"BASE":18} ``` ## DIY @@ -195,7 +201,7 @@ EX-Store 2 Kanal RS232 V4 {"NAME":"EXS Dimmer","GPIO":[0,148,0,149,0,0,0,0,0,18 Feit Electric DIM/WIFI {"NAME":"Generic","GPIO":[255,107,255,108,255,255,0,0,255,0,255,0,255],"FLAG":0,"BASE":54} Gosund SW2 {"NAME":"Gosund Dimmer","GPIO":[255,148,255,149,17,0,255,255,56,158,37,255,255],"FLAG":0,"BASE":18} iSwitch Touch Switch {"NAME":"iSwitchOZ Dimmer","GPIO":[0,0,0,0,0,0,0,0,0,0,54,0,0],"FLAG":0,"BASE":54} -Martin Jerry MJ-SD01 {"NAME":"MJ-SD02","GPIO":[19,18,0,59,158,58,0,0,57,37,56,122,29],"FLAG":0,"BASE":73} +Martin Jerry SD01 {"NAME":"MJ-SD02","GPIO":[19,18,0,59,158,58,0,0,57,37,56,122,29],"FLAG":0,"BASE":73} Moes DS01-1 {"NAME":"MOES DS01","GPIO":[255,255,255,255,255,255,0,0,255,108,255,107,255],"FLAG":0,"BASE":54} Moes MS-105-1 v2 {"NAME":"MS-105","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} PS-16-DZ {"NAME":"PS-16-DZ","GPIO":[255,148,255,149,255,255,0,0,255,52,255,255,255],"FLAG":0,"BASE":58} @@ -204,6 +210,7 @@ RJWF-02A {"NAME":"RJWF-02A","GPIO":[17,107,0,108,0,0,0,0,0,0,52, Sonoff D1 {"NAME":"Sonoff D1","GPIO":[255,148,0,149,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":74} Teekar UIW001-1 {"NAME":"Teekar UIW001-","GPIO":[0,149,37,148,6,5,0,0,9,0,0,0,0],"FLAG":0,"BASE":18} Tessan MJ-SD02 {"NAME":"MJ-SD02","GPIO":[19,18,0,59,158,58,0,0,57,37,56,122,29],"FLAG":0,"BASE":73} +TopGreener TGWF500D {"NAME":"TopGreener-Dimmer","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} TreatLife DS01 {"NAME":"DS02S Dimmer","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} TreatLife DS02S {"NAME":"DS02S Dimmer","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} WF-DS01 {"NAME":"Dimmer WF-DS01","GPIO":[255,255,255,255,255,255,0,0,255,255,54,255,255],"FLAG":0,"BASE":54} @@ -223,6 +230,7 @@ Sichler Haushaltsgeraete Column {"NAME":"Sichler Fan","GPIO":[0,107,0,108,0,0,0 Sonoff IFan02 {"NAME":"Sonoff iFan02","GPIO":[17,255,0,255,23,22,18,19,21,56,20,24,0],"FLAG":0,"BASE":44} Sonoff IFan03 {"NAME":"SonoffiFan03","GPIO":[17,148,0,149,0,0,29,161,23,56,22,24,0],"FLAG":0,"BASE":71} Technical Pro FXA16 {"NAME":"FXA16 Fan","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Zemismart Bladeless {"NAME":"Bladeless Fan","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} ``` ## IR Bridge @@ -264,10 +272,12 @@ Arilux AL-LC11 {"NAME":"Arilux LC11","GPIO":[17,0,59,0,38,37,0,0,41,40 Arilux SL-LC 03 {"NAME":"Arilux LC03","GPIO":[0,0,0,0,51,38,0,0,37,39,0,40,0],"FLAG":0,"BASE":34} Arilux SL-LC 09 {"NAME":"Arilux LC09","GPIO":[0,0,0,0,106,37,0,0,39,0,38,0,0],"FLAG":0,"BASE":18} CIN-03 96W RGB {"NAME":"CIN03-03 Strip","GPIO":[0,0,0,0,38,0,0,0,37,0,39,0,0],"FLAG":0,"BASE":18} +DD001-MINI(G)-IR-V03 {"NAME":"WIFI-RGB","GPIO":[17,0,0,0,0,0,0,0,38,39,37,0,0],"FLAG":0,"BASE":40} DD001-MINI(G)-IR-V08 {"NAME":"WIFI-RGB","GPIO":[0,0,0,0,37,0,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Electrodragon ESP LED Strip Board, Mosfet Drive {"NAME":"LEDBoard RGBW","GPIO":[0,0,0,0,0,0,0,0,39,38,40,37,52],"FLAG":0,"BASE":18} H801 {"NAME":"H801","GPIO":[0,52,0,0,41,57,0,0,39,38,40,37,0],"FLAG":0,"BASE":20} Jinvoo SM-WA104 RGB {"NAME":"Jinvoo LED Controller","GPIO":[0,0,0,0,29,39,0,0,37,17,38,0,30],"FLAG":0,"BASE":18} +Konesky 12V RGB {"NAME":"RGBwifi","GPIO":[0,0,0,0,37,0,0,0,38,56,39,0,0],"FLAG":0,"BASE":18} LEDEnet {"NAME":"LEDEnet","GPIO":[0,255,56,255,147,41,0,0,38,39,37,40,0],"FLAG":0,"BASE":34} Luminea ZX-2844 {"NAME":"Luminea ZX-284","GPIO":[40,0,0,0,0,39,0,0,38,17,37,0,0],"FLAG":0,"BASE":18} Luminea ZX-2844-675 {"NAME":"ZX-2844-675","GPIO":[17,0,0,0,38,40,0,0,37,0,39,0,0],"FLAG":0,"BASE":18} @@ -298,6 +308,7 @@ Cocoon Smart {"NAME":"Cocoon Smart","GPIO":[17,0,0,0,37,0,0,0,38,0,3 Deltaco 3m RGBCCT {"NAME":"Deltaco Led Strip","GPIO":[0,0,0,0,37,17,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} electriQ 3m RGBCCT {"NAME":"ElectricQ wifiRGBWLEDSTR","GPIO":[0,0,0,0,37,41,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} Elfeland 10m RGB {"NAME":"Elfeland RGB","GPIO":[0,0,0,0,0,38,0,0,39,51,0,37,0],"FLAG":0,"BASE":18} +Geeni Prisma Plus {"NAME":"Geeni Prisma Plus Strip","GPIO":[17,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Gosund 2.8m RGB {"NAME":"Gosund LED Strip","GPIO":[17,0,0,0,0,0,0,0,37,39,38,0,0],"FLAG":3,"BASE":18} HitLights L1012V-MC1 {"NAME":"HitLights RBG","GPIO":[17,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} HomeMate 10m RGB {"NAME":"Homemate Strip","GPIO":[0,0,0,0,0,37,0,0,39,17,38,0,0],"FLAG":0,"BASE":18} @@ -371,6 +382,7 @@ Mirabella Genio I002742 {"NAME":"GenioDLightCCT","GPIO":[0,0,0,0,0,0,0,0,38,0,3 Mirabella Genio I002798 Warm White Filament Festoon {"NAME":"GenioFestoon","GPIO":[0,0,0,0,0,0,0,0,0,0,37,0,0],"FLAG":0,"BASE":18} Moes 7W RGBCCT Downlight {"NAME":"Moes Downlight","GPIO":[0,0,0,0,40,41,0,0,37,38,39,0,0],"FLAG":0,"BASE":18} Novostella UT88835 20W Floodlight {"NAME":"Novo 20W Flood","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Reafoo A27 9W 810lm {"NAME":"ReaFooE27","GPIO":[0,0,0,0,41,40,0,0,37,0,39,38,0],"FLAG":0,"BASE":18} SMRTLite LED Panel {"NAME":"SMRTLite","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} Sonoff BN-SZ01 {"NAME":"Sonoff BN-SZ","GPIO":[0,0,0,0,0,0,0,0,37,56,0,0,0],"FLAG":0,"BASE":22} Spotlight 9cm RGB+W 7W {"NAME":"Spotlight RGBW","GPIO":[0,0,0,0,0,0,0,0,0,143,0,144,0],"FLAG":0,"BASE":27} @@ -425,6 +437,7 @@ HA109US {"NAME":"HA109US","GPIO":[17,0,0,0,52,53,0,0,21,0,22,0, iClever IC-BS06 {"NAME":"iClever Switch","GPIO":[0,0,0,0,157,56,0,0,21,17,22,0,0],"FLAG":0,"BASE":18} King-Link C128 {"NAME":"King-Link C128","GPIO":[0,0,58,0,22,56,0,0,23,157,17,21,57],"FLAG":0,"BASE":18} Kogan Energy Meter IP44 {"NAME":"Kogan Smart Sw IP44","GPIO":[17,0,0,0,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} +Koolertron {"NAME":"C168 Outdoor","GPIO":[0,17,0,56,134,132,0,0,21,131,22,23,0],"FLAG":0,"BASE":18} LEPOWER {"NAME":"LEPOWER Outdoo","GPIO":[255,255,255,255,56,57,0,0,21,17,22,255,255],"FLAG":0,"BASE":18} Luminea NX-4458 {"NAME":"Luminea NX4458","GPIO":[17,0,0,0,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":65} Maxcio EOP03-EU {"NAME":"Maxcio EOP03-EU","GPIO":[0,0,0,0,22,57,0,0,21,52,17,0,58],"FLAG":0,"BASE":18} @@ -479,6 +492,7 @@ Anoopsyche AWP08L {"NAME":"AWP08L-Annopsy","GPIO":[0,0,0,0,17,56,0,0,21,0 Anoopsyche SP-G01 {"NAME":"SP-G01","GPIO":[0,145,0,146,0,0,0,0,17,56,21,0,0],"FLAG":0,"BASE":41} Anoopsyche SP15 {"NAME":"Anoop SP15","GPIO":[0,0,0,0,56,21,0,0,0,17,0,0,0],"FLAG":0,"BASE":18} Anoopsyche UK1D {"NAME":"UK1D","GPIO":[0,17,0,0,133,132,0,0,130,52,21,0,0],"FLAG":0,"BASE":6} +AOFO 10A {"NAME":"AOFO Smart Plug Wifi","GPIO":[0,0,0,0,56,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Aoycocr EU5 16A {"NAME":"Aoycocr","GPIO":[255,0,56,0,0,0,0,0,255,17,0,21,0],"FLAG":0,"BASE":17} Aoycocr EU6S {"NAME":"Aoycocr EU6S","GPIO":[255,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":17} Aoycocr U2S {"NAME":"Aoycocr U2S","GPIO":[56,0,57,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} @@ -511,7 +525,7 @@ Avatar AWP14H {"NAME":"Avatar UK 10A","GPIO":[0,0,56,0,0,134,0,0,131, Avatto JH-G01E {"NAME":"AVATTO JH-G01E","GPIO":[0,145,0,146,0,0,0,0,17,56,21,0,0],"FLAG":0,"BASE":41} Avatto NAS-WR01W 10A {"NAME":"AvattoNAS-WR01W","GPIO":[0,0,0,0,52,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Avatto OT06 16A {"NAME":"Avatto OT06","GPIO":[17,0,0,0,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":49} -Avatto OT08 {"NAME":"Avatto OT08","GPIO":[37,0,39,0,38,134,0,0,130,17,132,21,0],"FLAG":0,"BASE":18} +Avatto OT08 {"NAME":"Avatto OT08","GPIO":[37,0,39,0,38,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} Awow EU3S {"NAME":"AWOW BSD33","GPIO":[0,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} Awow X5P {"NAME":"Awow","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} AWP02L-N {"NAME":"AWP02L-N","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} @@ -532,7 +546,7 @@ BlitzWolf BW-SHP6 10A {"NAME":"BW-SHP6 10A","GPIO":[158,255,56,255,0,134,0,0, Blitzwolf BW-SHP6 15A {"NAME":"Blitzwolf SHP6","GPIO":[56,255,158,255,132,134,0,0,131,17,0,21,0],"FLAG":0,"BASE":45} BlitzWolf BW-SHP7 {"NAME":"SHP7","GPIO":[17,158,57,131,134,132,0,0,18,56,21,0,22],"FLAG":0,"BASE":45} BN-LINK BNC-60/U133TJ-2P {"NAME":"BNC-60/U133TJ","GPIO":[0,56,0,17,134,132,0,0,131,57,21,0,0],"FLAG":0,"BASE":18} -BNETA IoT {"NAME":"BNETA WifiPlug","GPIO":[17,0,0,0,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} +BNETA IO-WIFI-PlugSA {"NAME":"BNETA WifiPlug","GPIO":[17,0,0,0,133,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} Brennenstuhl WA 3000 XS01 {"NAME":"WA 3000 XS01","GPIO":[0,0,0,0,21,17,0,0,158,52,0,0,0],"FLAG":0,"BASE":61} Bright {"NAME":"Bright Wi-Fi Smart Plug","GPIO":[0,0,0,0,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} Brilliant HK17654S05 {"NAME":"HK17654S05","GPIO":[17,255,255,255,133,132,255,255,131,56,21,255,255],"FLAG":0,"BASE":18} @@ -559,6 +573,7 @@ Coosa {"NAME":"COOSA","GPIO":[0,0,0,0,57,52,0,0,21,17,255,0,0 Coosa SP1 {"NAME":"COOSA SP1","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} CrazyLynX WiFi {"NAME":"CrazyLynX","GPIO":[0,0,0,0,57,56,0,0,21,17,0,0,0],"FLAG":1,"BASE":18} CYYLTF BIFANS J23 {"NAME":"CYYLTD BIFANS J23","GPIO":[56,0,0,0,0,0,0,0,21,17,0,0,0],"FLAG":1,"BASE":18} +D3D Smart Plug with USB & Power Monitor {"NAME":"D3D d_SUM","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} DE-1 16A {"NAME":"DE-1","GPIO":[0,17,0,0,133,0,0,0,0,52,21,0,0],"FLAG":1,"BASE":18} DeLock 11826 {"NAME":"DeLock 11826","GPIO":[17,0,0,0,0,0,0,0,21,158,0,0,0],"FLAG":0,"BASE":1} Deltaco SH-P01 {"NAME":"DELTACO SH-P01","GPIO":[0,0,0,0,0,56,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} @@ -651,6 +666,7 @@ iClever IC-BS08 {"NAME":"iClever BS08","GPIO":[0,0,0,0,157,56,0,0,21,17 iDIGITAL {"NAME":"Brilliant","GPIO":[0,0,0,0,52,0,0,0,21,90,0,0,0],"FLAG":0,"BASE":18} Ihommate ZCH-02 {"NAME":"ZCH-02","GPIO":[0,0,0,17,133,132,0,0,130,56,21,0,0],"FLAG":1,"BASE":18} Infray 16A {"NAME":"AWP08L","GPIO":[17,0,52,0,0,0,0,0,0,0,0,21,0],"FLAG":1,"BASE":18} +Insmart WP5 {"NAME":"INSMART","GPIO":[0,0,46,0,0,0,0,0,0,9,0,21,0],"FLAG":0,"BASE":18} iSwitch {"NAME":"Smart Plug XSA","GPIO":[255,17,255,255,255,255,0,0,255,56,21,255,255],"FLAG":0,"BASE":18} Jeeo TF-SH330 {"NAME":"Jeeo TF-SH330","GPIO":[56,0,0,0,0,0,0,0,0,17,0,21,0],"FLAG":1,"BASE":18} Jeeo TF-SH331W {"NAME":"Jeeo SH331W","GPIO":[56,0,158,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} @@ -658,6 +674,7 @@ Jinli XS-SSA01 {"NAME":"JINLI","GPIO":[0,0,0,0,0,0,0,0,56,17,0,21,0]," Jinvoo SM-PW701U {"NAME":"SM-PW702","GPIO":[0,0,0,0,57,56,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Jinvoo SM-PW712UA 10A {"NAME":"SM-PW712UA","GPIO":[0,0,0,158,56,57,0,0,22,17,21,0,0],"FLAG":15,"BASE":18} Jinvoo SM-PW762U {"NAME":"SM-PW762U","GPIO":[0,0,0,0,158,56,0,0,21,17,22,0,0],"FLAG":0,"BASE":18} +Jomarto SH0617 {"NAME":"Jomarto SH0617","GPIO":[57,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Jomarto SH1123 {"NAME":"SH1123","GPIO":[0,0,56,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Jules V (Upgrade Version) {"NAME":"Jules-V_UV","GPIO":[56,0,0,0,0,134,0,0,21,17,132,57,131],"FLAG":0,"BASE":18} JULES.V NX-SM200 V1.3 {"NAME":"NX-SM200","GPIO":[52,0,0,131,0,134,0,0,0,17,132,21,0],"FLAG":1,"BASE":45} @@ -710,6 +727,7 @@ Merkury MI-WW105-199W {"NAME":"Merkury Switch","GPIO":[255,255,255,255,158,56 Minleaf W-DEXI {"NAME":"W-DEXI","GPIO":[0,17,0,0,134,132,0,0,131,52,21,0,0],"FLAG":0,"BASE":18} Mirabella Genio 1002341 {"NAME":"Genio 1","GPIO":[0,0,56,0,0,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":1} Mirabella Genio USB {"NAME":"Mirabella Genio 1002826","GPIO":[0,0,0,17,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":1} +Mirabella Genio USB Port and Plug {"NAME":"Genio I002341","GPIO":[0,0,0,0,56,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":1} Mistral {"NAME":"Mistral Smart ","GPIO":[56,0,0,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Moes NX-SP203 {"NAME":"Moes NX-SP203","GPIO":[52,0,0,0,17,134,0,0,21,18,0,22,0],"FLAG":0,"BASE":18} Moes W-DE004S {"NAME":"Moes DE004S ","GPIO":[57,0,0,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} @@ -722,6 +740,7 @@ Nedis P130 {"NAME":"WIFIP130FWT","GPIO":[0,0,0,0,56,57,0,0,21,17,0 NEO Coolcam NAS-WR01W {"NAME":"NAS-WR01W","GPIO":[0,0,0,0,52,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} NEO Coolcam NAS-WR01W 16A {"NAME":"Neo Coolcam 16","GPIO":[17,0,0,0,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":49} NETVIP XS-SSA01 {"NAME":"XS-SSA01","GPIO":[0,0,0,0,0,0,0,0,56,17,0,21,0],"FLAG":0,"BASE":18} +Nightlight and AC Outlet {"NAME":"SWN03","GPIO":[17,0,0,0,0,0,255,255,37,0,0,21,0],"FLAG":0,"BASE":18} Nishica SM-PW701I {"NAME":"SM-PW701I","GPIO":[255,255,255,255,255,255,255,255,21,52,17,255,255],"FLAG":15,"BASE":18} NX-SM112 {"NAME":"NX-SM112v3","GPIO":[0,0,0,0,134,132,0,0,158,17,130,21,0],"FLAG":0,"BASE":45} NX-SM200 {"NAME":"NX-SM200","GPIO":[56,0,0,0,0,134,0,0,21,17,132,57,131],"FLAG":0,"BASE":18} @@ -751,10 +770,12 @@ Prime CCRCWFII113PK {"NAME":"Prime","GPIO":[0,0,0,0,57,56,0,0,21,122,0,0,0] Prime RCWFII11 {"NAME":"Prime Plug","GPIO":[0,0,0,0,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":18} PrimeCables Cab-LA-WF4 {"NAME":"Mini Smart Outlet Wifi Socket with Timer Function","GPIO":[0,0,0,56,57,0,0,0,0,0,0,21,17],"FLAG":0,"BASE":18} qnect 16A {"NAME":"QNECT QN-WP01E","GPIO":[0,0,0,17,133,132,0,0,131,52,21,0,0],"FLAG":0,"BASE":18} +Qualitel Mini {"NAME":"Qualitel HG01WT","GPIO":[56,0,57,0,0,133,0,0,131,17,132,21,0],"FLAG":0,"BASE":18} RenPho RF-SM004 {"NAME":"RenPho RFSM004","GPIO":[0,0,0,0,157,56,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Robaxo {"NAME":"Robaxo RSP-025","GPIO":[17,0,0,0,134,132,0,0,131,56,21,0,0],"FLAG":0,"BASE":18} RSH-WS007-EU {"NAME":"RSH-WS007","GPIO":[0,0,56,0,0,134,0,0,131,17,132,21,0],"FLAG":1,"BASE":18} S126 {"NAME":"tuya-plug","GPIO":[0,0,0,0,0,0,0,0,21,20,0,0,0],"FLAG":0,"BASE":8} +Sansui {"NAME":"Sansui YSP-1","GPIO":[52,0,53,0,0,0,0,0,0,17,0,21,0],"FLAG":0,"BASE":18} Shelly Plug S {"NAME":"Shelly Plug S","GPIO":[57,255,56,255,0,134,0,0,131,17,132,21,0],"FLAG":2,"BASE":45} Silvergear Slimme Stekker {"NAME":"Silvergear SmartHomePlug","GPIO":[0,0,0,122,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} SimpleHome {"NAME":"SimpleHome","GPIO":[53,0,0,0,0,0,0,0,21,56,17,0,0],"FLAG":0,"BASE":1} @@ -800,6 +821,7 @@ Teckin SP22 {"NAME":"Teckin","GPIO":[0,17,0,57,134,132,0,0,131,56,2 Teckin SP23 {"NAME":"Teckin SP23","GPIO":[56,255,57,255,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} Teckin SP25 {"NAME":"Teckin SP25","GPIO":[56,255,255,255,255,255,0,0,22,17,255,21,255],"FLAG":1,"BASE":18} Teckin SP27 {"NAME":"Teckin SP27","GPIO":[56,255,255,255,255,255,0,0,255,17,255,21,255],"FLAG":0,"BASE":18} +Tellur 16A 2 Ports {"NAME":"Tellur WiFi Smart Socket","GPIO":[18,0,0,131,134,132,0,0,157,21,22,0,17],"FLAG":0,"BASE":18} Tflag NX-SM100 {"NAME":"NX-SM100","GPIO":[56,0,0,0,0,134,0,0,21,17,132,57,131],"FLAG":0,"BASE":18} TikLok TL650 {"NAME":"TikLok Mini","GPIO":[0,0,0,0,57,0,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Timethinker C338 {"NAME":"C338","GPIO":[17,0,255,0,0,0,0,0,21,52,255,0,0],"FLAG":0,"BASE":1} @@ -828,6 +850,7 @@ WAZA 10A {"NAME":"WAZA","GPIO":[0,0,0,0,21,17,0,0,56,0,0,0,0],"F WAZA JH-G01B {"NAME":"Teckin SP27","GPIO":[255,255,255,255,53,255,0,0,21,17,255,255,255],"FLAG":0,"BASE":18} WAZA JH-G01E 10A {"NAME":"Waza JH-G01E","GPIO":[0,0,0,0,52,0,0,0,21,17,0,0,0],"FLAG":1,"BASE":18} Waza JH-G01E 16A {"NAME":"Waza JH-G01E 2","GPIO":[0,0,0,0,0,0,0,0,17,52,21,0,0],"FLAG":1,"BASE":18} +Wily Electronics {"NAME":"VC Plug","GPIO":[157,0,0,0,0,134,0,0,131,17,132,21,0],"FLAG":0,"BASE":45} WiOn 50055 {"NAME":"WiOn","GPIO":[255,0,52,0,0,0,0,0,255,17,0,21,0],"FLAG":0,"BASE":17} Wisdom ZY_ACU02 {"NAME":"ZY-ACU02","GPIO":[0,0,0,157,22,21,0,0,56,17,57,0,0],"FLAG":0,"BASE":18} WL-SC01 {"NAME":"WL-SC01","GPIO":[0,0,0,0,56,0,0,0,21,0,17,0,0],"FLAG":0,"BASE":1} @@ -870,7 +893,7 @@ ZSP-001 {"NAME":"ZSP-001","GPIO":[17,255,255,255,133,132,0,0,13 ``` A0F0 ZLD-44EU-W {"NAME":"AOFO-4AC-4USB","GPIO":[0,56,0,17,22,21,0,0,23,24,33,0,0],"FLAG":1,"BASE":18} Acenx 3AC+3USB {"NAME":"ACENX 3-Outlet","GPIO":[56,55,54,53,0,21,0,0,23,24,22,0,17],"FLAG":0,"BASE":18} -AHRise 4+4AC+4USB {"NAME":"AHRise-083","GPIO":[0,0,0,0,52,17,0,0,22,21,23,24,0],"FLAG":0,"BASE":18} +AHRise 4+4AC+4USB {"NAME":"AHRise-083","GPIO":[0,0,0,0,56,17,0,0,22,21,23,24,0],"FLAG":0,"BASE":18} AHRise AHR-085 {"NAME":"AHRise AHR-085","GPIO":[0,0,0,0,17,56,0,0,22,23,21,0,0],"FLAG":0,"BASE":18} Annhome 3AC + 2USB {"NAME":"1200W WiFi SPS","GPIO":[32,0,0,0,57,52,0,0,21,17,22,23,33],"FLAG":0,"BASE":18} AOFO 3AC+4USB {"NAME":"AOFO","GPIO":[0,56,0,17,22,21,0,0,0,23,24,0,0],"FLAG":1,"BASE":18} @@ -902,6 +925,7 @@ Hyleton 330 {"NAME":"Hyleton-330","GPIO":[57,0,0,56,29,17,0,0,31,30 Hyleton 331 {"NAME":"HLT-331","GPIO":[52,255,255,57,29,17,0,0,31,30,32,255,58],"FLAG":0,"BASE":18} Hyleton 333 {"NAME":"HLT-333","GPIO":[52,0,0,57,29,17,0,0,31,30,0,0,24],"FLAG":0,"BASE":18} Hyleton 336 {"NAME":"HLT-336","GPIO":[52,0,0,57,29,17,0,0,31,30,0,0,32],"FLAG":0,"BASE":18} +Jinvoo 4AC+2USB {"NAME":"JINVOO Model SM-SO306-2A","GPIO":[56,0,0,0,32,17,0,0,30,31,29,0,25],"FLAG":0,"BASE":18} KMC 5 {"NAME":"KMC 5-Outlet","GPIO":[56,0,0,0,25,9,0,0,22,21,23,0,24],"FLAG":0,"BASE":18} Kogan Power Strip USB Ports & Energy Meter {"NAME":"Generic","GPIO":[90,56,0,24,134,132,0,0,131,22,23,21,0],"FLAG":0,"BASE":18} Konesky Type 1 {"NAME":"Konesky","GPIO":[0,0,0,0,25,22,0,0,24,17,23,21,0],"FLAG":0,"BASE":18} @@ -1009,6 +1033,7 @@ Globe A19 10W 800lm {"NAME":"GlobeRGBWW","GPIO":[0,0,0,0,37,40,0,0,38,41,39 Helloify BR30 9W 600lm {"NAME":"Helloify","GPIO":[255,255,255,255,37,40,255,255,38,41,39,255,255],"FLAG":0,"BASE":18} HIPER IoT A61 {"NAME":"HIPER IoT A61","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} HIPER IoT C1 {"NAME":"Hiper IoT C1 RGB","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} +Holdpeak BR40 12W 1100lm {"NAME":"HP-BR40-12W","GPIO":[0,0,0,0,140,37,0,0,38,0,141,0,0],"FLAG":0,"BASE":18} Infray 9W 900LM {"NAME":"InfrayRGBCCT","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Jeeo TF-QPZ13 800lm {"NAME":"Jeeo","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} Julun JL-021 5W Candle {"NAME":"E14 RGBCCT","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} @@ -1042,10 +1067,12 @@ LVWIT A70 12W 1521lm {"NAME":"LVWIT A70 12W","GPIO":[0,0,0,0,37,40,0,0,38,50 LVWIT BR30 8.5W 650lm {"NAME":"LVWIT BR30 8.5W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} LVWIT G45 5W 470Lm {"NAME":"LVWIT E14 5W G45 RGBWCCT","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} MagicHome 7W {"NAME":"MagicHome E27","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Moes 9W 800lm {"NAME":"Moes 9w","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Nishica JBT 9W 806lm {"NAME":"Nishica","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} +Novostella 7W 600lm {"NAME":"Novostella E27","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} +Novostella 7W 600lm {"NAME":"Novostella B22","GPIO":[0,0,0,0,37,41,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} Novostella HM-LB09 13W 1300lm {"NAME":"Novostella 13W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Novostella NTB10 9W 900lm {"NAME":"NTB10","GPIO":[0,0,0,0,41,38,0,0,39,0,40,37,0],"FLAG":0,"BASE":18} -Novostella UT55505 7W 600lm {"NAME":"Novostella B22","GPIO":[0,0,0,0,37,41,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} Novostella UT55507 9W 900lm {"NAME":"Novostella UT55507","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Novostella UT55507 9W 900lm {"NAME":"Novostella UT55507","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Novostella UT55508 12W 1150lm {"NAME":"Novostella","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} @@ -1074,7 +1101,7 @@ Techlux A19 9W 806lm {"NAME":"TECHLUX A19 RGBCW 806lm 9w","GPIO":[0,0,0,0,37 Teckin SB50 v3 A19 800lm {"NAME":"Teckin SB50v3","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Teckin SB53 1300lm {"NAME":"Teckin SB53","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Treatlife A19 8W 650lm {"NAME":"Treatlife RGBW","GPIO":[0,0,0,0,38,37,0,0,41,39,40,0,0],"FLAG":0,"BASE":18} -V-Tac PAR16 4.5W 400lm {"NAME":"V-TAC VT5164","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} +V-Tac PAR16 4.5W 400lm 100C {"NAME":"V-TAC VT5164","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} Vizia 5W GU10 {"NAME":"Vizia RGBWW","GPIO":[0,0,0,0,40,41,0,0,38,39,37,0,0],"FLAG":15,"BASE":18} Wipro Garnet 9W 810lm {"NAME":"Wipro","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} Zemismart 5W 480lm {"NAME":"Zemismart 5W","GPIO":[0,0,0,0,37,40,0,0,38,41,39,0,0],"FLAG":0,"BASE":18} @@ -1173,6 +1200,7 @@ Merkury MI-BW904-999W 1050lm {"NAME":"MI-BW904-999W","GPIO":[0,0,0,0,140,37,0,0 Merkury MI-BW904-999W v2 1050lm {"NAME":"MI-BW210-999W","GPIO":[0,0,0,0,38,37,0,0,141,142,140,0,0],"FLAG":0,"BASE":48} Merkury MI-BW904-999W v3 {"NAME":"MI-BW904-999W","GPIO":[0,0,0,0,37,38,0,0,141,142,140,0,0],"FLAG":0,"BASE":69} Merkury MI-BW906-999W BR30 750lm {"NAME":"MI-BW906-999W","GPIO":[0,0,0,0,38,37,0,0,141,142,140,0,0],"FLAG":0,"BASE":18} +Mimoodz A19 6.5W {"NAME":"Miimoodz RGBCW LED","GPIO":[0,0,0,0,180,0,0,0,0,0,181,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbRGB","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"GenioBulbRGB","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Mirabella Genio 9W 800lm {"NAME":"MiraBellaGenio","GPIO":[0,0,0,0,0,0,0,0,181,0,180,0,0],"FLAG":0,"BASE":18} @@ -1203,6 +1231,7 @@ Swisstone SH 320 350lm {"NAME":"SH 320","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0] Swisstone SH 340 806lm {"NAME":"SH 340","GPIO":[0,0,0,0,140,37,0,0,0,142,141,0,0],"FLAG":15,"BASE":18} Syska 720lm {"NAME":"SyskaSmartBulb","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} TCP Smart 806lm {"NAME":"TCP Smart RGBW","GPIO":[0,0,0,0,140,37,0,0,38,142,141,0,0],"FLAG":0,"BASE":18} +Teckin 7.5W 800lm {"NAME":"Teckin SB60","GPIO":[0,0,0,0,37,40,0,0,38,0,39,0,0],"FLAG":0,"BASE":18} Teckin SB50 800lm {"NAME":"Teckin SB50","GPIO":[0,0,0,0,40,0,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} Teckin SB50 v2 800lm {"NAME":"Teckin SB50","GPIO":[0,0,0,0,37,0,0,0,38,40,39,0,0],"FLAG":0,"BASE":18} Teckin SB51 800lm {"NAME":"Teckin SB51","GPIO":[0,0,0,0,40,0,0,0,38,39,37,0,0],"FLAG":0,"BASE":18} @@ -1228,8 +1257,9 @@ Zilotek A19 800lm {"NAME":"Zilotek RGBW","GPIO":[0,0,0,0,140,37,0,0,38,14 Anmbest 2 Channel Inching Self-locking Switch Module {"NAME":"Generic","GPIO":[17,255,255,255,255,22,18,0,21,56,0,0,0],"FLAG":0,"BASE":1} ATMS1601 230VAC DIN Timer/Switch {"NAME":"ATMS1601","GPIO":[255,255,255,255,157,56,255,255,21,17,255,255,255],"FLAG":15,"BASE":18} BlitzWolf BW-SS1 {"NAME":"BW-SS1","GPIO":[255,255,255,255,157,21,0,0,255,17,255,255,0],"FLAG":0,"BASE":18} +BlitzWolf BW-SS5 1 Gang {"NAME":"BlitzWolf SS5 1 Gang","GPIO":[0,0,0,0,0,0,0,0,9,21,0,0,0],"FLAG":0,"BASE":18} BlitzWolf BW-SS5 2 Gang {"NAME":"BlitzWolf SS5 2 Gang","GPIO":[0,0,0,0,160,0,0,0,43,42,21,22,0],"FLAG":0,"BASE":18} -BlitzWolf SS4 Two Gang {"NAME":"BlitzWolf SS4","GPIO":[0,0,0,0,56,21,0,0,22,17,0,0,0],"FLAG":0,"BASE":18} +BlitzWolf SS4 {"NAME":"BlitzWolf SS4 Two Gang","GPIO":[0,0,0,0,56,21,0,0,22,17,0,0,0],"FLAG":0,"BASE":18} Canwing CW-001 {"NAME":"Canwing CW-001","GPIO":[17,255,0,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":1} Century Aoke Smart Switch {"NAME":"CenturyAoke","GPIO":[0,255,0,255,21,0,0,0,17,56,255,0,0],"FLAG":0,"BASE":18} Deta 6000HA Smart Inline Switch {"NAME":"DETA-6000HA","GPIO":[0,17,0,0,0,0,0,0,0,56,21,0,0],"FLAG":0,"BASE":18} @@ -1314,6 +1344,7 @@ Lenovo Rechargable PIR Motion {"NAME":"Lenovo PIR","GPIO":[255,107,255,108,255, Mirabella Genio I002576 Motion {"NAME":"GenioPir","GPIO":[17,107,0,108,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":54} Natural Gas (CH4) Alarm {"NAME":"PA-210WYS","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} Nedis Smoke Detector {"NAME":"Nedis Smoke","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} +Shelly i3 Action and Scenes Activation Device {"NAME":"Shelly i3","GPIO":[0,0,0,0,0,0,0,0,83,84,82,0,0],"FLAG":0,"BASE":18} Shelly Temperature Sensor Add-on {"NAME":"Shelly 1 Temp ","GPIO":[192,0,0,4,21,82,0,0,0,0,0,0,0],"FLAG":0,"BASE":46} Smoke Alarm {"NAME":"YG400A","GPIO":[255,107,255,108,255,255,0,0,255,255,255,255,255],"FLAG":0,"BASE":54} Sonoff SC {"NAME":"Sonoff SC","GPIO":[17,148,255,149,0,0,0,0,0,56,0,0,0],"FLAG":0,"BASE":21} @@ -1324,6 +1355,7 @@ Zemismart Door Window {"NAME":"Zemismart","GPIO":[255,107,255,108,255,255,0,0 ## Switch ``` 3A Smart Home HGZB-043 {"NAME":"3A Smart Home ","GPIO":[52,0,55,18,22,19,0,0,17,21,54,23,53],"FLAG":0,"BASE":18} +AGL 3 Gang {"NAME":"AGL WiFi 03","GPIO":[0,0,56,0,19,18,0,0,22,21,23,0,17],"FLAG":0,"BASE":18} Aoycocr SW1 {"NAME":"Aoycocr SW1","GPIO":[158,255,57,255,255,255,255,255,56,17,255,21,255],"FLAG":15,"BASE":18} Avatto 2 Gang {"NAME":"Avatto Wifi - ","GPIO":[0,0,52,0,0,17,0,0,21,22,0,0,18],"FLAG":0,"BASE":18} Avatto Fan Light {"NAME":"AVATTO Smart Wifi Fan Light","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} @@ -1365,6 +1397,7 @@ Girier JRSWR-US01 No Neutral 3 Gang {"NAME":"Girier JRSWR-U","GPIO":[0,0,0,0,21 GoKlug Glass Touch 1 Gang {"NAME":"GoKlug 1x","GPIO":[56,57,0,0,0,9,0,0,0,0,0,21,0],"FLAG":0,"BASE":18} Gosund KS-602S {"NAME":"Gosund KS-602S","GPIO":[17,0,56,0,0,0,0,0,0,0,21,0,158],"FLAG":0,"BASE":18} Gosund SW1 {"NAME":"Gosund SW1","GPIO":[17,0,57,0,0,0,0,0,0,0,21,0,56],"FLAG":0,"BASE":18} +Gosund SW6 3-Way {"NAME":"Gosund SW6","GPIO":[17,0,56,0,9,0,0,0,0,0,22,21,158],"FLAG":0,"BASE":18} Hama Flush-mounted {"NAME":"Hama WiFiTouch","GPIO":[157,0,0,0,0,18,0,0,17,22,0,21,0],"FLAG":0,"BASE":45} HBN Wall-Mounted Timer {"NAME":"HBN Timer Switch","GPIO":[0,0,0,0,54,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Innens 1 Gang 1 Way {"NAME":"Innens 1 Gang 1 Way","GPIO":[0,0,0,17,21,0,0,0,0,0,52,0,0],"FLAG":0,"BASE":18} @@ -1400,8 +1433,7 @@ LX-WIFI-00M 4 Gang {"NAME":"LX-WIFI-00M","GPIO":[17,25,255,255,23,22,18,19 MakeGood 2 Gang {"NAME":"MakeGood 2 Gang","GPIO":[0,0,0,0,0,0,0,0,0,0,54,0,0],"FLAG":0,"BASE":54} MakeGood 4 Gang {"NAME":"MakeGood 4 Gang","GPIO":[0,0,0,0,0,0,0,0,0,0,54,0,0],"FLAG":0,"BASE":54} Markevina KS-602S {"NAME":"Markevina KS-6","GPIO":[17,255,0,255,0,0,0,0,21,52,0,0,0],"FLAG":0,"BASE":18} -Martin Jerry 3 Way {"NAME":"MJ 3Way Switch","GPIO":[0,0,0,0,52,53,0,0,21,9,157,0,0],"FLAG":0,"BASE":18} -Martin Jerry MJ-S01 15A {"NAME":"MJ Switch","GPIO":[0,0,0,0,56,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} +Martin Jerry S01 15A {"NAME":"MJ-S01 Switch","GPIO":[0,0,0,0,56,57,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Martin Jerry ST01 3 Way {"NAME":"MJ 3Way Switch","GPIO":[255,255,255,255,52,53,0,0,21,9,157,255,0],"FLAG":0,"BASE":18} Merkury MI-WW107-199W {"NAME":"MI-WW107-199W","GPIO":[52,0,0,0,0,0,0,0,17,21,0,0,0],"FLAG":0,"BASE":18} Micmi K38 {"NAME":"KS-605","GPIO":[17,0,0,0,0,0,0,0,21,158,0,0,0],"FLAG":0,"BASE":18} @@ -1434,6 +1466,9 @@ NaamaSmart KS602 {"NAME":"KS-602","GPIO":[17,0,0,0,0,0,0,0,21,158,0,0,0] Nedis Dual {"NAME":"SM-SW102U-2","GPIO":[158,0,0,18,22,0,0,0,17,21,0,0,0],"FLAG":1,"BASE":18} Nexete DS-123 {"NAME":"DS-123","GPIO":[157,57,255,17,21,18,0,0,255,22,56,255,255],"FLAG":0,"BASE":18} Nexete DS-123 Single {"NAME":"DS-123","GPIO":[157,0,255,18,0,17,0,0,255,21,56,255,255],"FLAG":0,"BASE":18} +Qualitel 1 Gang {"NAME":"Qualitel 1 Gang","GPIO":[157,0,0,9,21,0,0,0,0,0,52,0,0],"FLAG":0,"BASE":18} +Qualitel 2-Gang {"NAME":"Qualitel 2 Gang","GPIO":[157,0,53,0,0,10,0,0,9,21,0,22,52],"FLAG":0,"BASE":18} +Qualitel 3 Gang {"NAME":"Qualitel 3 Gang","GPIO":[157,0,54,10,22,11,0,0,9,21,53,23,52],"FLAG":0,"BASE":18} RY-RSM104 Light Touch {"NAME":"RY-RSM104","GPIO":[0,107,0,108,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54} Sainko 1-Way {"NAME":"SAINKO 1CH","GPIO":[17,255,255,255,0,0,0,0,21,56,0,0,0],"FLAG":0,"BASE":28} Sainko 2 Way {"NAME":"Sainko 2-Way","GPIO":[0,255,56,0,0,17,0,0,21,22,0,0,18],"FLAG":0,"BASE":18} @@ -1474,6 +1509,7 @@ Teekar 10 Way 1 Gang {"NAME":"Teekar 10way","GPIO":[9,10,11,20,13,14,0,0,15, Teekar Wi-Fi Light 1 Gang {"NAME":"TeeKar Touch","GPIO":[0,0,255,0,255,21,0,0,0,255,17,0,255],"FLAG":0,"BASE":18} Teepao Smart-Rollladen-Schalter {"NAME":"Teepao","GPIO":[158,58,23,18,22,19,0,0,56,21,57,0,17],"FLAG":0,"BASE":18} Tonbux AMZ180648-2 {"NAME":"Tonbux","GPIO":[17,255,255,255,255,0,0,0,21,56,255,0,0],"FLAG":0,"BASE":1} +TopGreener TGWF15S {"NAME":"TopGreener-Switch","GPIO":[0,0,0,0,0,0,0,0,0,108,0,107,0],"FLAG":0,"BASE":54} Touch 2 Gang {"NAME":"tuya_2_gang","GPIO":[52,0,0,0,18,0,0,0,17,21,255,22,29],"FLAG":0,"BASE":18} Touch 3 Gang {"NAME":"Switch 3-Gang","GPIO":[0,0,0,0,23,18,0,0,17,21,19,22,157],"FLAG":0,"BASE":18} Treatlife SS01 3-Way {"NAME":"Treatlife SS01 3-Way","GPIO":[0,0,0,0,21,158,0,0,22,18,9,0,0],"FLAG":0,"BASE":18} @@ -1508,7 +1544,7 @@ ZUCZUG 3 Gang {"NAME":"2ph105626a x3","GPIO":[0,52,0,17,19,18,0,0,22, ## Valve ``` -Garden Water Timer BQ05 {"NAME":"BQ05","GPIO":[255,255,255,255,255,255,0,0,255,255,255,21,22],"FLAG":1,"BASE":18} +Garden Water Timer BQ05 {"NAME":"BQ05","GPIO":[17,0,0,0,0,0,0,0,21,157,0,0,0],"FLAG":1,"BASE":18} Hoenyzy DN20 3/4 {"NAME":"DN20 Valve","GPIO":[0,0,0,0,0,0,0,0,17,21,0,0,0],"FLAG":0,"BASE":18} Jinvoo SM-AW713 {"NAME":"Jinvoo Valve","GPIO":[0,0,0,0,0,52,0,0,21,17,0,0,0],"FLAG":0,"BASE":18} Jinvoo SM-AW713 v2 {"NAME":"Jinvoo Valve v2","GPIO":[0,0,0,0,52,53,0,0,21,17,0,0,0],"FLAG":0,"BASE":1} @@ -1547,5 +1583,5 @@ Vigica VGSPK00815 {"NAME":"VIGICA outlet","GPIO":[17,255,255,255,255,22,1 ## Zigbee Bridge ``` -Sonoff ZBBridge {"NAME":"Sonoff ZBBridge","GPIO":[56,165,0,166,59,58,0,0,0,158,0,0,17],"FLAG":0,"BASE":18} +Sonoff ZBBridge {"NAME":"Sonoff ZbBridge","GPIO":[56,165,0,166,215,0,0,0,0,158,0,0,17],"FLAG":0,"BASE":75} ``` From c47d8d03a5c64d8a1dce3d986ed4b3a2ffcd784a Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Wed, 29 Jul 2020 10:02:04 +0200 Subject: [PATCH 60/91] Change Zigbee randomizing of parameters at first run or after Reset --- tasmota/CHANGELOG.md | 1 + tasmota/my_user_config.h | 6 --- tasmota/tasmota_configurations.h | 5 --- tasmota/xdrv_23_zigbee_0_constants.ino | 41 ++++++++++++++++++++ tasmota/xdrv_23_zigbee_7_statemachine.ino | 47 +++++++++-------------- tasmota/xdrv_23_zigbee_8_parsers.ino | 46 ++++++++-------------- tasmota/xdrv_23_zigbee_9_serial.ino | 3 ++ tasmota/xdrv_23_zigbee_A_impl.ino | 33 +++++++++++----- 8 files changed, 103 insertions(+), 79 deletions(-) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index d30040e93..939aad6ac 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -11,6 +11,7 @@ - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command (``S``)``SerialSend6`` \ (#8937) - Change ``Ping`` now reports the hostname instead of IP address (#8948) +- Change Zigbee randomizing of parameters at first run or after Reset ### 8.3.1.6 20200617 diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index d7dd6b2cc..fff58d480 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -684,14 +684,8 @@ #define USE_ZIGBEE_ZNP // Enable ZNP protocol, needed for CC2530 based devices // #define USE_ZIGBEE_EZSP // [EXPERIMENTAL - DO NOT USE] Enable EZSP protocol, needed for EFR32 EmberZNet based devices, like Sonoff Zigbee bridge // Note: USE_ZIGBEE_ZNP and USE_ZIGBEE_EZSP are mutually incompatible, you must select exactly one - #define USE_ZIGBEE_PANID 0x1A63 // arbitrary PAN ID for Zigbee network, must be unique in the home - // if PANID == 0xFFFF, then the device will act as a Zigbee router, the parameters below are ignored - // if PANID == 0xFFFE, then the device will act as a Zigbee end-device (non-router), the parameters below are ignored - #define USE_ZIGBEE_EXTPANID 0xCCCCCCCCCCCCCCCCL // arbitrary extended PAN ID #define USE_ZIGBEE_CHANNEL 11 // Zigbee Channel (11-26) #define USE_ZIGBEE_TXRADIO_DBM 20 // Tx Radio power in dBm (only for EZSP, EFR32 can go up to 20 dBm) - #define USE_ZIGBEE_PRECFGKEY_L 0x0F0D0B0907050301L // note: changing requires to re-pair all devices - #define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices #define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms) #define USE_ZIGBEE_MODELID "Tasmota Z2T" // reported "ModelId" (cluster 0000 / attribute 0005) diff --git a/tasmota/tasmota_configurations.h b/tasmota/tasmota_configurations.h index da1248f6e..2ee368d84 100644 --- a/tasmota/tasmota_configurations.h +++ b/tasmota/tasmota_configurations.h @@ -537,12 +537,7 @@ #undef USE_ZIGBEE_ZNP #define USE_ZIGBEE_EZSP #define USE_TCP_BRIDGE - #define USE_ZIGBEE_PANID 0x1A63 // arbitrary PAN ID for Zigbee network, must be unique in the home - #define USE_ZIGBEE_EXTPANID 0xCCCCCCCCCCCCCCCCL // arbitrary extended PAN ID #define USE_ZIGBEE_CHANNEL 11 // Zigbee Channel (11-26) - #define USE_ZIGBEE_PRECFGKEY_L 0x0F0D0B0907050301L // note: changing requires to re-pair all devices - #define USE_ZIGBEE_PRECFGKEY_H 0x0D0C0A0806040200L // note: changing requires to re-pair all devices - #define USE_ZIGBEE_PERMIT_JOIN false // don't allow joining by default #define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms) diff --git a/tasmota/xdrv_23_zigbee_0_constants.ino b/tasmota/xdrv_23_zigbee_0_constants.ino index c24e5c091..62b3652af 100644 --- a/tasmota/xdrv_23_zigbee_0_constants.ino +++ b/tasmota/xdrv_23_zigbee_0_constants.ino @@ -1131,6 +1131,47 @@ String getZDPStatusMessage(uint8_t status) { return String(msg); } +String getEmberStatus(uint8_t status) { + static const char StatusMsg[] PROGMEM = "SUCCESS|ERR_FATAL|BAD_ARGUMENT|EEPROM_MFG_STACK_VERSION_MISMATCH|INCOMPATIBLE_STATIC_MEMORY_DEFINITIONS|EEPROM_MFG_VERSION_MISMATCH|EEPROM_STACK_VERSION_MISMATCH" + "|NO_BUFFERS|SERIAL_INVALID_BAUD_RATE|SERIAL_INVALID_PORT|SERIAL_TX_OVERFLOW|SERIAL_RX_OVERFLOW|SERIAL_RX_FRAME_ERROR|SERIAL_RX_PARITY_ERROR|SERIAL_RX_EMPTY|SERIAL_RX_OVERRUN_ERROR" + "|MAC_TRANSMIT_QUEUE_FULL|MAC_UNKNOWN_HEADER_TYPE|MAC_SCANNING|MAC_NO_DATA|MAC_JOINED_NETWORK|MAC_BAD_SCAN_DURATION|MAC_INCORRECT_SCAN_TYPE|MAC_INVALID_CHANNEL_MASK|MAC_COMMAND_TRANSMIT_FAILURE" + "|MAC_NO_ACK_RECEIVED|MAC_INDIRECT_TIMEOUT|SIM_EEPROM_ERASE_PAGE_GREEN|SIM_EEPROM_ERASE_PAGE_RED|SIM_EEPROM_FULL|ERR_FLASH_WRITE_INHIBITED|ERR_FLASH_VERIFY_FAILED|SIM_EEPROM_INIT_1_FAILED|SIM_EEPROM_INIT_2_FAILED|SIM_EEPROM_INIT_3_FAILED|ERR_FLASH_PROG_FAIL|ERR_FLASH_ERASE_FAIL" + "|ERR_BOOTLOADER_TRAP_TABLE_BAD|ERR_BOOTLOADER_TRAP_UNKNOWN|ERR_BOOTLOADER_NO_IMAGE|DELIVERY_FAILED|BINDING_INDEX_OUT_OF_RANGE|ADDRESS_TABLE_INDEX_OUT_OF_RANGE|INVALID_BINDING_INDEX" + "|INVALID_CALL|COST_NOT_KNOWN|MAX_MESSAGE_LIMIT_REACHED|MESSAGE_TOO_LONG|BINDING_IS_ACTIVE|ADDRESS_TABLE_ENTRY_IS_ACTIVE" + "|ADC_CONVERSION_DONE|ADC_CONVERSION_BUSY|ADC_CONVERSION_DEFERRED|ADC_NO_CONVERSION_PENDING|SLEEP_INTERRUPTED|PHY_TX_UNDERFLOW|PHY_TX_INCOMPLETE|PHY_INVALID_CHANNEL|PHY_INVALID_POWER|PHY_TX_BUSY|PHY_TX_CCA_FAIL|PHY_OSCILLATOR_CHECK_FAILED|PHY_ACK_RECEIVED" + "|NETWORK_UP|NETWORK_DOWN|JOIN_FAILED|MOVE_FAILED|CANNOT_JOIN_AS_ROUTER|NODE_ID_CHANGED|PAN_ID_CHANGED|NO_BEACONS|RECEIVED_KEY_IN_THE_CLEAR|NO_NETWORK_KEY_RECEIVED|NO_LINK_KEY_RECEIVED|PRECONFIGURED_KEY_REQUIRED" + "|NOT_JOINED|INVALID_SECURITY_LEVEL|NETWORK_BUSY|INVALID_ENDPOINT|BINDING_HAS_CHANGED|INSUFFICIENT_RANDOM_DATA|APS_ENCRYPTION_ERROR|SECURITY_STATE_NOT_SET" + "|KEY_TABLE_INVALID_ADDRESS|SECURITY_CONFIGURATION_INVALID|TOO_SOON_FOR_SWITCH_KEY|KEY_NOT_AUTHORIZED|SECURITY_DATA_INVALID|SOURCE_ROUTE_FAILURE|MANY_TO_ONE_ROUTE_FAILURE" + "|STACK_AND_HARDWARE_MISMATCH|INDEX_OUT_OF_RANGE|TABLE_FULL|TABLE_ENTRY_ERASED|LIBRARY_NOT_PRESENT|OPERATION_IN_PROGRESS" + ; + static const uint8_t StatusIdx[] PROGMEM = { 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x07, + 0x18, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x39, 0x3A, 0x3D, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, + 0x40, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, + 0x58, 0x59, 0x5A, 0x66, 0x69, 0x6A, 0x6C, + 0x70, 0x71, 0x72, 0x74, 0x75, 0x76, + 0x80, 0x81, 0x82, 0x84, 0x85, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x94, 0x96, 0x98, 0x99, 0x9A, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0x93, 0x95, 0xA1, 0xA3, 0xA4, 0xA5, 0xA6, 0xA8, + 0xB3, 0xB7, 0xB8, 0xBB, 0xBD, 0xA9, 0xAA, + 0xB0, 0xB1, 0xB4, 0xB6, 0xB5, 0xBA }; + + char msg[32]; + int32_t idx = -1; + for (uint32_t i = 0; i < sizeof(StatusIdx); i++) { + if (status == pgm_read_byte(&StatusIdx[i])) { + idx = i; + break; + } + } + if (idx >= 0) { + GetTextIndexed(msg, sizeof(msg), idx, StatusMsg); + } else { + *msg = 0x00; // empty string + } + return String(msg); +} + // Undocumented Zigbee ZCL code here: https://github.com/dresden-elektronik/deconz-rest-plugin/wiki/Zigbee-Error-Codes-in-the-Log String getZigbeeStatusMessage(uint8_t status) { diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index f46b34f7c..784a5ebf3 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -204,13 +204,12 @@ ZBM(ZBR_ZNPHC, Z_SRSP | Z_SYS, SYS_OSAL_NV_READ, Z_SUCCESS, 0x01 /* len */, 0x55 ZBM(ZBS_PAN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PANID ) // 260483 ZBR(ZBR_PAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PANID, 0x02 /* len */, - Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID) ) // 6604008302xxxx + 0x00, 0x00 /* pan_id */ ) // 6604008302xxxx ZBM(ZBS_EXTPAN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_EXTENDED_PAN_ID ) // 26042D ZBR(ZBR_EXTPAN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_EXTENDED_PAN_ID, 0x08 /* len */, - Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), - Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ext_pan_id */ ) // 6604002D08xxxxxxxxxxxxxxxx ZBM(ZBS_CHANN, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_CHANLIST ) // 260484 @@ -222,10 +221,8 @@ ZBR(ZBR_CHANN, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_CHANLIS ZBM(ZBS_PFGK, Z_SREQ | Z_SAPI, SAPI_READ_CONFIGURATION, CONF_PRECFGKEY ) // 260462 ZBR(ZBR_PFGK, Z_SRSP | Z_SAPI, SAPI_READ_CONFIGURATION, Z_SUCCESS, CONF_PRECFGKEY, 0x10 /* len */, - Z_B0(USE_ZIGBEE_PRECFGKEY_L), Z_B1(USE_ZIGBEE_PRECFGKEY_L), Z_B2(USE_ZIGBEE_PRECFGKEY_L), Z_B3(USE_ZIGBEE_PRECFGKEY_L), - Z_B4(USE_ZIGBEE_PRECFGKEY_L), Z_B5(USE_ZIGBEE_PRECFGKEY_L), Z_B6(USE_ZIGBEE_PRECFGKEY_L), Z_B7(USE_ZIGBEE_PRECFGKEY_L), - Z_B0(USE_ZIGBEE_PRECFGKEY_H), Z_B1(USE_ZIGBEE_PRECFGKEY_H), Z_B2(USE_ZIGBEE_PRECFGKEY_H), Z_B3(USE_ZIGBEE_PRECFGKEY_H), - Z_B4(USE_ZIGBEE_PRECFGKEY_H), Z_B5(USE_ZIGBEE_PRECFGKEY_H), Z_B6(USE_ZIGBEE_PRECFGKEY_H), Z_B7(USE_ZIGBEE_PRECFGKEY_H), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_l */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_h */ /*0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0D*/ ) // 660400621001030507090B0D0F00020406080A0C0D @@ -250,13 +247,12 @@ ZBM(ZBR_WNV_OK, Z_SRSP | Z_SYS, SYS_OSAL_NV_WRITE, Z_SUCCESS ) // 610900 - NV // Factory reset ZBM(ZBS_FACTRES, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_STARTUP_OPTION, 0x01 /* len */, 0x03 ) // 2605030103 // Write PAN ID -ZBR(ZBS_W_PAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PANID, 0x02 /* len */, Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID) ) // 26058302xxxx +ZBR(ZBS_W_PAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PANID, 0x02 /* len */, 0x00, 0x00 /* pan_id */ ) // 26058302xxxx // Write Universal PAN ID ZBR(ZBS_W_ALL_PAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PANID, 0x02 /* len */, Z_B0(0xFFFF), Z_B1(0xFFFF) ) // 26058302FFFF // Write EXT PAN ID ZBR(ZBS_W_EXTPAN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_EXTENDED_PAN_ID, 0x08 /* len */, - Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), - Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID) + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ext_pan_id */ ) // 26052D086263151D004B1200 // Write Channel ID ZBR(ZBS_W_CHANN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_CHANLIST, 0x04 /* len */, @@ -276,11 +272,8 @@ ZBM(ZBS_W_LOGTYP_DEVICE, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_LOGICAL // Write precfgkey ZBR(ZBS_W_PFGK, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PRECFGKEY, 0x10 /* len */, - Z_B0(USE_ZIGBEE_PRECFGKEY_L), Z_B1(USE_ZIGBEE_PRECFGKEY_L), Z_B2(USE_ZIGBEE_PRECFGKEY_L), Z_B3(USE_ZIGBEE_PRECFGKEY_L), - Z_B4(USE_ZIGBEE_PRECFGKEY_L), Z_B5(USE_ZIGBEE_PRECFGKEY_L), Z_B6(USE_ZIGBEE_PRECFGKEY_L), Z_B7(USE_ZIGBEE_PRECFGKEY_L), - Z_B0(USE_ZIGBEE_PRECFGKEY_H), Z_B1(USE_ZIGBEE_PRECFGKEY_H), Z_B2(USE_ZIGBEE_PRECFGKEY_H), Z_B3(USE_ZIGBEE_PRECFGKEY_H), - Z_B4(USE_ZIGBEE_PRECFGKEY_H), Z_B5(USE_ZIGBEE_PRECFGKEY_H), Z_B6(USE_ZIGBEE_PRECFGKEY_H), Z_B7(USE_ZIGBEE_PRECFGKEY_H), - /*0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_l */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_h */ /*0x01, 0x03, 0x05, 0x07, 0x09, 0x0B, 0x0D, 0x0F, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0D*/ ) // 2605621001030507090B0D0F00020406080A0C0D // Write precfgkey enable ZBM(ZBS_W_PFGKEN, Z_SREQ | Z_SAPI, SAPI_WRITE_CONFIGURATION, CONF_PRECFGKEYS_ENABLE, 0x01 /* len */, 0x00 ) // 2605630100 @@ -428,7 +421,7 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_WAIT(10500) // wait for 10 seconds for Tasmota to stabilize //ZI_MQTT_STATE(ZIGBEE_STATUS_BOOT, "Booting") - ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting device") + ZI_LOG(LOG_LEVEL_INFO, D_LOG_ZIGBEE "rebooting CC2530 device") ZI_CALL(&ZNP_Reset_Device, 0) // LOW = reset ZI_WAIT(100) // wait for .1 second @@ -693,11 +686,8 @@ ZBR(ZBS_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/, // preConfiguredKey 0x5A, 0x69, 0x67, 0x42, 0x65, 0x65, 0x41, 0x6C, 0x6C, 0x69, 0x61, 0x6E, 0x63, 0x65, 0x30, 0x39, // well known key "ZigBeeAlliance09" // networkKey - Z_B0(USE_ZIGBEE_PRECFGKEY_L), Z_B1(USE_ZIGBEE_PRECFGKEY_L), Z_B2(USE_ZIGBEE_PRECFGKEY_L), Z_B3(USE_ZIGBEE_PRECFGKEY_L), - Z_B4(USE_ZIGBEE_PRECFGKEY_L), Z_B5(USE_ZIGBEE_PRECFGKEY_L), Z_B6(USE_ZIGBEE_PRECFGKEY_L), Z_B7(USE_ZIGBEE_PRECFGKEY_L), - Z_B0(USE_ZIGBEE_PRECFGKEY_H), Z_B1(USE_ZIGBEE_PRECFGKEY_H), Z_B2(USE_ZIGBEE_PRECFGKEY_H), Z_B3(USE_ZIGBEE_PRECFGKEY_H), - Z_B4(USE_ZIGBEE_PRECFGKEY_H), Z_B5(USE_ZIGBEE_PRECFGKEY_H), Z_B6(USE_ZIGBEE_PRECFGKEY_H), Z_B7(USE_ZIGBEE_PRECFGKEY_H), - 0x00 /*sequence*/, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_l */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* key_h */ 0x00 /*sequence*/, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /*trustcenter*/ ) ZBM(ZBR_SET_SECURITY, EZSP_setInitialSecurityState, 0x00 /*high*/, 0x00 /*status*/) @@ -723,9 +713,8 @@ ZBM(ZBR_NETWORK_INIT, EZSP_networkInit, 0x00 /*high*/, 0x00 /*status*/) // // formNetwork - i.e. start zigbee network as coordinator ZBR(ZBS_FORM_NETWORK, EZSP_formNetwork, 0x00 /*high*/, - Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), - Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID), - Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ext_pan_id */ + 0x00, 0x00, // pan_id USE_ZIGBEE_TXRADIO_DBM /*radioTxPower*/, USE_ZIGBEE_CHANNEL /*channel*/, EMBER_USE_MAC_ASSOCIATION, @@ -746,9 +735,8 @@ ZBM(ZBR_GET_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/, 0x00 /*ok*/) ZBR(ZBR_CHECK_NETW_PARM, EZSP_getNetworkParameters, 0x00 /*high*/, 0x00 /*status*/, EMBER_COORDINATOR /*0x01*/, - Z_B0(USE_ZIGBEE_EXTPANID), Z_B1(USE_ZIGBEE_EXTPANID), Z_B2(USE_ZIGBEE_EXTPANID), Z_B3(USE_ZIGBEE_EXTPANID), - Z_B4(USE_ZIGBEE_EXTPANID), Z_B5(USE_ZIGBEE_EXTPANID), Z_B6(USE_ZIGBEE_EXTPANID), Z_B7(USE_ZIGBEE_EXTPANID), - Z_B0(USE_ZIGBEE_PANID), Z_B1(USE_ZIGBEE_PANID), + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ext_pan_id */ + 0x00, 0x00, // pan_id USE_ZIGBEE_TXRADIO_DBM /*radioTxPower*/, USE_ZIGBEE_CHANNEL /*channel*/, ) // 2800... @@ -884,7 +872,9 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_WAIT_RECV(1500, ZBR_NETWORK_UP) // wait for network to start // check if configuration is ok ZI_SEND(ZBS_GET_CURR_SEC) ZI_WAIT_RECV(500, ZBR_GET_CURR_SEC) - ZI_SEND(ZBS_GET_NETW_PARM) ZI_WAIT_RECV(500, ZBR_CHECK_NETW_PARM) + ZI_SEND(ZBS_GET_EUI64) ZI_WAIT_RECV_FUNC(500, ZBR_GET_EUI64, &EZ_GetEUI64) + ZI_SEND(ZBS_GET_NETW_PARM) ZI_WAIT_RECV_FUNC(500, ZBR_CHECK_NETW_PARM, &EZ_NetworkParameters) + // all ok, proceed to next step ZI_GOTO(ZIGBEE_LABEL_NETWORK_CONFIGURED) @@ -908,7 +898,6 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { // Query device information ZI_SEND(ZBS_GET_EUI64) ZI_WAIT_RECV_FUNC(500, ZBR_GET_EUI64, &EZ_GetEUI64) ZI_SEND(ZBS_GET_NODEID) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NODEID, &EZ_GetNodeId) - ZI_SEND(ZBS_GET_NETW_PARM) ZI_WAIT_RECV_FUNC(500, ZBR_GET_NETW_PARM, &EZ_NetworkParameters) ZI_LABEL(ZIGBEE_LABEL_READY) ZI_MQTT_STATE(ZIGBEE_STATUS_OK, kStarted) diff --git a/tasmota/xdrv_23_zigbee_8_parsers.ino b/tasmota/xdrv_23_zigbee_8_parsers.ino index 05b0b4b37..5814538ff 100644 --- a/tasmota/xdrv_23_zigbee_8_parsers.ino +++ b/tasmota/xdrv_23_zigbee_8_parsers.ino @@ -20,6 +20,16 @@ #ifdef USE_ZIGBEE #ifdef USE_ZIGBEE_EZSP +// +// Trying to get a uniform LQI measure, we are aligning with the definition of ZNP +// I.e. a linear projection from -87dBm to +10dB over 0..255 +// for ZNP, lqi is linear from -87 to +10 dBm (https://sunmaysky.blogspot.com/2017/02/conversion-between-rssi-and-lqi-in-z.html) +uint8_t ZNP_RSSI2Lqi(int8_t rssi) { + if (rssi < -87) { rssi = -87; } + if (rssi > 10) { rssi = 10; } + return changeUIntScale(rssi + 87, 0, 87+10, 0, 255); +} + /*********************************************************************************************\ * Parsers for incoming EZSP messages \*********************************************************************************************/ @@ -123,8 +133,8 @@ int32_t EZ_RouteError(int32_t res, const class SBuffer &buf) { uint16_t shortaddr = buf.get16(3); Response_P(PSTR("{\"" D_JSON_ZIGBEE_ROUTE_ERROR "\":{" - "\"ShortAddr\":\"0x%04X\",\"" D_JSON_ZIGBEE_STATUS "\":%d,\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"0x%s\"}}"), - shortaddr, status, ""); + "\"ShortAddr\":\"0x%04X\",\"" D_JSON_ZIGBEE_STATUS "\":%d,\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"}}"), + shortaddr, status, getEmberStatus(status).c_str()); MqttPublishPrefixTopicRulesProcess_P(RESULT_OR_TELE, PSTR(D_JSON_ZIGBEE_STATE)); @@ -776,8 +786,9 @@ int32_t Z_MgmtBindRsp(int32_t res, const class SBuffer &buf) { ResponseAppend_P(PSTR(",\"" D_JSON_ZIGBEE_STATUS "\":%d" ",\"" D_JSON_ZIGBEE_STATUS_MSG "\":\"%s\"" ",\"BindingsTotal\":%d" + ",\"BindingsStart\":%d" ",\"Bindings\":[" - ), status, getZigbeeStatusMessage(status).c_str(), bind_total); + ), status, getZigbeeStatusMessage(status).c_str(), bind_total, bind_start + 1); uint32_t idx = prefix_len; for (uint32_t i = 0; i < bind_len; i++) { @@ -1118,8 +1129,9 @@ int32_t EZ_IncomingMessage(int32_t res, const class SBuffer &buf) { bool securityuse = (apsoptions & EMBER_APS_OPTION_ENCRYPTION) ? true : false; uint16_t groupid = buf.get16(11); uint8_t seqnumber = buf.get8(13); - uint8_t linkquality = buf.get8(14); - // uint8_t linkrsssi = buf.get8(15); // probably not used as there is no equivalent in Z-Stack + // uint8_t linkquality = buf.get8(14); + int8_t linkrssi = buf.get8(15); + uint8_t linkquality = ZNP_RSSI2Lqi(linkrssi); // don't take EZSP LQI but calculate our own based on ZNP uint16_t srcaddr = buf.get16(16); // uint8_t bindingindex = buf.get8(18); // not sure we need this one as a coordinator // uint8_t addressindex = buf.get8(19); // not sure how to handle this one @@ -1315,30 +1327,6 @@ int32_t ZNP_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { * Global dispatcher for incoming messages \*********************************************************************************************/ -int32_t Z_ReceiveAfIncomingMessage(int32_t res, const class SBuffer &buf) { - uint16_t groupid = buf.get16(2); - uint16_t clusterid = buf.get16(4); - uint16_t srcaddr = buf.get16(6); - uint8_t srcendpoint = buf.get8(8); - uint8_t dstendpoint = buf.get8(9); - uint8_t wasbroadcast = buf.get8(10); - uint8_t linkquality = buf.get8(11); - uint8_t securityuse = buf.get8(12); - // uint32_t timestamp = buf.get32(13); - uint8_t seqnumber = buf.get8(17); - - bool defer_attributes = false; // do we defer attributes reporting to coalesce - - ZCLFrame zcl_received = ZCLFrame::parseRawFrame(buf, 19, buf.get8(18), clusterid, groupid, - srcaddr, - srcendpoint, dstendpoint, wasbroadcast, - linkquality, securityuse, seqnumber); - // - Z_IncomingMessage(zcl_received); - - return -1; -} - #ifdef USE_ZIGBEE_ZNP // Structure for the Dispatcher callbacks table diff --git a/tasmota/xdrv_23_zigbee_9_serial.ino b/tasmota/xdrv_23_zigbee_9_serial.ino index 1715d6763..c8a9953a1 100644 --- a/tasmota/xdrv_23_zigbee_9_serial.ino +++ b/tasmota/xdrv_23_zigbee_9_serial.ino @@ -585,12 +585,15 @@ int32_t ZigbeeProcessInputEZSP(class SBuffer &buf) { case EZSP_permitJoining: // 2200 case EZSP_getEui64: // 2600 case EZSP_getNodeId: // 2700 + case EZSP_getNetworkParameters: // 2800 case EZSP_sendUnicast: // 3400 case EZSP_sendBroadcast: // 3600 case EZSP_messageSentHandler: // 3F00 case EZSP_setConfigurationValue: // 5300 case EZSP_setPolicy: // 5500 case EZSP_setMulticastTableEntry: // 6400 + case EZSP_setInitialSecurityState: // 6800 + case EZSP_getCurrentSecurityState: // 6900 log_level = LOG_LEVEL_DEBUG; break; } diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index a631432fc..f48258031 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -57,14 +57,25 @@ void (* const ZigbeeCommand[])(void) PROGMEM = { void ZigbeeInit(void) { // Check if settings in Flash are set - if (0 == Settings.zb_channel) { - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Initializing Zigbee parameters from defaults")); - Settings.zb_ext_panid = USE_ZIGBEE_EXTPANID; - Settings.zb_precfgkey_l = USE_ZIGBEE_PRECFGKEY_L; - Settings.zb_precfgkey_h = USE_ZIGBEE_PRECFGKEY_H; - Settings.zb_pan_id = USE_ZIGBEE_PANID; - Settings.zb_channel = USE_ZIGBEE_CHANNEL; - Settings.zb_txradio_dbm = USE_ZIGBEE_TXRADIO_DBM; + if (PinUsed(GPIO_ZIGBEE_RX) && PinUsed(GPIO_ZIGBEE_TX)) { + if (0 == Settings.zb_channel) { + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Randomizing Zigbee parameters, please check with 'ZbConfig'")); + uint64_t mac64 = 0; // stuff mac address into 64 bits + WiFi.macAddress((uint8_t*) &mac64); + uint32_t esp_id = ESP.getChipId(); + uint32_t flash_id = ESP.getFlashChipId(); + + uint16_t pan_id = (mac64 & 0x3FFF); + if (0x0000 == pan_id) { pan_id = 0x0001; } // avoid extreme values + if (0x3FFF == pan_id) { pan_id = 0x3FFE; } // avoid extreme values + Settings.zb_pan_id = pan_id; + + Settings.zb_ext_panid = 0xCCCCCCCC00000000L | (mac64 & 0x00000000FFFFFFFFL); + Settings.zb_precfgkey_l = (mac64 << 32) | (esp_id << 16) | flash_id; + Settings.zb_precfgkey_h = (mac64 << 32) | (esp_id << 16) | flash_id; + Settings.zb_channel = USE_ZIGBEE_CHANNEL; + Settings.zb_txradio_dbm = USE_ZIGBEE_TXRADIO_DBM; + } } // update commands with the current settings @@ -751,18 +762,20 @@ void CmndZbUnbind(void) { // // Command `ZbBindState` +// `ZbBindState` as index if it does not fit. If default, `1` starts at the beginning // void CmndZbBindState(void) { if (zigbee.init_phase) { ResponseCmndChar_P(PSTR(D_ZIGBEE_NOT_STARTED)); return; } uint16_t shortaddr = zigbee_devices.parseDeviceParam(XdrvMailbox.data); if (BAD_SHORTADDR == shortaddr) { ResponseCmndChar_P(PSTR("Unknown device")); return; } + uint8_t index = XdrvMailbox.index - 1; // change default 1 to 0 #ifdef USE_ZIGBEE_ZNP SBuffer buf(10); buf.add8(Z_SREQ | Z_ZDO); // 25 buf.add8(ZDO_MGMT_BIND_REQ); // 33 buf.add16(shortaddr); // shortaddr - buf.add8(0); // StartIndex = 0 + buf.add8(index); // StartIndex = 0 ZigbeeZNPSend(buf.getBuffer(), buf.len()); #endif // USE_ZIGBEE_ZNP @@ -770,7 +783,7 @@ void CmndZbBindState(void) { #ifdef USE_ZIGBEE_EZSP // ZDO message payload (see Zigbee spec 2.4.3.3.4) - uint8_t buf[] = { 0x00 }; // index = 0 + uint8_t buf[] = { index }; // index = 0 EZ_SendZDO(shortaddr, ZDO_Mgmt_Bind_req, buf, sizeof(buf)); #endif // USE_ZIGBEE_EZSP From 69e252b7d7b3bf9b901e2175c29555c1456a624f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 29 Jul 2020 10:31:38 +0200 Subject: [PATCH 61/91] Prep release 8.4.0 --- MODULES.md | 2 +- RELEASENOTES.md | 15 ++++++++------- tasmota/CHANGELOG.md | 5 +++-- tasmota/my_user_config.h | 10 +++++----- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/MODULES.md b/MODULES.md index 1ca8ab473..29575f5bb 100644 --- a/MODULES.md +++ b/MODULES.md @@ -80,4 +80,4 @@ Module | Description 74 Sonoff D1 | Sonoff D1 Wifi and RF Dimmer 75 Sonoff ZbBridge | Sonoff Zigbee bridge -Over 1000 additional devices are supported using [templates](TEMPLATES.md). +Over 1400 additional devices are supported using [templates](TEMPLATES.md). diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 468f761c6..bc9abff0c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -66,6 +66,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset`` - Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message - Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` +- Change Zigbee randomizing of parameters at first run or after Reset - Fix escape of non-JSON received serial data (#8329) - Fix exception or watchdog on rule re-entry (#8757) - Add command ``Rule0`` to change global rule parameters @@ -81,28 +82,28 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add command (``S``)``SerialSend6`` \ (#8937) - Add commands ``LedPwmOn 0..255``, ``LedPwmOff 0..255`` and ``LedPwmMode1 0/1`` to control led brightness by George (#8491) - Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3`` +- Add more functionality to command ``Switchmode`` 11 and 12 (#8450) - Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet - Add support for unique MQTTClient (and inherited fallback topic) by full Mac address using ``mqttclient DVES_%12X`` (#8300) -- Add more functionality to ``Switchmode`` 11 and 12 (#8450) - Add wildcard pattern ``?`` for JSON matching in rules -- Add support for VEML6075 UVA/UVB/UVINDEX Sensor by device111 (#8432) -- Add support for VEML7700 Ambient light intensity Sensor by device111 (#8432) - Add Three Phase Export Active Energy to SDM630 driver - Add Zigbee options to ``ZbSend`` to write and report attributes - Add Zigbee auto-responder for common attributes - Add ``CpuFrequency`` to ``status 2`` - Add ``FlashFrequency`` to ``status 4`` +- Add compile time interlock parameters (#8759) +- Add compile time user template (#8766) +- Add support for VEML6075 UVA/UVB/UVINDEX Sensor by device111 (#8432) +- Add support for VEML7700 Ambient light intensity Sensor by device111 (#8432) - Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139) - Add support for up to eight MCP9808 temperature sensors by device111 (#8594) - Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175) - Add support for Telegram bot (#8619) - Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638) - Add support for Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff -- Add Library to be used for decoding Teleinfo (French Metering Smart Meter) - Add support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON - Add support for single wire LMT01 temperature Sensor by justifiably (#8713) -- Add compile time interlock parameters (#8759) -- Add compile time user template (#8766) -- Add rotary encoder support for light dimmer and optional color temperature if button1 still pressed (#8670) +- Add support for rotary encoder as light dimmer and optional color temperature if button1 still pressed (#8670) - Add support for switches/relays using an AC detection circuitry e.g. MOES MS-104B or BlitzWolf SS5 (#8606) - Add support for Schneider Electric iEM3000 series Modbus energy meter by Marius Bezuidenhout +- Add support for Sonoff Zigbee Bridge as module 75 (#8583) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 939aad6ac..6a9520fcc 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -6,12 +6,13 @@ - Change to limited support of Arduino IDE as an increasing amount of features cannot be compiled with Arduino IDE - Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message - Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` +- Change ``Ping`` now reports the hostname instead of IP address (#8948) +- Change Zigbee randomizing of parameters at first run or after Reset - Add command ``DzSend ,`` to send values or state to Domoticz - Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command (``S``)``SerialSend6`` \ (#8937) -- Change ``Ping`` now reports the hostname instead of IP address (#8948) -- Change Zigbee randomizing of parameters at first run or after Reset +- Add support for Sonoff Zigbee Bridge as module 75 (#8583) ### 8.3.1.6 20200617 diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index fff58d480..69f51a546 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -681,11 +681,11 @@ // -- Zigbee interface ---------------------------- //#define USE_ZIGBEE // Enable serial communication with Zigbee CC2530 flashed with ZNP (+49k code, +3k mem) - #define USE_ZIGBEE_ZNP // Enable ZNP protocol, needed for CC2530 based devices - // #define USE_ZIGBEE_EZSP // [EXPERIMENTAL - DO NOT USE] Enable EZSP protocol, needed for EFR32 EmberZNet based devices, like Sonoff Zigbee bridge - // Note: USE_ZIGBEE_ZNP and USE_ZIGBEE_EZSP are mutually incompatible, you must select exactly one - #define USE_ZIGBEE_CHANNEL 11 // Zigbee Channel (11-26) - #define USE_ZIGBEE_TXRADIO_DBM 20 // Tx Radio power in dBm (only for EZSP, EFR32 can go up to 20 dBm) + #define USE_ZIGBEE_ZNP // Enable ZNP protocol, needed for CC2530 based devices +// #define USE_ZIGBEE_EZSP // Enable EZSP protocol, needed for EFR32 EmberZNet based devices, like Sonoff Zigbee bridge + // Note: USE_ZIGBEE_ZNP and USE_ZIGBEE_EZSP are mutually incompatible, you must select exactly one + #define USE_ZIGBEE_CHANNEL 11 // Zigbee Channel (11-26) + #define USE_ZIGBEE_TXRADIO_DBM 20 // Tx Radio power in dBm (only for EZSP, EFR32 can go up to 20 dBm) #define USE_ZIGBEE_COALESCE_ATTR_TIMER 350 // timer to coalesce attribute values (in ms) #define USE_ZIGBEE_MODELID "Tasmota Z2T" // reported "ModelId" (cluster 0000 / attribute 0005) From 25a187499b035fa0ca9aa69e29158a3830ecf0ed Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 29 Jul 2020 10:44:09 +0200 Subject: [PATCH 62/91] Prep release 8.4.0 --- BUILDS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BUILDS.md b/BUILDS.md index c1aa5e2e3..b27400c96 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -148,6 +148,8 @@ | USE_NRF24 | - | - | - | - | - | - | - | | USE_MIBLE | - | - | - | - | - | - | - | | USE_ZIGBEE | - | - | - | - | - | - | - | +| USE_ZIGBEE_ZNP | - | - | - | - | - | - | - | +| USE_ZIGBEE_EZSP | - | - | - | - | - | - | - | Sonoff ZbBridge | | | | | | | | | | USE_IR_REMOTE | - | - | x | x | x | x | x | | USE_IR_RECEIVE | - | - | x | x | x | x | x | From e83351864ee8cba836eb15e70b67eee29b2f6483 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Wed, 29 Jul 2020 13:57:44 +0200 Subject: [PATCH 63/91] Change IRRemoteESP8266 IR lib to pre-2.7.9, fixing Samsung and Pioneer protocols (#8938) --- .../TurnOnToshibaAC/TurnOnToshibaAC.ino | 2 +- lib/IRremoteESP8266-2.7.8/src/IRac.cpp | 228 ++++-- lib/IRremoteESP8266-2.7.8/src/IRac.h | 31 +- lib/IRremoteESP8266-2.7.8/src/IRrecv.cpp | 10 +- lib/IRremoteESP8266-2.7.8/src/IRrecv.h | 10 +- .../src/IRremoteESP8266.h | 18 +- lib/IRremoteESP8266-2.7.8/src/IRsend.cpp | 7 + lib/IRremoteESP8266-2.7.8/src/IRsend.h | 7 +- lib/IRremoteESP8266-2.7.8/src/IRtext.cpp | 2 + lib/IRremoteESP8266-2.7.8/src/IRtext.h | 3 +- lib/IRremoteESP8266-2.7.8/src/IRtimer.cpp | 4 +- lib/IRremoteESP8266-2.7.8/src/IRtimer.h | 8 +- lib/IRremoteESP8266-2.7.8/src/IRutils.cpp | 32 + lib/IRremoteESP8266-2.7.8/src/IRutils.h | 2 + lib/IRremoteESP8266-2.7.8/src/ir_Airwell.cpp | 217 ++++- lib/IRremoteESP8266-2.7.8/src/ir_Airwell.h | 97 +++ lib/IRremoteESP8266-2.7.8/src/ir_Daikin.h | 5 +- lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.cpp | 12 +- lib/IRremoteESP8266-2.7.8/src/ir_LG.cpp | 10 +- lib/IRremoteESP8266-2.7.8/src/ir_LG.h | 3 +- lib/IRremoteESP8266-2.7.8/src/ir_Midea.cpp | 43 +- lib/IRremoteESP8266-2.7.8/src/ir_Midea.h | 15 + lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.h | 4 +- .../src/ir_MitsubishiHeavy.cpp | 36 +- lib/IRremoteESP8266-2.7.8/src/ir_Pioneer.cpp | 28 +- lib/IRremoteESP8266-2.7.8/src/ir_Samsung.cpp | 40 +- lib/IRremoteESP8266-2.7.8/src/ir_Samsung.h | 2 + lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.cpp | 480 ++++++++++- lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.h | 163 ++++ lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.cpp | 282 +++++-- lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.h | 89 ++- .../src/locale/defaults.h | 6 + lib/IRremoteESP8266-2.7.8/test/IRac_test.cpp | 326 +++++--- .../test/IRutils_test.cpp | 84 +- .../test/ir_Airwell_test.cpp | 150 +++- lib/IRremoteESP8266-2.7.8/test/ir_LG_test.cpp | 51 +- .../test/ir_Midea_test.cpp | 49 +- .../test/ir_Pioneer_test.cpp | 146 +++- .../test/ir_Samsung_test.cpp | 132 ++-- .../test/ir_Sanyo_test.cpp | 275 ++++++- .../test/ir_Toshiba_test.cpp | 743 +++++++++--------- .../tools/RawToGlobalCache.sh | 0 .../tools/auto_analyse_raw_data.py | 0 .../tools/auto_analyse_raw_data_test.py | 0 .../tools/generate_irtext_h.sh | 0 lib/IRremoteESP8266-2.7.8/tools/mkkeywords | 0 .../tools/scrape_supported_devices.py | 0 tasmota/CHANGELOG.md | 1 + 48 files changed, 2991 insertions(+), 862 deletions(-) create mode 100644 lib/IRremoteESP8266-2.7.8/src/ir_Airwell.h create mode 100644 lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.h mode change 100644 => 100755 lib/IRremoteESP8266-2.7.8/tools/RawToGlobalCache.sh mode change 100644 => 100755 lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data.py mode change 100644 => 100755 lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data_test.py mode change 100644 => 100755 lib/IRremoteESP8266-2.7.8/tools/generate_irtext_h.sh mode change 100644 => 100755 lib/IRremoteESP8266-2.7.8/tools/mkkeywords mode change 100644 => 100755 lib/IRremoteESP8266-2.7.8/tools/scrape_supported_devices.py diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino index a37a07e5c..fb71c0486 100644 --- a/lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino +++ b/lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino @@ -38,7 +38,7 @@ void printState() { // Display the encoded IR sequence. unsigned char* ir_code = ac.getRaw(); Serial.print("IR Code: 0x"); - for (uint8_t i = 0; i < kToshibaACStateLength; i++) + for (uint8_t i = 0; i < ac.getStateLength(); i++) Serial.printf("%02X", ir_code[i]); Serial.println(); } diff --git a/lib/IRremoteESP8266-2.7.8/src/IRac.cpp b/lib/IRremoteESP8266-2.7.8/src/IRac.cpp index fda16aba5..4e54d26f0 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRac.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/IRac.cpp @@ -16,6 +16,7 @@ #include "IRremoteESP8266.h" #include "IRtext.h" #include "IRutils.h" +#include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" #include "ir_Carrier.h" @@ -34,6 +35,7 @@ #include "ir_Neoclima.h" #include "ir_Panasonic.h" #include "ir_Samsung.h" +#include "ir_Sanyo.h" #include "ir_Sharp.h" #include "ir_Tcl.h" #include "ir_Teco.h" @@ -132,6 +134,9 @@ stdAc::state_t IRac::getStatePrev(void) { return _prev; } /// @return true if the protocol is supported by this class, otherwise false. bool IRac::isProtocolSupported(const decode_type_t protocol) { switch (protocol) { +#if SEND_AIRWELL + case decode_type_t::AIRWELL: +#endif #if SEND_AMCOR case decode_type_t::AMCOR: #endif @@ -236,6 +241,9 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { #if SEND_SAMSUNG_AC case decode_type_t::SAMSUNG_AC: #endif +#if SEND_SANYO_AC + case decode_type_t::SANYO_AC: +#endif #if SEND_SHARP_AC case decode_type_t::SHARP_AC: #endif @@ -269,6 +277,34 @@ bool IRac::isProtocolSupported(const decode_type_t protocol) { } } +#if SEND_AIRWELL +/// Send an Airwell A/C message with the supplied settings. +/// @param[in, out] ac A Ptr to an IRAirwellAc object to use. +/// @param[in] on The power setting. +/// @param[in] mode The operation mode setting. +/// @param[in] degrees The temperature setting in degrees. +/// @param[in] fan The speed setting for the fan. +void IRac::airwell(IRAirwellAc *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan) { + ac->begin(); + ac->setPowerToggle(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + // No Swing setting available. + // No Quiet setting available. + // No Light setting available. + // No Filter setting available. + // No Turbo setting available. + // No Economy setting available. + // No Clean setting available. + // No Beep setting available. + // No Sleep setting available. + ac->send(); +} +#endif // SEND_AIRWELL + #if SEND_AMCOR /// Send an Amcor A/C message with the supplied settings. /// @param[in, out] ac A Ptr to an IRAmcorAc object to use. @@ -1231,11 +1267,14 @@ void IRac::lg(IRLgAc *ac, const lg_ac_remote_model_t model, /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. /// @param[in] swingv The vertical swing setting. +/// @param[in] econo Run the device in economical mode. /// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, >= 0 is on. +/// @note On Danby A/C units, swingv controls the Ion Filter instead. void IRac::midea(IRMideaAC *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const int16_t sleep) { + const stdAc::swingv_t swingv, const bool econo, + const int16_t sleep) { ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); @@ -1246,6 +1285,7 @@ void IRac::midea(IRMideaAC *ac, // No Horizontal swing setting available. // No Quiet setting available. // No Turbo setting available. + ac->setEconoToggle(econo); // No Light setting available. // No Filter setting available. // No Clean setting available. @@ -1572,6 +1612,45 @@ void IRac::samsung(IRSamsungAc *ac, } #endif // SEND_SAMSUNG_AC +#if SEND_SANYO_AC +/// Send a Toshiba A/C message with the supplied settings. +/// @param[in, out] ac A Ptr to an IRSanyoAc object to use. +/// @param[in] on The power setting. +/// @param[in] mode The operation mode setting. +/// @param[in] degrees The temperature setting in degrees. +/// @param[in] fan The speed setting for the fan. +/// @param[in] swingv The vertical swing setting. +/// @param[in] beep Enable/Disable beeps when receiving IR messages. +/// @param[in] sleep Nr. of minutes for sleep mode. -1 is Off, > 0 is on. +void IRac::sanyo(IRSanyoAc *ac, + const bool on, const stdAc::opmode_t mode, + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, const bool beep, + const int16_t sleep) { + ac->begin(); + ac->setPower(on); + ac->setMode(ac->convertMode(mode)); + ac->setTemp(degrees); + ac->setFan(ac->convertFan(fan)); + ac->setSwingV(ac->convertSwingV(swingv)); + // No Horizontal swing setting available. + // No Quiet setting available. + // No Turbo setting available. + // No Econo setting available. + // No Light setting available. + // No Filter setting available. + // No Clean setting available. + ac->setBeep(beep); + ac->setSleep(sleep >= 0); // Sleep is either on/off, so convert to boolean. + // No Clock setting available. + + // Extra + ac->setSensor(true); // Set the A/C to use the temp sensor in the Unit/Wall. + ac->setSensorTemp(degrees); // Set the sensor temp to the desired temp. + ac->send(); +} +#endif // SEND_SANYO_AC + #if SEND_SHARP_AC /// Send a Sharp A/C message with the supplied settings. /// @note Multiple IR messages may be generated & sent. @@ -1703,18 +1782,26 @@ void IRac::teco(IRTecoAc *ac, /// @param[in] mode The operation mode setting. /// @param[in] degrees The temperature setting in degrees. /// @param[in] fan The speed setting for the fan. +/// @param[in] swingv The vertical swing setting. +/// @param[in] turbo Run the device in turbo/powerful mode. +/// @param[in] econo Run the device in economical mode. void IRac::toshiba(IRToshibaAC *ac, const bool on, const stdAc::opmode_t mode, - const float degrees, const stdAc::fanspeed_t fan) { + const float degrees, const stdAc::fanspeed_t fan, + const stdAc::swingv_t swingv, + const bool turbo, const bool econo) { ac->begin(); ac->setPower(on); ac->setMode(ac->convertMode(mode)); ac->setTemp(degrees); ac->setFan(ac->convertFan(fan)); - // No Vertical swing setting available. + // The API has no "step" option, so off is off, anything else is on. + ac->setSwing((swingv == stdAc::swingv_t::kOff) ? kToshibaAcSwingOff + : kToshibaAcSwingOn); // No Horizontal swing setting available. // No Quiet setting available. - // No Turbo setting available. + ac->setTurbo(turbo); + ac->setEcono(econo); // No Light setting available. // No Filter setting available. // No Clean setting available. @@ -1881,10 +1968,12 @@ stdAc::state_t IRac::handleToggles(const stdAc::state_t desired, case decode_type_t::ELECTRA_AC: result.light = desired.light ^ prev->light; break; + case decode_type_t::MIDEA: + result.econo = desired.econo ^ prev->econo; + // FALL THRU case decode_type_t::CORONA_AC: case decode_type_t::HITACHI_AC344: case decode_type_t::HITACHI_AC424: - case decode_type_t::MIDEA: case decode_type_t::SHARP_AC: if ((desired.swingv == stdAc::swingv_t::kOff) ^ (prev->swingv == stdAc::swingv_t::kOff)) // It changed, so toggle. @@ -1892,6 +1981,7 @@ stdAc::state_t IRac::handleToggles(const stdAc::state_t desired, else result.swingv = stdAc::swingv_t::kOff; // No change, so no toggle. break; + case decode_type_t::AIRWELL: case decode_type_t::DAIKIN64: case decode_type_t::WHIRLPOOL_AC: result.power = desired.power ^ prev->power; @@ -1959,6 +2049,14 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { stdAc::state_t send = this->handleToggles(this->cleanState(desired), prev); // Per vendor settings & setup. switch (send.protocol) { +#if SEND_AIRWELL + case AIRWELL: + { + IRAirwellAc ac(_pin, _inverted, _modulation); + airwell(&ac, send.power, send.mode, degC, send.fanspeed); + break; + } +#endif // SEND_AIRWELL #if SEND_AMCOR case AMCOR: { @@ -2210,7 +2308,7 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { { IRMideaAC ac(_pin, _inverted, _modulation); midea(&ac, send.power, send.mode, send.celsius, send.degrees, - send.fanspeed, send.swingv, send.sleep); + send.fanspeed, send.swingv, send.econo, send.sleep); break; } #endif // SEND_MIDEA @@ -2288,6 +2386,15 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { break; } #endif // SEND_SAMSUNG_AC +#if SEND_SANYO_AC + case SANYO_AC: + { + IRSanyoAc ac(_pin, _inverted, _modulation); + sanyo(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.beep, send.sleep); + break; + } +#endif // SEND_SANYO_AC #if SEND_SHARP_AC case SHARP_AC: { @@ -2321,7 +2428,8 @@ bool IRac::sendAc(const stdAc::state_t desired, const stdAc::state_t *prev) { case TOSHIBA_AC: { IRToshibaAC ac(_pin, _inverted, _modulation); - toshiba(&ac, send.power, send.mode, degC, send.fanspeed); + toshiba(&ac, send.power, send.mode, degC, send.fanspeed, send.swingv, + send.turbo, send.econo); break; } #endif // SEND_TOSHIBA_AC @@ -2715,16 +2823,23 @@ namespace IRAcUtils { /// An empty string if we can't. String resultAcToString(const decode_results * const result) { switch (result->decode_type) { +#if DECODE_AIRWELL + case decode_type_t::AIRWELL: { + IRAirwellAc ac(kGpioUnused); + ac.setRaw(result->value); // AIRWELL uses value instead of state. + return ac.toString(); + } +#endif // DECODE_AIRWELL #if DECODE_AMCOR case decode_type_t::AMCOR: { - IRAmcorAc ac(0); + IRAmcorAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_AMCOR #if DECODE_ARGO case decode_type_t::ARGO: { - IRArgoAC ac(0); + IRArgoAC ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } @@ -2738,49 +2853,49 @@ namespace IRAcUtils { #endif // DECODE_CARRIER_AC64 #if DECODE_DAIKIN case decode_type_t::DAIKIN: { - IRDaikinESP ac(0); + IRDaikinESP ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_DAIKIN #if DECODE_DAIKIN128 case decode_type_t::DAIKIN128: { - IRDaikin128 ac(0); + IRDaikin128 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_DAIKIN128 #if DECODE_DAIKIN152 case decode_type_t::DAIKIN152: { - IRDaikin152 ac(0); + IRDaikin152 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_DAIKIN152 #if DECODE_DAIKIN160 case decode_type_t::DAIKIN160: { - IRDaikin160 ac(0); + IRDaikin160 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_DAIKIN160 #if DECODE_DAIKIN176 case decode_type_t::DAIKIN176: { - IRDaikin176 ac(0); + IRDaikin176 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_DAIKIN160 #if DECODE_DAIKIN2 case decode_type_t::DAIKIN2: { - IRDaikin2 ac(0); + IRDaikin2 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_DAIKIN2 #if DECODE_DAIKIN216 case decode_type_t::DAIKIN216: { - IRDaikin216 ac(0); + IRDaikin216 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } @@ -2801,131 +2916,138 @@ namespace IRAcUtils { #endif // DECODE_DELONGHI_AC #if DECODE_ELECTRA_AC case decode_type_t::ELECTRA_AC: { - IRElectraAc ac(0); + IRElectraAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_ELECTRA_AC #if DECODE_FUJITSU_AC case decode_type_t::FUJITSU_AC: { - IRFujitsuAC ac(0); + IRFujitsuAC ac(kGpioUnused); ac.setRaw(result->state, result->bits / 8); return ac.toString(); } #endif // DECODE_FUJITSU_AC #if DECODE_KELVINATOR case decode_type_t::KELVINATOR: { - IRKelvinatorAC ac(0); + IRKelvinatorAC ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_KELVINATOR #if DECODE_MITSUBISHI_AC case decode_type_t::MITSUBISHI_AC: { - IRMitsubishiAC ac(0); + IRMitsubishiAC ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_MITSUBISHI_AC #if DECODE_MITSUBISHI112 case decode_type_t::MITSUBISHI112: { - IRMitsubishi112 ac(0); + IRMitsubishi112 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_MITSUBISHI112 #if DECODE_MITSUBISHI136 case decode_type_t::MITSUBISHI136: { - IRMitsubishi136 ac(0); + IRMitsubishi136 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_MITSUBISHI136 #if DECODE_MITSUBISHIHEAVY case decode_type_t::MITSUBISHI_HEAVY_88: { - IRMitsubishiHeavy88Ac ac(0); + IRMitsubishiHeavy88Ac ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } case decode_type_t::MITSUBISHI_HEAVY_152: { - IRMitsubishiHeavy152Ac ac(0); + IRMitsubishiHeavy152Ac ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_MITSUBISHIHEAVY #if DECODE_NEOCLIMA case decode_type_t::NEOCLIMA: { - IRNeoclimaAc ac(0); + IRNeoclimaAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_NEOCLIMA #if DECODE_TOSHIBA_AC case decode_type_t::TOSHIBA_AC: { - IRToshibaAC ac(0); + IRToshibaAC ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_TOSHIBA_AC #if DECODE_TROTEC case decode_type_t::TROTEC: { - IRTrotecESP ac(0); + IRTrotecESP ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_TROTEC #if DECODE_GOODWEATHER case decode_type_t::GOODWEATHER: { - IRGoodweatherAc ac(0); + IRGoodweatherAc ac(kGpioUnused); ac.setRaw(result->value); // Goodweather uses value instead of state. return ac.toString(); } #endif // DECODE_GOODWEATHER #if DECODE_GREE case decode_type_t::GREE: { - IRGreeAC ac(0); + IRGreeAC ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_GREE #if DECODE_MIDEA case decode_type_t::MIDEA: { - IRMideaAC ac(0); + IRMideaAC ac(kGpioUnused); ac.setRaw(result->value); // Midea uses value instead of state. return ac.toString(); } #endif // DECODE_MIDEA #if DECODE_HAIER_AC case decode_type_t::HAIER_AC: { - IRHaierAC ac(0); + IRHaierAC ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_HAIER_AC #if DECODE_HAIER_AC_YRW02 case decode_type_t::HAIER_AC_YRW02: { - IRHaierACYRW02 ac(0); + IRHaierACYRW02 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_HAIER_AC_YRW02 #if DECODE_SAMSUNG_AC case decode_type_t::SAMSUNG_AC: { - IRSamsungAc ac(0); + IRSamsungAc ac(kGpioUnused); ac.setRaw(result->state, result->bits / 8); return ac.toString(); } #endif // DECODE_SAMSUNG_AC +#if DECODE_SANYO_AC + case decode_type_t::SANYO_AC: { + IRSanyoAc ac(kGpioUnused); + ac.setRaw(result->state); + return ac.toString(); + } +#endif // DECODE_SANYO_AC #if DECODE_SHARP_AC case decode_type_t::SHARP_AC: { - IRSharpAc ac(0); + IRSharpAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_SHARP_AC #if DECODE_COOLIX case decode_type_t::COOLIX: { - IRCoolixAC ac(0); + IRCoolixAC ac(kGpioUnused); ac.on(); ac.setRaw(result->value); // Coolix uses value instead of state. return ac.toString(); @@ -2941,7 +3063,7 @@ namespace IRAcUtils { #if DECODE_PANASONIC_AC case decode_type_t::PANASONIC_AC: { if (result->bits > kPanasonicAcShortBits) { - IRPanasonicAc ac(0); + IRPanasonicAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } @@ -2950,7 +3072,7 @@ namespace IRAcUtils { #endif // DECODE_PANASONIC_AC #if DECODE_HITACHI_AC case decode_type_t::HITACHI_AC: { - IRHitachiAc ac(0); + IRHitachiAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } @@ -2971,35 +3093,35 @@ namespace IRAcUtils { #endif // DECODE_HITACHI_AC344 #if DECODE_HITACHI_AC424 case decode_type_t::HITACHI_AC424: { - IRHitachiAc424 ac(0); + IRHitachiAc424 ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_HITACHI_AC424 #if DECODE_WHIRLPOOL_AC case decode_type_t::WHIRLPOOL_AC: { - IRWhirlpoolAc ac(0); + IRWhirlpoolAc ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } #endif // DECODE_WHIRLPOOL_AC #if DECODE_VESTEL_AC case decode_type_t::VESTEL_AC: { - IRVestelAc ac(0); + IRVestelAc ac(kGpioUnused); ac.setRaw(result->value); // Like Coolix, use value instead of state. return ac.toString(); } #endif // DECODE_VESTEL_AC #if DECODE_TECO case decode_type_t::TECO: { - IRTecoAc ac(0); + IRTecoAc ac(kGpioUnused); ac.setRaw(result->value); // Like Coolix, use value instead of state. return ac.toString(); } #endif // DECODE_TECO #if DECODE_TCL112AC case decode_type_t::TCL112AC: { - IRTcl112Ac ac(0); + IRTcl112Ac ac(kGpioUnused); ac.setRaw(result->state); return ac.toString(); } @@ -3007,7 +3129,7 @@ namespace IRAcUtils { #if DECODE_LG case decode_type_t::LG: case decode_type_t::LG2: { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setRaw(result->value); // Like Coolix, use value instead of state. switch (result->decode_type) { case decode_type_t::LG2: @@ -3040,6 +3162,14 @@ namespace IRAcUtils { ) { if (decode == NULL || result == NULL) return false; // Safety check. switch (decode->decode_type) { +#if DECODE_AIRWELL + case decode_type_t::AIRWELL: { + IRAirwellAc ac(kGpioUnused); + ac.setRaw(decode->value); // Uses value instead of state. + *result = ac.toCommon(); + break; + } +#endif // DECODE_AIRWELL #if DECODE_AMCOR case decode_type_t::AMCOR: { IRAmcorAc ac(kGpioUnused); @@ -3090,7 +3220,7 @@ namespace IRAcUtils { #endif // DECODE_DAIKIN #if DECODE_DAIKIN128 case decode_type_t::DAIKIN128: { - IRDaikin128 ac(0); + IRDaikin128 ac(kGpioUnused); ac.setRaw(decode->state); *result = ac.toCommon(); break; @@ -3098,7 +3228,7 @@ namespace IRAcUtils { #endif // DECODE_DAIKIN128 #if DECODE_DAIKIN152 case decode_type_t::DAIKIN152: { - IRDaikin152 ac(0); + IRDaikin152 ac(kGpioUnused); ac.setRaw(decode->state); *result = ac.toCommon(); break; @@ -3327,6 +3457,14 @@ namespace IRAcUtils { break; } #endif // DECODE_SAMSUNG_AC +#if DECODE_SANYO_AC + case decode_type_t::SANYO_AC: { + IRSanyoAc ac(kGpioUnused); + ac.setRaw(decode->state); + *result = ac.toCommon(); + break; + } +#endif // DECODE_SANYO_AC #if DECODE_SHARP_AC case decode_type_t::SHARP_AC: { IRSharpAc ac(kGpioUnused); diff --git a/lib/IRremoteESP8266-2.7.8/src/IRac.h b/lib/IRremoteESP8266-2.7.8/src/IRac.h index 01365a180..5721f2bd6 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRac.h +++ b/lib/IRremoteESP8266-2.7.8/src/IRac.h @@ -7,6 +7,7 @@ #include #endif #include "IRremoteESP8266.h" +#include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" #include "ir_Carrier.h" @@ -28,6 +29,7 @@ #include "ir_Neoclima.h" #include "ir_Panasonic.h" #include "ir_Samsung.h" +#include "ir_Sanyo.h" #include "ir_Sharp.h" #include "ir_Tcl.h" #include "ir_Teco.h" @@ -37,9 +39,10 @@ #include "ir_Whirlpool.h" // Constants -const int8_t kGpioUnused = -1; +const int8_t kGpioUnused = -1; ///< A placeholder for not using an actual GPIO. // Class +/// A universal/common/generic interface for controling supported A/Cs. class IRac { public: explicit IRac(const uint16_t pin, const bool inverted = false, @@ -93,10 +96,15 @@ class IRac { private: #endif - uint16_t _pin; - bool _inverted; - bool _modulation; - stdAc::state_t _prev; // The state we expect the device to currently be in. + uint16_t _pin; ///< The GPIO to use to transmit messages from. + bool _inverted; ///< IR LED is lit when GPIO is LOW (true) or HIGH (false)? + bool _modulation; ///< Is frequency modulation to be used? + stdAc::state_t _prev; ///< The state we expect the device to currently be in. +#if SEND_AIRWELL + void airwell(IRAirwellAc *ac, + const bool on, const stdAc::opmode_t mode, const float degrees, + const stdAc::fanspeed_t fan); +#endif // SEND_AIRWELL #if SEND_AMCOR void amcor(IRAmcorAc *ac, const bool on, const stdAc::opmode_t mode, const float degrees, @@ -286,7 +294,8 @@ void electra(IRElectraAc *ac, void midea(IRMideaAC *ac, const bool on, const stdAc::opmode_t mode, const bool celsius, const float degrees, const stdAc::fanspeed_t fan, - const stdAc::swingv_t swingv, const int16_t sleep = -1); + const stdAc::swingv_t swingv, const bool econo, + const int16_t sleep = -1); #endif // SEND_MIDEA #if SEND_MITSUBISHI_AC void mitsubishi(IRMitsubishiAC *ac, @@ -350,6 +359,12 @@ void electra(IRElectraAc *ac, const bool beep, const bool prevpower = true, const bool forcepower = true); #endif // SEND_SAMSUNG_AC +#if SEND_SANYO_AC + void sanyo(IRSanyoAc *ac, + const bool on, const stdAc::opmode_t mode, const float degrees, + const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, + const bool beep, const int16_t sleep = -1); +#endif // SEND_SANYO_AC #if SEND_SHARP_AC void sharp(IRSharpAc *ac, const bool on, const bool prev_power, const stdAc::opmode_t mode, @@ -374,7 +389,8 @@ void electra(IRElectraAc *ac, #if SEND_TOSHIBA_AC void toshiba(IRToshibaAC *ac, const bool on, const stdAc::opmode_t mode, const float degrees, - const stdAc::fanspeed_t fan); + const stdAc::fanspeed_t fan, const stdAc::swingv_t swingv, + const bool turbo, const bool econo); #endif // SEND_TOSHIBA_AC #if SEND_TROTEC void trotec(IRTrotecESP *ac, @@ -401,6 +417,7 @@ static stdAc::state_t handleToggles(const stdAc::state_t desired, const stdAc::state_t *prev = NULL); }; // IRac class +/// Common functions for use with all A/Cs supported by the IRac class. namespace IRAcUtils { String resultAcToString(const decode_results * const results); bool decodeToState(const decode_results *decode, stdAc::state_t *result, diff --git a/lib/IRremoteESP8266-2.7.8/src/IRrecv.cpp b/lib/IRremoteESP8266-2.7.8/src/IRrecv.cpp index efddcc17c..24ea0b021 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRrecv.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/IRrecv.cpp @@ -614,8 +614,12 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, if (decodeDaikin216(results, offset)) return true; #endif #if DECODE_TOSHIBA_AC - DPRINTLN("Attempting Toshiba AC decode"); + DPRINTLN("Attempting Toshiba AC 72bit decode"); if (decodeToshibaAC(results, offset)) return true; + DPRINTLN("Attempting Toshiba AC 80bit decode"); + if (decodeToshibaAC(results, offset, kToshibaACBitsLong)) return true; + DPRINTLN("Attempting Toshiba AC 56bit decode"); + if (decodeToshibaAC(results, offset, kToshibaACBitsShort)) return true; #endif #if DECODE_MIDEA DPRINTLN("Attempting Midea decode"); @@ -852,6 +856,10 @@ bool IRrecv::decode(decode_results *results, irparams_t *save, DPRINTLN("Attempting Zepeal decode"); if (decodeZepeal(results, offset)) return true; #endif // DECODE_ZEPEAL +#if DECODE_SANYO_AC + DPRINTLN("Attempting Sanyo AC decode"); + if (decodeSanyoAc(results, offset)) return true; +#endif // DECODE_SANYO_AC // Typically new protocols are added above this line. } #if DECODE_HASH diff --git a/lib/IRremoteESP8266-2.7.8/src/IRrecv.h b/lib/IRremoteESP8266-2.7.8/src/IRrecv.h index 36da8df1b..62cdeed6b 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRrecv.h +++ b/lib/IRremoteESP8266-2.7.8/src/IRrecv.h @@ -283,8 +283,14 @@ class IRrecv { bool decodeSanyoLC7461(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kSanyoLC7461Bits, - bool strict = true); + const bool strict = true); #endif +#if DECODE_SANYO_AC + bool decodeSanyoAc(decode_results *results, + uint16_t offset = kStartOffset, + const uint16_t nbits = kSanyoAcBits, + const bool strict = true); +#endif // DECODE_SANYO_AC #if DECODE_MITSUBISHI bool decodeMitsubishi(decode_results *results, uint16_t offset = kStartOffset, const uint16_t nbits = kMitsubishiBits, @@ -469,7 +475,7 @@ class IRrecv { #endif #if DECODE_TOSHIBA_AC bool decodeToshibaAC(decode_results *results, uint16_t offset = kStartOffset, - const uint16_t nbytes = kToshibaACBits, + const uint16_t nbits = kToshibaACBits, const bool strict = true); #endif #if DECODE_TROTEC diff --git a/lib/IRremoteESP8266-2.7.8/src/IRremoteESP8266.h b/lib/IRremoteESP8266-2.7.8/src/IRremoteESP8266.h index 4490baa3b..007645073 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRremoteESP8266.h +++ b/lib/IRremoteESP8266-2.7.8/src/IRremoteESP8266.h @@ -201,6 +201,13 @@ #define SEND_SANYO _IR_ENABLE_DEFAULT_ #endif // SEND_SANYO +#ifndef DECODE_SANYO_AC +#define DECODE_SANYO_AC _IR_ENABLE_DEFAULT_ +#endif // DECODE_SANYO_AC +#ifndef SEND_SANYO_AC +#define SEND_SANYO_AC _IR_ENABLE_DEFAULT_ +#endif // SEND_SANYO_AC + #ifndef DECODE_MITSUBISHI #define DECODE_MITSUBISHI _IR_ENABLE_DEFAULT_ #endif // DECODE_MITSUBISHI @@ -674,7 +681,7 @@ DECODE_NEOCLIMA || DECODE_DAIKIN176 || DECODE_DAIKIN128 || \ DECODE_AMCOR || DECODE_DAIKIN152 || DECODE_MITSUBISHI136 || \ DECODE_MITSUBISHI112 || DECODE_HITACHI_AC424 || DECODE_HITACHI_AC3 || \ - DECODE_HITACHI_AC344 || DECODE_CORONA_AC) + DECODE_HITACHI_AC344 || DECODE_CORONA_AC || DECODE_SANYO_AC) // Add any DECODE to the above if it uses result->state (see kStateSizeMax) // you might also want to add the protocol to hasACState function #define DECODE_AC true // We need some common infrastructure for decoding A/Cs. @@ -802,8 +809,9 @@ enum decode_type_t { CORONA_AC, MIDEA24, ZEPEAL, + SANYO_AC, // Add new entries before this one, and update it to point to the last entry. - kLastDecodeType = ZEPEAL, + kLastDecodeType = SANYO_AC, }; // Message lengths & required repeat values @@ -971,6 +979,8 @@ const uint16_t kSamsungAcBits = kSamsungAcStateLength * 8; const uint16_t kSamsungAcExtendedStateLength = 21; const uint16_t kSamsungAcExtendedBits = kSamsungAcExtendedStateLength * 8; const uint16_t kSamsungAcDefaultRepeat = kNoRepeat; +const uint16_t kSanyoAcStateLength = 9; +const uint16_t kSanyoAcBits = kSanyoAcStateLength * 8; const uint16_t kSanyoSA8650BBits = 12; const uint16_t kSanyoLC7461AddressBits = 13; const uint16_t kSanyoLC7461CommandBits = 8; @@ -999,6 +1009,10 @@ const uint16_t kTecoDefaultRepeat = kNoRepeat; const uint16_t kToshibaACStateLength = 9; const uint16_t kToshibaACBits = kToshibaACStateLength * 8; const uint16_t kToshibaACMinRepeat = kSingleRepeat; +const uint16_t kToshibaACStateLengthShort = kToshibaACStateLength - 2; +const uint16_t kToshibaACBitsShort = kToshibaACStateLengthShort * 8; +const uint16_t kToshibaACStateLengthLong = kToshibaACStateLength + 1; +const uint16_t kToshibaACBitsLong = kToshibaACStateLengthLong * 8; const uint16_t kTrotecStateLength = 9; const uint16_t kTrotecBits = kTrotecStateLength * 8; const uint16_t kTrotecDefaultRepeat = kNoRepeat; diff --git a/lib/IRremoteESP8266-2.7.8/src/IRsend.cpp b/lib/IRremoteESP8266-2.7.8/src/IRsend.cpp index d3e097839..e3537381f 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRsend.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/IRsend.cpp @@ -721,6 +721,8 @@ uint16_t IRsend::defaultBits(const decode_type_t protocol) { return kNeoclimaBits; case SAMSUNG_AC: return kSamsungAcBits; + case SANYO_AC: + return kSanyoAcBits; case SHARP_AC: return kSharpAcBits; case TCL112AC: @@ -1152,6 +1154,11 @@ bool IRsend::send(const decode_type_t type, const uint8_t *state, sendSamsungAC(state, nbytes); break; #endif // SEND_SAMSUNG_AC +#if SEND_SANYO_AC + case SANYO_AC: + sendSanyoAc(state, nbytes); + break; +#endif // SEND_SANYO_AC #if SEND_SHARP_AC case SHARP_AC: sendSharpAc(state, nbytes); diff --git a/lib/IRremoteESP8266-2.7.8/src/IRsend.h b/lib/IRremoteESP8266-2.7.8/src/IRsend.h index fe206583f..0b237ecc0 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRsend.h +++ b/lib/IRremoteESP8266-2.7.8/src/IRsend.h @@ -294,6 +294,11 @@ class IRsend { const uint16_t nbits = kSanyoLC7461Bits, const uint16_t repeat = kNoRepeat); #endif +#if SEND_SANYO_AC + void sendSanyoAc(const uint8_t *data, + const uint16_t nbytes = kSanyoAcStateLength, + const uint16_t repeat = kNoRepeat); +#endif // SEND_SANYO_AC #if SEND_DISH // sendDISH() should typically be called with repeat=3 as DISH devices // expect the code to be sent at least 4 times. (code + 3 repeats = 4 codes) @@ -461,7 +466,7 @@ class IRsend { uint16_t repeat = kNoRepeat); #endif #if SEND_TOSHIBA_AC - void sendToshibaAC(const unsigned char data[], + void sendToshibaAC(const uint8_t data[], const uint16_t nbytes = kToshibaACStateLength, const uint16_t repeat = kToshibaACMinRepeat); #endif diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtext.cpp b/lib/IRremoteESP8266-2.7.8/src/IRtext.cpp index 7af2ffd0b..80e39b0a1 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRtext.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/IRtext.cpp @@ -130,6 +130,7 @@ const PROGMEM char* kTopStr = D_STR_TOP; ///< "Top" const PROGMEM char* kBottomStr = D_STR_BOTTOM; ///< "Bottom" // Compound words/phrases/descriptions from pre-defined words. +const PROGMEM char* kEconoToggleStr = D_STR_ECONOTOGGLE; ///< "Econo Toggle" const PROGMEM char* kEyeAutoStr = D_STR_EYEAUTO; ///< "Eye Auto" const PROGMEM char* kLightToggleStr = D_STR_LIGHTTOGGLE; ///< "Light Toggle" const PROGMEM char* kOutsideQuietStr = D_STR_OUTSIDEQUIET; ///< "Outside Quiet" @@ -264,5 +265,6 @@ const PROGMEM char *kAllProtocolNamesStr = D_STR_CORONA_AC "\x0" D_STR_MIDEA24 "\x0" D_STR_ZEPEAL "\x0" + D_STR_SANYO_AC "\x0" ///< New protocol strings should be added just above this line. "\x0"; ///< This string requires double null termination. diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtext.h b/lib/IRremoteESP8266-2.7.8/src/IRtext.h index 57ba2858b..73b42edc1 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRtext.h +++ b/lib/IRremoteESP8266-2.7.8/src/IRtext.h @@ -45,6 +45,7 @@ extern const char* kDisplayTempStr; extern const char* kDownStr; extern const char* kDryStr; extern const char* kEconoStr; +extern const char* kEconoToggleStr; extern const char* kEyeAutoStr; extern const char* kEyeStr; extern const char* kFalseStr; @@ -104,10 +105,10 @@ extern const char* kOnStr; extern const char* kOnTimerStr; extern const char* kOutsideQuietStr; extern const char* kOutsideStr; +extern const char* kPowerButtonStr; extern const char* kPowerfulStr; extern const char* kPowerStr; extern const char* kPowerToggleStr; -extern const char* kPowerButtonStr; extern const char* kPreviousPowerStr; extern const char* kProtocolStr; extern const char* kPurifyStr; diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtimer.cpp b/lib/IRremoteESP8266-2.7.8/src/IRtimer.cpp index edd98a2d7..e1f098b28 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRtimer.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/IRtimer.cpp @@ -14,7 +14,7 @@ uint32_t _TimerMs_unittest_now = 0; /// Class constructor. IRtimer::IRtimer() { reset(); } -/// Resets the IRtimer object. +/// Resets the IRtimer object. I.e. The counter starts again from now. void IRtimer::reset() { #ifndef UNIT_TEST start = micros(); @@ -47,7 +47,7 @@ void IRtimer::add(uint32_t usecs) { _IRtimer_unittest_now += usecs; } /// Class constructor. TimerMs::TimerMs() { reset(); } -/// Resets the TimerMs object. +/// Resets the TimerMs object. I.e. The counter starts again from now. void TimerMs::reset() { #ifndef UNIT_TEST start = millis(); diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtimer.h b/lib/IRremoteESP8266-2.7.8/src/IRtimer.h index 1a2215fd5..659819d8f 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRtimer.h +++ b/lib/IRremoteESP8266-2.7.8/src/IRtimer.h @@ -8,7 +8,7 @@ // Classes -/// This class performs a simple timer in useconds since instantiated. +/// This class offers a simple counter in micro-seconds since instantiated. /// @note Handles when the system timer wraps around (once). class IRtimer { public: @@ -20,10 +20,10 @@ class IRtimer { #endif // UNIT_TEST private: - uint32_t start; + uint32_t start; ///< Time in uSeconds when the class was instantiated/reset. }; -/// This class performs a simple timer in milli-seoncds since instantiated. +/// This class offers a simple counter in milli-seconds since instantiated. /// @note Handles when the system timer wraps around (once). class TimerMs { public: @@ -35,6 +35,6 @@ class TimerMs { #endif // UNIT_TEST private: - uint32_t start; + uint32_t start; ///< Time in mSeconds when the class was instantiated/reset. }; #endif // IRTIMER_H_ diff --git a/lib/IRremoteESP8266-2.7.8/src/IRutils.cpp b/lib/IRremoteESP8266-2.7.8/src/IRutils.cpp index 9393fcf2d..beec2fbfb 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRutils.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/IRutils.cpp @@ -161,6 +161,7 @@ bool hasACState(const decode_type_t protocol) { case NEOCLIMA: case PANASONIC_AC: case SAMSUNG_AC: + case SANYO_AC: case SHARP_AC: case TCL112AC: case TOSHIBA_AC: @@ -915,4 +916,35 @@ namespace irutils { // Merge in the data. *dst |= ((data & mask) << offset); } + + /// Create byte pairs where the second byte of the pair is a bit + /// inverted/flipped copy of the first/previous byte of the pair. + /// @param[in,out] ptr A pointer to the start of array to modify. + /// @param[in] length The byte size of the array. + /// @note A length of `<= 1` will do nothing. + /// @return A ptr to the modified array. + uint8_t * invertBytePairs(uint8_t *ptr, const uint16_t length) { + for (uint16_t i = 1; i < length; i += 2) { + // Code done this way to avoid a compiler warning bug. + uint8_t inv = ~*(ptr + i - 1); + *(ptr + i) = inv; + } + return ptr; + } + + /// Check an array to see if every second byte of a pair is a bit + /// inverted/flipped copy of the first/previous byte of the pair. + /// @param[in] ptr A pointer to the start of array to check. + /// @param[in] length The byte size of the array. + /// @note A length of `<= 1` will always return true. + /// @return true, if every second byte is inverted. Otherwise false. + bool checkInvertedBytePairs(const uint8_t * const ptr, + const uint16_t length) { + for (uint16_t i = 1; i < length; i += 2) { + // Code done this way to avoid a compiler warning bug. + uint8_t inv = ~*(ptr + i - 1); + if (*(ptr + i) != inv) return false; + } + return true; + } } // namespace irutils diff --git a/lib/IRremoteESP8266-2.7.8/src/IRutils.h b/lib/IRremoteESP8266-2.7.8/src/IRutils.h index 3c865dfcf..a3320ae93 100644 --- a/lib/IRremoteESP8266-2.7.8/src/IRutils.h +++ b/lib/IRremoteESP8266-2.7.8/src/IRutils.h @@ -107,5 +107,7 @@ namespace irutils { const uint32_t data); void setBits(uint64_t * const dst, const uint8_t offset, const uint8_t nbits, const uint64_t data); + uint8_t * invertBytePairs(uint8_t *ptr, const uint16_t length); + bool checkInvertedBytePairs(const uint8_t * const ptr, const uint16_t length); } // namespace irutils #endif // IRUTILS_H_ diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.cpp index 2bf0a2db8..106e9c7bf 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.cpp @@ -1,23 +1,28 @@ // Copyright 2020 David Conran - +#include "ir_Airwell.h" +#include #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" +#include "IRutils.h" /// @file /// @brief Airwell "Manchester code" based protocol. /// Some other Airwell products use the COOLIX protocol. -// Supports: -// Brand: Airwell, Model: RC08W remote -// Brand: Airwell, Model: RC04 remote -// Brand: Airwell, Model: DLS 21 DCI R410 AW A/C - const uint8_t kAirwellOverhead = 4; const uint16_t kAirwellHalfClockPeriod = 950; // uSeconds const uint16_t kAirwellHdrMark = 3 * kAirwellHalfClockPeriod; // uSeconds const uint16_t kAirwellHdrSpace = 3 * kAirwellHalfClockPeriod; // uSeconds const uint16_t kAirwellFooterMark = 5 * kAirwellHalfClockPeriod; // uSeconds +using irutils::addBoolToString; +using irutils::addModeToString; +using irutils::addFanToString; +using irutils::addTempToString; +using irutils::setBit; +using irutils::setBits; + #if SEND_AIRWELL /// Send an Airwell Manchester Code formatted message. /// Status: BETA / Appears to be working. @@ -74,3 +79,203 @@ bool IRrecv::decodeAirwell(decode_results *results, uint16_t offset, return true; } #endif + +/// Class constructor +/// @param[in] pin GPIO to be used when sending. +/// @param[in] inverted Is the output signal to be inverted? +/// @param[in] use_modulation Is frequency modulation to be used? +IRAirwellAc::IRAirwellAc(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { stateReset(); } + +/// Set up hardware to be able to send a message. +void IRAirwellAc::begin(void) { _irsend.begin(); } + +/// Get the raw state of the object, suitable to be sent with the appropriate +/// IRsend object method. +/// @return A copy of the internal state. +uint64_t IRAirwellAc::getRaw(void) { + return remote_state; +} + +/// Set the raw state of the object. +/// @param[in] state The raw state from the native IR message. +void IRAirwellAc::setRaw(const uint64_t state) { + remote_state = state; +} + +#if SEND_AIRWELL +/// Send the current internal state as an IR message. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRAirwellAc::send(const uint16_t repeat) { + _irsend.sendAirwell(getRaw(), kAirwellBits, repeat); +} +#endif // SEND_AIRWELL + +/// Reset the internals of the object to a known good state. +void IRAirwellAc::stateReset(void) { + remote_state = kAirwellKnownGoodState; +} + +/// Turn on/off the Power Airwell setting. +/// @param[in] on The desired setting state. +void IRAirwellAc::setPowerToggle(const bool on) { + setBit(&remote_state, kAirwellPowerToggleBit, on); +} + +/// Get the power toggle setting from the internal state. +/// @return A boolean indicating the setting. +bool IRAirwellAc::getPowerToggle(void) { + return GETBIT64(remote_state, kAirwellPowerToggleBit); +} + +/// Get the current operation mode setting. +/// @return The current operation mode. +uint8_t IRAirwellAc::getMode(void) { + return GETBITS64(remote_state, kAirwellModeOffset, kAirwellModeSize); +} + +/// Set the desired operation mode. +/// @param[in] mode The desired operation mode. +void IRAirwellAc::setMode(const uint8_t mode) { + switch (mode) { + case kAirwellFan: + case kAirwellCool: + case kAirwellHeat: + case kAirwellDry: + case kAirwellAuto: + setBits(&remote_state, kAirwellModeOffset, kAirwellModeSize, mode); + break; + default: + setMode(kAirwellAuto); + } + setFan(getFan()); // Ensure the fan is at the correct speed for the new mode. +} + +/// Convert a stdAc::opmode_t enum into its native mode. +/// @param[in] mode The enum to be converted. +/// @return The native equivilant of the enum. +uint8_t IRAirwellAc::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kAirwellCool; + case stdAc::opmode_t::kHeat: return kAirwellHeat; + case stdAc::opmode_t::kDry: return kAirwellDry; + case stdAc::opmode_t::kFan: return kAirwellFan; + default: return kAirwellAuto; + } +} + +/// Convert a native mode into its stdAc equivilant. +/// @param[in] mode The native setting to be converted. +/// @return The stdAc equivilant of the native setting. +stdAc::opmode_t IRAirwellAc::toCommonMode(const uint8_t mode) { + switch (mode) { + case kAirwellCool: return stdAc::opmode_t::kCool; + case kAirwellHeat: return stdAc::opmode_t::kHeat; + case kAirwellDry: return stdAc::opmode_t::kDry; + case kAirwellFan: return stdAc::opmode_t::kFan; + default: return stdAc::opmode_t::kAuto; + } +} + +/// Set the speed of the fan. +/// @param[in] speed The desired setting. +/// @note The speed is locked to Low when in Dry mode. +void IRAirwellAc::setFan(const uint8_t speed) { + setBits(&remote_state, kAirwellFanOffset, kAirwellFanSize, + (getMode() == kAirwellDry) ? kAirwellFanLow + : std::min(speed, kAirwellFanAuto)); +} + +/// Get the current fan speed setting. +/// @return The current fan speed. +uint8_t IRAirwellAc::getFan(void) { + return GETBITS64(remote_state, kAirwellFanOffset, kAirwellFanSize); +} + +/// Convert a stdAc::fanspeed_t enum into it's native speed. +/// @param[in] speed The enum to be converted. +/// @return The native equivilant of the enum. +uint8_t IRAirwellAc::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kLow: + return kAirwellFanLow; + case stdAc::fanspeed_t::kMedium: + return kAirwellFanMedium; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: + return kAirwellFanHigh; + default: + return kAirwellFanAuto; + } +} + +/// Convert a native fan speed into its stdAc equivilant. +/// @param[in] speed The native setting to be converted. +/// @return The stdAc equivilant of the native setting. +stdAc::fanspeed_t IRAirwellAc::toCommonFanSpeed(const uint8_t speed) { + switch (speed) { + case kAirwellFanHigh: return stdAc::fanspeed_t::kMax; + case kAirwellFanMedium: return stdAc::fanspeed_t::kMedium; + case kAirwellFanLow: return stdAc::fanspeed_t::kMin; + default: return stdAc::fanspeed_t::kAuto; + } +} + +/// Set the temperature. +/// @param[in] degrees The temperature in degrees celsius. +void IRAirwellAc::setTemp(const uint8_t degrees) { + uint8_t temp = std::max(kAirwellMinTemp, degrees); + temp = std::min(kAirwellMaxTemp, temp); + setBits(&remote_state, kAirwellTempOffset, kAirwellTempSize, + temp - kAirwellMinTemp + 1); +} + +/// Get the current temperature setting. +/// @return Get current setting for temp. in degrees celsius. +uint8_t IRAirwellAc::getTemp(void) { + return GETBITS64(remote_state, kAirwellTempOffset, + kAirwellTempSize) + kAirwellMinTemp - 1; +} + +/// Convert the current internal state into its stdAc::state_t equivilant. +/// @return The stdAc equivilant of the native settings. +stdAc::state_t IRAirwellAc::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::AIRWELL; + result.power = getPowerToggle(); + result.mode = toCommonMode(getMode()); + result.celsius = true; + result.degrees = getTemp(); + result.fanspeed = toCommonFanSpeed(getFan()); + // Not supported. + result.model = -1; + result.turbo = false; + result.swingv = stdAc::swingv_t::kOff; + result.swingh = stdAc::swingh_t::kOff; + result.light = false; + result.filter = false; + result.econo = false; + result.quiet = false; + result.clean = false; + result.beep = false; + result.sleep = -1; + result.clock = -1; + return result; +} + +/// Convert the current internal state into a human readable string. +/// @return A human readable string. +String IRAirwellAc::toString(void) { + String result = ""; + result.reserve(70); // Reserve some heap for the string to reduce fragging. + result += addBoolToString(getPowerToggle(), kPowerToggleStr, false); + result += addModeToString(getMode(), kAirwellAuto, kAirwellCool, + kAirwellHeat, kAirwellDry, kAirwellFan); + result += addFanToString(getFan(), kAirwellFanHigh, kAirwellFanLow, + kAirwellFanAuto, kAirwellFanAuto, + kAirwellFanMedium); + result += addTempToString(getTemp()); + return result; +} diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.h b/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.h new file mode 100644 index 000000000..3ffbd21c7 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.h @@ -0,0 +1,97 @@ +// Copyright 2020 David Conran + +/// @file +/// @brief Airwell "Manchester code" based protocol. +/// Some other Airwell products use the COOLIX protocol. + +// Supports: +// Brand: Airwell, Model: RC08W remote +// Brand: Airwell, Model: RC04 remote +// Brand: Airwell, Model: DLS 21 DCI R410 AW A/C + +#ifndef IR_AIRWELL_H_ +#define IR_AIRWELL_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifndef UNIT_TEST +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + + +// Constants +const uint64_t kAirwellKnownGoodState = 0x140500002; // Mode Fan, Speed 1, 25C +// Temperature +const uint8_t kAirwellMinTemp = 16; // Celsius +const uint8_t kAirwellMaxTemp = 30; // Celsius +const uint8_t kAirwellTempSize = 4; // Bits +const uint8_t kAirwellTempOffset = 19; // 0b1111 << 19 +// Fan +const uint8_t kAirwellFanSize = 2; // Bits +const uint8_t kAirwellFanOffset = 28; // 0b11 << 28 +const uint8_t kAirwellFanLow = 0; // 0b00 +const uint8_t kAirwellFanMedium = 1; // 0b01 +const uint8_t kAirwellFanHigh = 2; // 0b10 +const uint8_t kAirwellFanAuto = 3; // 0b11 +// Modes +const uint8_t kAirwellModeSize = 3; // Bits +const uint8_t kAirwellModeOffset = 30; // 0b111 << 30 +const uint8_t kAirwellCool = 1; // 0b001 +const uint8_t kAirwellHeat = 2; // 0b010 +const uint8_t kAirwellAuto = 3; // 0b011 +const uint8_t kAirwellDry = 4; // 0b100 +const uint8_t kAirwellFan = 5; // 0b101 +// Power +const uint8_t kAirwellPowerToggleBit = 33; // 0b1 << 33 + + +// Classes +/// Class for handling detailed Airwell A/C messages. +class IRAirwellAc { + public: + explicit IRAirwellAc(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + void stateReset(); +#if SEND_AIRWELL + void send(const uint16_t repeat = kAirwellMinRepeats); + /// Run the calibration to calculate uSec timing offsets for this platform. + /// @return The uSec timing offset needed per modulation of the IR Led. + /// @note This will produce a 65ms IR signal pulse at 38kHz. + /// Only ever needs to be run once per object instantiation, if at all. + int8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_AIRWELL + void begin(); + void setPowerToggle(const bool on); + bool getPowerToggle(); + void setTemp(const uint8_t temp); + uint8_t getTemp(); + void setFan(const uint8_t speed); + uint8_t getFan(); + void setMode(const uint8_t mode); + uint8_t getMode(); + uint64_t getRaw(); + void setRaw(const uint64_t state); + uint8_t convertMode(const stdAc::opmode_t mode); + uint8_t convertFan(const stdAc::fanspeed_t speed); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + stdAc::state_t toCommon(void); + String toString(); +#ifndef UNIT_TEST + + private: + IRsend _irsend; ///< Instance of the IR send class +#else + /// @cond IGNORE + IRsendTest _irsend; ///< Instance of the testing IR send class + /// @endcond +#endif + uint64_t remote_state; // The state of the IR remote in native IR code form. + void checksum(void); +}; +#endif // IR_AIRWELL_H_ diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Daikin.h b/lib/IRremoteESP8266-2.7.8/src/ir_Daikin.h index 8c11dfb9f..35e62302b 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Daikin.h +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Daikin.h @@ -598,7 +598,7 @@ class IRDaikinESP { }; /// Class for handling detailed Daikin 312-bit A/C messages. -/// Code by crankyoldgit, Reverse engineering analysis by sheppy99 +/// @note Code by crankyoldgit, Reverse engineering analysis by sheppy99 class IRDaikin2 { public: explicit IRDaikin2(const uint16_t pin, const bool inverted = false, @@ -859,8 +859,7 @@ class IRDaikin176 { }; /// Class for handling detailed Daikin 128-bit A/C messages. -/// Code by crankyoldgit. -/// Analysis by Daniel Vena +/// @note Code by crankyoldgit. Analysis by Daniel Vena class IRDaikin128 { public: explicit IRDaikin128(const uint16_t pin, const bool inverted = false, diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.cpp index 368f9995a..68d562fce 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.cpp @@ -52,6 +52,8 @@ using irutils::addModeToString; using irutils::addModelToString; using irutils::addFanToString; using irutils::addTempToString; +using irutils::checkInvertedBytePairs; +using irutils::invertBytePairs; using irutils::minsToString; using irutils::setBit; using irutils::setBits; @@ -1047,8 +1049,7 @@ void IRHitachiAc424::stateReset(void) { /// Update the internal consistency check for the protocol. void IRHitachiAc424::setInvertedStates(void) { - for (uint8_t i = 3; i < kHitachiAc424StateLength - 1; i += 2) - remote_state[i + 1] = ~remote_state[i]; + invertBytePairs(remote_state + 3, kHitachiAc424StateLength - 3); } /// Set up hardware to be able to send a message. @@ -1402,8 +1403,7 @@ void IRHitachiAc3::stateReset(void) { /// @param[in] length The size of the state array. /// @note This is this protocols integrity check. void IRHitachiAc3::setInvertedStates(const uint16_t length) { - for (uint8_t i = 3; i < length - 1; i += 2) - remote_state[i + 1] = ~remote_state[i]; + if (length > 3) invertBytePairs(remote_state + 3, length - 3); } /// Check if every second byte of the state, after the fixed header @@ -1413,9 +1413,7 @@ void IRHitachiAc3::setInvertedStates(const uint16_t length) { /// @note This is this protocols integrity check. bool IRHitachiAc3::hasInvertedStates(const uint8_t state[], const uint16_t length) { - for (uint8_t i = 3; i < length - 1; i += 2) - if ((state[i + 1] ^ state[i]) != 0xFF) return false; - return true; + return (length <= 3 || checkInvertedBytePairs(state + 3, length - 3)); } /// Set up hardware to be able to send a message. diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_LG.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_LG.cpp index 65fe91883..40b141176 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_LG.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_LG.cpp @@ -400,6 +400,7 @@ uint8_t IRLgAc::getTemp(void) { void IRLgAc::setFan(const uint8_t speed) { switch (speed) { case kLgAcFanAuto: + case kLgAcFanLowest: case kLgAcFanLow: case kLgAcFanMedium: case kLgAcFanHigh: @@ -469,12 +470,12 @@ stdAc::opmode_t IRLgAc::toCommonMode(const uint8_t mode) { /// @return The native equivilant of the enum. uint8_t IRLgAc::convertFan(const stdAc::fanspeed_t speed) { switch (speed) { - case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kMin: return kLgAcFanLowest; case stdAc::fanspeed_t::kLow: return kLgAcFanLow; case stdAc::fanspeed_t::kMedium: return kLgAcFanMedium; case stdAc::fanspeed_t::kHigh: - case stdAc::fanspeed_t::kMax: return kHitachiAcFanHigh; - default: return kHitachiAcFanAuto; + case stdAc::fanspeed_t::kMax: return kLgAcFanHigh; + default: return kLgAcFanAuto; } } @@ -486,6 +487,7 @@ stdAc::fanspeed_t IRLgAc::toCommonFanSpeed(const uint8_t speed) { case kLgAcFanHigh: return stdAc::fanspeed_t::kMax; case kLgAcFanMedium: return stdAc::fanspeed_t::kMedium; case kLgAcFanLow: return stdAc::fanspeed_t::kLow; + case kLgAcFanLowest: return stdAc::fanspeed_t::kMin; default: return stdAc::fanspeed_t::kAuto; } } @@ -528,7 +530,7 @@ String IRLgAc::toString(void) { kLgAcHeat, kLgAcDry, kLgAcFan); result += addTempToString(getTemp()); result += addFanToString(getFan(), kLgAcFanHigh, kLgAcFanLow, - kLgAcFanAuto, kLgAcFanAuto, kLgAcFanMedium); + kLgAcFanAuto, kLgAcFanLowest, kLgAcFanMedium); } return result; } diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_LG.h b/lib/IRremoteESP8266-2.7.8/src/ir_LG.h index bf0cdd0b6..1748d143e 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_LG.h +++ b/lib/IRremoteESP8266-2.7.8/src/ir_LG.h @@ -32,7 +32,8 @@ const uint8_t kLgAcChecksumOffset = 0; // Nr. of bits const uint8_t kLgAcChecksumSize = kNibbleSize; // Nr. of bits const uint8_t kLgAcFanOffset = 4; // Nr. of bits const uint8_t kLgAcFanSize = 3; // Nr. of bits -const uint8_t kLgAcFanLow = 0; // 0b000 +const uint8_t kLgAcFanLowest = 0; // 0b000 +const uint8_t kLgAcFanLow = 1; // 0b001 const uint8_t kLgAcFanMedium = 2; // 0b010 const uint8_t kLgAcFanHigh = 4; // 0b100 const uint8_t kLgAcFanAuto = 5; // 0b101 diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Midea.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_Midea.cpp index 5d270d3d4..d02088cef 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Midea.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Midea.cpp @@ -3,7 +3,9 @@ /// @brief Support for Midea protocols. /// Midea added by crankyoldgit & bwze. /// send: bwze/crankyoldgit, decode: crankyoldgit +/// @note SwingV has the function of an Ion Filter on Danby A/C units. /// @see https://docs.google.com/spreadsheets/d/1TZh4jWrx4h9zzpYUI9aYXMl1fYOiqu-xVuOOMqagxrs/edit?usp=sharing +/// @see https://github.com/crankyoldgit/IRremoteESP8266/pull/1213 #include "ir_Midea.h" #include "ir_NEC.h" @@ -99,6 +101,7 @@ void IRMideaAC::stateReset(void) { // Power On, Mode Auto, Fan Auto, Temp = 25C/77F remote_state = 0xA1826FFFFF62; _SwingVToggle = false; + _EconoToggle = false; } /// Set up hardware to be able to send a message. @@ -110,11 +113,14 @@ void IRMideaAC::begin(void) { _irsend.begin(); } void IRMideaAC::send(const uint16_t repeat) { this->checksum(); // Ensure correct checksum before sending. _irsend.sendMidea(remote_state, kMideaBits, repeat); - // Handle toggling the swing if we need to. - if (_SwingVToggle && !isSwingVToggle()) { + // Handle toggling the swing & econo mode if we need to. + if (_SwingVToggle && !isSwingVToggle()) _irsend.sendMidea(kMideaACToggleSwingV, kMideaBits, repeat); - } - _SwingVToggle = false; // The toggle message has been sent, so reset. + if (_EconoToggle && !isEconoToggle()) + _irsend.sendMidea(kMideaACToggleEcono, kMideaBits, repeat); + // The toggle messages has been sent, so reset. + _SwingVToggle = false; + _EconoToggle = false; } #endif // SEND_MIDEA @@ -246,22 +252,42 @@ bool IRMideaAC::getSleep(void) { } /// Set the A/C to toggle the vertical swing toggle for the next send. +/// @note On Danby A/C units, this is associated with the Ion Filter instead. /// @param[in] on true, the setting is on. false, the setting is off. void IRMideaAC::setSwingVToggle(const bool on) { _SwingVToggle = on; } /// Is the current state a vertical swing toggle message? +/// @note On Danby A/C units, this is associated with the Ion Filter instead. /// @return true, it is. false, it isn't. bool IRMideaAC::isSwingVToggle(void) { return remote_state == kMideaACToggleSwingV; } // Get the vertical swing toggle state of the A/C. +/// @note On Danby A/C units, this is associated with the Ion Filter instead. /// @return true, the setting is on. false, the setting is off. bool IRMideaAC::getSwingVToggle(void) { _SwingVToggle |= isSwingVToggle(); return _SwingVToggle; } +/// Set the A/C to toggle the Econo (energy saver) mode for the next send. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRMideaAC::setEconoToggle(const bool on) { _EconoToggle = on; } + +/// Is the current state an Econo (energy saver) toggle message? +/// @return true, it is. false, it isn't. +bool IRMideaAC::isEconoToggle(void) { + return remote_state == kMideaACToggleEcono; +} + +// Get the Econo (energy saver) toggle state of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRMideaAC::getEconoToggle(void) { + _EconoToggle |= isEconoToggle(); + return _EconoToggle; +} + /// Calculate the checksum for a given state. /// @param[in] state The value to calc the checksum of. /// @return The calculated checksum value. @@ -376,6 +402,7 @@ stdAc::state_t IRMideaAC::toCommon(const stdAc::state_t *prev) { result.degrees = this->getTemp(result.celsius); result.fanspeed = this->toCommonFanSpeed(this->getFan()); result.sleep = this->getSleep() ? 0 : -1; + result.econo = this->getEconoToggle(); return result; } @@ -384,7 +411,8 @@ stdAc::state_t IRMideaAC::toCommon(const stdAc::state_t *prev) { String IRMideaAC::toString(void) { String result = ""; result.reserve(100); // Reserve some heap for the string to reduce fragging. - if (!isSwingVToggle()) { + bool needComma = false; + if (!isSwingVToggle() && !isEconoToggle()) { result += addBoolToString(getPower(), kPowerStr, false); result += addModeToString(getMode(), kMideaACAuto, kMideaACCool, kMideaACHeat, kMideaACDry, kMideaACFan); @@ -396,9 +424,10 @@ String IRMideaAC::toString(void) { result += addFanToString(getFan(), kMideaACFanHigh, kMideaACFanLow, kMideaACFanAuto, kMideaACFanAuto, kMideaACFanMed); result += addBoolToString(getSleep(), kSleepStr); + needComma = true; } - result += addBoolToString(getSwingVToggle(), kSwingVToggleStr, - !isSwingVToggle()); + result += addBoolToString(getSwingVToggle(), kSwingVToggleStr, needComma); + result += addBoolToString(getEconoToggle(), kEconoToggleStr); return result; } diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Midea.h b/lib/IRremoteESP8266-2.7.8/src/ir_Midea.h index b7825f569..96a1ffec4 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Midea.h +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Midea.h @@ -11,6 +11,10 @@ // Brand: Comfee, Model: MPD1-12CRN7 A/C (MIDEA) // Brand: Keystone, Model: RG57H4(B)BGEF remote (MIDEA) // Brand: Midea, Model: FS40-7AR Stand Fan (MIDEA24) +// Brand: Danby, Model: DAC080BGUWDB (MIDEA) +// Brand: Danby, Model: DAC100BGUWDB (MIDEA) +// Brand: Danby, Model: DAC120BGUWDB (MIDEA) +// Brand: Danby, Model: R09C/BCGE remote (MIDEA) #ifndef IR_MIDEA_H_ #define IR_MIDEA_H_ @@ -26,6 +30,10 @@ #include "IRsend_test.h" #endif +#if DANBY_DAC + kSwingVToggleStr = kIonStr; +#endif + // Constants const uint8_t kMideaACTempOffset = 24; const uint8_t kMideaACTempSize = 5; // Bits @@ -49,6 +57,9 @@ const uint8_t kMideaACFanHigh = 3; // 0b11 const uint8_t kMideaACSleepOffset = 38; const uint8_t kMideaACPowerOffset = 39; const uint64_t kMideaACToggleSwingV = 0x0000A201FFFFFF7C; +// For Danby DAC unit, the Ionizer toggle is the same as ToggleSwingV +// const uint64_t kMideaACToggleIonizer = 0x0000A201FFFFFF7C; +const uint64_t kMideaACToggleEcono = 0x0000A202FFFFFF7E; // Legacy defines. (Deprecated) #define MIDEA_AC_COOL kMideaACCool @@ -104,6 +115,9 @@ class IRMideaAC { bool isSwingVToggle(void); void setSwingVToggle(const bool on); bool getSwingVToggle(void); + bool isEconoToggle(void); + void setEconoToggle(const bool on); + bool getEconoToggle(void); uint8_t convertMode(const stdAc::opmode_t mode); uint8_t convertFan(const stdAc::fanspeed_t speed); static stdAc::opmode_t toCommonMode(const uint8_t mode); @@ -121,6 +135,7 @@ class IRMideaAC { #endif // UNIT_TEST uint64_t remote_state; ///< The state of the IR remote in IR code form. bool _SwingVToggle; + bool _EconoToggle; void checksum(void); static uint8_t calcChecksum(const uint64_t state); }; diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.h index 04c7bf57d..60f997095 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.h +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.h @@ -163,7 +163,7 @@ const uint8_t kMitsubishi112SwingHAuto = 0b1100; /// Class for handling detailed Mitsubishi 144-bit A/C messages. -/// Inspired and derived from the work done at: https://github.com/r45635/HVAC-IR-Control +/// @note Inspired and derived from the work done at: https://github.com/r45635/HVAC-IR-Control /// @warning Consider this very alpha code. Seems to work, but not validated. class IRMitsubishiAC { public: @@ -282,7 +282,7 @@ class IRMitsubishi136 { void checksum(void); }; - +/// Class for handling detailed Mitsubishi 122-bit A/C messages. class IRMitsubishi112 { public: explicit IRMitsubishi112(const uint16_t pin, const bool inverted = false, diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.cpp index 7747ded6d..8a52bb762 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.cpp @@ -33,6 +33,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::checkInvertedBytePairs; +using irutils::invertBytePairs; using irutils::setBit; using irutils::setBits; @@ -321,32 +323,24 @@ bool IRMitsubishiHeavy152Ac::checkZmsSig(const uint8_t *state) { } /// Calculate the checksum for the current internal state of the remote. -/// Note: Technically it has no checksum, but does has inverted byte pairs. +/// Note: Technically it has no checksum, but does have inverted byte pairs. void IRMitsubishiHeavy152Ac::checksum(void) { - for (uint8_t i = kMitsubishiHeavySigLength - 2; - i < kMitsubishiHeavy152StateLength; - i += 2) { - remote_state[i + 1] = ~remote_state[i]; - } + const uint8_t kOffset = kMitsubishiHeavySigLength - 2; + invertBytePairs(remote_state + kOffset, + kMitsubishiHeavy152StateLength - kOffset); } /// Verify the checksum is valid for a given state. /// @param[in] state The array to verify the checksum of. /// @param[in] length The length/size of the state array. /// @return true, if the state has a valid checksum. Otherwise, false. -/// Note: Technically it has no checksum, but does has inverted byte pairs. +/// Note: Technically it has no checksum, but does have inverted byte pairs. bool IRMitsubishiHeavy152Ac::validChecksum(const uint8_t *state, const uint16_t length) { // Assume anything too short is fine. if (length < kMitsubishiHeavySigLength) return true; - // Check all the byte pairs. - for (uint16_t i = kMitsubishiHeavySigLength - 2; - i < length; - i += 2) { - // XOR of a byte and it's self inverted should be 0xFF; - if ((state[i] ^ state[i + 1]) != 0xFF) return false; - } - return true; + const uint8_t kOffset = kMitsubishiHeavySigLength - 2; + return checkInvertedBytePairs(state + kOffset, length - kOffset); } /// Convert a stdAc::opmode_t enum into its native mode. @@ -856,20 +850,18 @@ bool IRMitsubishiHeavy88Ac::checkZjsSig(const uint8_t *state) { } /// Calculate the checksum for the current internal state of the remote. -/// Note: Technically it has no checksum, but does has inverted byte pairs. +/// Note: Technically it has no checksum, but does have inverted byte pairs. void IRMitsubishiHeavy88Ac::checksum(void) { - for (uint8_t i = kMitsubishiHeavySigLength - 2; - i < kMitsubishiHeavy88StateLength; - i += 2) { - remote_state[i + 1] = ~remote_state[i]; - } + const uint8_t kOffset = kMitsubishiHeavySigLength - 2; + invertBytePairs(remote_state + kOffset, + kMitsubishiHeavy88StateLength - kOffset); } /// Verify the checksum is valid for a given state. /// @param[in] state The array to verify the checksum of. /// @param[in] length The length/size of the state array. /// @return true, if the state has a valid checksum. Otherwise, false. -/// Note: Technically it has no checksum, but does has inverted byte pairs. +/// Note: Technically it has no checksum, but does have inverted byte pairs. bool IRMitsubishiHeavy88Ac::validChecksum(const uint8_t *state, const uint16_t length) { return IRMitsubishiHeavy152Ac::validChecksum(state, length); diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Pioneer.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_Pioneer.cpp index d5ac89765..90f58c6ed 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Pioneer.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Pioneer.cpp @@ -8,9 +8,12 @@ /// @see http://www.adrian-kingston.com/IRFormatPioneer.htm /// @see https://github.com/crankyoldgit/IRremoteESP8266/pull/547 /// @see https://www.pioneerelectronics.com/PUSA/Support/Home-Entertainment-Custom-Install/IR+Codes/A+V+Receivers +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1220 // Supports: // Brand: Pioneer, Model: AV Receivers +// Brand: Pioneer, Model: VSX-324 AV Receiver +// Brand: Pioneer, Model: AXD7690 Remote #define __STDC_LIMIT_MACROS #include @@ -20,22 +23,15 @@ #include "IRutils.h" // Constants -const uint16_t kPioneerTick = 534; -const uint16_t kPioneerHdrMarkTicks = 16; -const uint16_t kPioneerHdrMark = kPioneerHdrMarkTicks * kPioneerTick; -const uint16_t kPioneerHdrSpaceTicks = 8; -const uint16_t kPioneerHdrSpace = kPioneerHdrSpaceTicks * kPioneerTick; -const uint16_t kPioneerBitMarkTicks = 1; -const uint16_t kPioneerBitMark = kPioneerBitMarkTicks * kPioneerTick; -const uint16_t kPioneerOneSpaceTicks = 3; -const uint16_t kPioneerOneSpace = kPioneerOneSpaceTicks * kPioneerTick; -const uint16_t kPioneerZeroSpaceTicks = 1; -const uint16_t kPioneerZeroSpace = kPioneerZeroSpaceTicks * kPioneerTick; -const uint16_t kPioneerMinCommandLengthTicks = 159; -const uint32_t kPioneerMinCommandLength = kPioneerMinCommandLengthTicks * - kPioneerTick; -const uint16_t kPioneerMinGapTicks = 47; -const uint32_t kPioneerMinGap = kPioneerMinGapTicks * kPioneerTick; +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1220 +const uint16_t kPioneerTick = 534; ///< uSeconds. +const uint16_t kPioneerHdrMark = 8506; ///< uSeconds. +const uint16_t kPioneerHdrSpace = 4191; ///< uSeconds. +const uint16_t kPioneerBitMark = 568; ///< uSeconds. +const uint16_t kPioneerOneSpace = 1542; ///< uSeconds. +const uint16_t kPioneerZeroSpace = 487; ///< uSeconds. +const uint32_t kPioneerMinCommandLength = 84906; ///< uSeconds. +const uint32_t kPioneerMinGap = 25181; ///< uSeconds. #if SEND_PIONEER /// Send a raw Pioneer formatted message. diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.cpp index 02aa4abdd..c3ff5ec7d 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.cpp @@ -53,6 +53,14 @@ const uint16_t kSamsungAcBitMark = 586; const uint16_t kSamsungAcOneSpace = 1432; const uint16_t kSamsungAcZeroSpace = 436; +// Data from https://github.com/crankyoldgit/IRremoteESP8266/issues/1220 +// Values calculated based on the average of ten messages. +const uint16_t kSamsung36HdrMark = 4515; /// < uSeconds +const uint16_t kSamsung36HdrSpace = 4438; /// < uSeconds +const uint16_t kSamsung36BitMark = 512; /// < uSeconds +const uint16_t kSamsung36OneSpace = 1468; /// < uSeconds +const uint16_t kSamsung36ZeroSpace = 490; /// < uSeconds + using irutils::addBoolToString; using irutils::addFanToString; using irutils::addIntToString; @@ -146,7 +154,7 @@ bool IRrecv::decodeSAMSUNG(decode_results *results, uint16_t offset, #if SEND_SAMSUNG36 /// Send a Samsung 36-bit formatted message. -/// Status: Alpha / Experimental. +/// Status: STABLE / Works on real devices. /// @param[in] data The message to be sent. /// @param[in] nbits The number of bits of message to be sent. /// @param[in] repeat The number of times the command is to be repeated. @@ -156,16 +164,16 @@ void IRsend::sendSamsung36(const uint64_t data, const uint16_t nbits, if (nbits < 16) return; // To small to send. for (uint16_t r = 0; r <= repeat; r++) { // Block #1 (16 bits) - sendGeneric(kSamsungHdrMark, kSamsungHdrSpace, - kSamsungBitMark, kSamsungOneSpace, - kSamsungBitMark, kSamsungZeroSpace, - kSamsungBitMark, kSamsungHdrSpace, + sendGeneric(kSamsung36HdrMark, kSamsung36HdrSpace, + kSamsung36BitMark, kSamsung36OneSpace, + kSamsung36BitMark, kSamsung36ZeroSpace, + kSamsung36BitMark, kSamsung36HdrSpace, data >> (nbits - 16), 16, 38, true, 0, kDutyDefault); // Block #2 (The rest, typically 20 bits) sendGeneric(0, 0, // No header - kSamsungBitMark, kSamsungOneSpace, - kSamsungBitMark, kSamsungZeroSpace, - kSamsungBitMark, kSamsungMinGap, // Gap is just a guess. + kSamsung36BitMark, kSamsung36OneSpace, + kSamsung36BitMark, kSamsung36ZeroSpace, + kSamsung36BitMark, kSamsungMinGap, // Gap is just a guess. // Mask off the rest of the bits. data & ((1ULL << (nbits - 16)) - 1), nbits - 16, 38, true, 0, kDutyDefault); @@ -175,7 +183,7 @@ void IRsend::sendSamsung36(const uint64_t data, const uint16_t nbits, #if DECODE_SAMSUNG36 /// Decode the supplied Samsung36 message. -/// Status: Alpha / Experimental +/// Status: STABLE / Expected to work. /// @param[in,out] results Ptr to the data to decode & where to store the result /// @param[in] offset The starting index to use when attempting to decode the /// raw data. Typically/Defaults to kStartOffset. @@ -198,10 +206,10 @@ bool IRrecv::decodeSamsung36(decode_results *results, uint16_t offset, uint16_t used; used = matchGeneric(results->rawbuf + offset, &data, results->rawlen - offset, 16, - kSamsungHdrMark, kSamsungHdrSpace, - kSamsungBitMark, kSamsungOneSpace, - kSamsungBitMark, kSamsungZeroSpace, - kSamsungBitMark, kSamsungHdrSpace, false); + kSamsung36HdrMark, kSamsung36HdrSpace, + kSamsung36BitMark, kSamsung36OneSpace, + kSamsung36BitMark, kSamsung36ZeroSpace, + kSamsung36BitMark, kSamsung36HdrSpace, false); if (!used) return false; offset += used; // Data (Block #2) @@ -209,9 +217,9 @@ bool IRrecv::decodeSamsung36(decode_results *results, uint16_t offset, if (!matchGeneric(results->rawbuf + offset, &data2, results->rawlen - offset, nbits - 16, 0, 0, - kSamsungBitMark, kSamsungOneSpace, - kSamsungBitMark, kSamsungZeroSpace, - kSamsungBitMark, kSamsungMinGap, true)) return false; + kSamsung36BitMark, kSamsung36OneSpace, + kSamsung36BitMark, kSamsung36ZeroSpace, + kSamsung36BitMark, kSamsungMinGap, true)) return false; data <<= (nbits - 16); data += data2; diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.h b/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.h index fa6f9f2f3..d5c9955ec 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.h +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.h @@ -14,6 +14,8 @@ // Brand: Samsung, Model: DB93-16761C remote // Brand: Samsung, Model: IEC-R03 remote // Brand: Samsung, Model: AK59-00167A Bluray remote (SAMSUNG36) +// Brand: Samsung, Model: AH59-02692E Soundbar remote (SAMSUNG36) +// Brand: Samsung, Model: HW-J551 Soundbar (SAMSUNG36) // Brand: Samsung, Model: AR09FSSDAWKNFA A/C (SAMSUNG_AC) // Brand: Samsung, Model: AR12KSFPEWQNET A/C (SAMSUNG_AC) // Brand: Samsung, Model: AR12HSSDBWKNEU A/C (SAMSUNG_AC) diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.cpp index 25baf380b..04a9f4f2f 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.cpp @@ -1,6 +1,6 @@ // Copyright 2009 Ken Shirriff // Copyright 2016 marcosamarinho -// Copyright 2017 David Conran +// Copyright 2017-2020 David Conran /// @file /// @brief Support for Sanyo protocols. @@ -11,15 +11,27 @@ /// @see http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf /// @see https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp /// @see http://slydiman.narod.ru/scr/kb/sanyo.htm +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1211 +/// @see https://docs.google.com/spreadsheets/d/1dYfLsnYvpjV-SgO8pdinpfuBIpSzm8Q1R5SabrLeskw/edit?usp=sharing -// Supports: -// Brand: Sanyo, Model: SA 8650B - disabled -// Brand: Sanyo, Model: LC7461 transmitter IC (SANYO_LC7461) - +#include "ir_Sanyo.h" #include +#include #include "IRrecv.h" #include "IRsend.h" +#include "IRtext.h" +#include "IRutils.h" +using irutils::addBoolToString; +using irutils::addFanToString; +using irutils::addIntToString; +using irutils::addLabeledString; +using irutils::addModeToString; +using irutils::addTempToString; +using irutils::minsToString; +using irutils::sumNibbles; +using irutils::setBit; +using irutils::setBits; // Constants // Sanyo SA 8650B @@ -48,6 +60,14 @@ const uint16_t kSanyoLc7461MinGap = (kSanyoLc7461OneSpace + kSanyoLc7461ZeroSpace) / 2) + kSanyoLc7461BitMark); +const uint16_t kSanyoAcHdrMark = 8500; ///< uSeconds +const uint16_t kSanyoAcHdrSpace = 4200; ///< uSeconds +const uint16_t kSanyoAcBitMark = 500; ///< uSeconds +const uint16_t kSanyoAcOneSpace = 1600; ///< uSeconds +const uint16_t kSanyoAcZeroSpace = 550; ///< uSeconds +const uint32_t kSanyoAcGap = kDefaultMessageGap; ///< uSeconds (Guess only) +const uint16_t kSanyoAcFreq = 38000; ///< Hz. (Guess only) + #if SEND_SANYO /// Construct a Sanyo LC7461 message. /// @param[in] address The 13 bit value of the address(Custom) portion of the @@ -221,3 +241,453 @@ bool IRrecv::decodeSanyo(decode_results *results, uint16_t nbits, bool strict) { } */ #endif // DECODE_SANYO + + +#if SEND_SANYO_AC +/// Send a SanyoAc formatted message. +/// Status: STABLE / Reported as working. +/// @param[in] data An array of bytes containing the IR command. +/// @param[in] nbytes Nr. of bytes of data in the array. +/// @param[in] repeat Nr. of times the message is to be repeated. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1211 +void IRsend::sendSanyoAc(const uint8_t data[], const uint16_t nbytes, + const uint16_t repeat) { + // Header + Data + Footer + sendGeneric(kSanyoAcHdrMark, kSanyoAcHdrSpace, + kSanyoAcBitMark, kSanyoAcOneSpace, + kSanyoAcBitMark, kSanyoAcZeroSpace, + kSanyoAcBitMark, kSanyoAcGap, + data, nbytes, kSanyoAcFreq, false, repeat, kDutyDefault); +} +#endif // SEND_SANYO_AC + +#if DECODE_SANYO_AC +/// Decode the supplied SanyoAc message. +/// Status: STABLE / Reported as working. +/// @param[in,out] results Ptr to the data to decode & where to store the decode +/// @param[in] offset The starting index to use when attempting to decode the +/// raw data. Typically/Defaults to kStartOffset. +/// @param[in] nbits The number of data bits to expect. +/// @param[in] strict Flag indicating if we should perform strict matching. +/// @return A boolean. True if it can decode it, false if it can't. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1211 +bool IRrecv::decodeSanyoAc(decode_results *results, uint16_t offset, + const uint16_t nbits, const bool strict) { + if (strict && nbits != kSanyoAcBits) + return false; + + // Header + Data + Footer + if (!matchGeneric(results->rawbuf + offset, results->state, + results->rawlen - offset, nbits, + kSanyoAcHdrMark, kSanyoAcHdrSpace, + kSanyoAcBitMark, kSanyoAcOneSpace, + kSanyoAcBitMark, kSanyoAcZeroSpace, + kSanyoAcBitMark, kSanyoAcGap, + true, kUseDefTol, kMarkExcess, false)) return false; + // Compliance + if (strict) + if (!IRSanyoAc::validChecksum(results->state, nbits / 8)) return false; + + // Success + results->decode_type = decode_type_t::SANYO_AC; + results->bits = nbits; + // No need to record the state as we stored it as we decoded it. + // As we use result->state, we don't record value, address, or command as it + // is a union data type. + return true; +} +#endif // DECODE_SANYO_AC + +/// Class constructor +/// @param[in] pin GPIO to be used when sending. +/// @param[in] inverted Is the output signal to be inverted? +/// @param[in] use_modulation Is frequency modulation to be used? +IRSanyoAc::IRSanyoAc(const uint16_t pin, const bool inverted, + const bool use_modulation) + : _irsend(pin, inverted, use_modulation) { stateReset(); } + +/// Reset the state of the remote to a known good state/sequence. +/// @see https://docs.google.com/spreadsheets/d/1dYfLsnYvpjV-SgO8pdinpfuBIpSzm8Q1R5SabrLeskw/edit?ts=5f0190a5#gid=1050142776&range=A2:B2 +void IRSanyoAc::stateReset(void) { + static const uint8_t kReset[kSanyoAcStateLength] = { + 0x6A, 0x6D, 0x51, 0x00, 0x10, 0x45, 0x00, 0x00, 0x33}; + memcpy(remote_state, kReset, kSanyoAcStateLength); +} + +/// Set up hardware to be able to send a message. +void IRSanyoAc::begin(void) { _irsend.begin(); } + +#if SEND_SANYO_AC +/// Send the current internal state as IR messages. +/// @param[in] repeat Nr. of times the message will be repeated. +void IRSanyoAc::send(const uint16_t repeat) { + _irsend.sendSanyoAc(getRaw(), kSanyoAcStateLength, repeat); +} +#endif // SEND_SANYO_AC + +/// Get a PTR to the internal state/code for this protocol with all integrity +/// checks passing. +/// @return PTR to a code for this protocol based on the current internal state. +uint8_t* IRSanyoAc::getRaw(void) { + checksum(); + return remote_state; +} + +/// Set the internal state from a valid code for this protocol. +/// @param[in] newState A valid code for this protocol. +void IRSanyoAc::setRaw(const uint8_t newState[]) { + memcpy(remote_state, newState, kSanyoAcStateLength); +} + +/// Calculate the checksum for a given state. +/// @param[in] state The array to calc the checksum of. +/// @param[in] length The length/size of the array. +/// @return The calculated checksum value. +uint8_t IRSanyoAc::calcChecksum(const uint8_t state[], + const uint16_t length) { + return length ? sumNibbles(state, length - 1) : 0; +} + +/// Verify the checksum is valid for a given state. +/// @param[in] state The array to verify the checksum of. +/// @param[in] length The length/size of the array. +/// @return true, if the state has a valid checksum. Otherwise, false. +bool IRSanyoAc::validChecksum(const uint8_t state[], const uint16_t length) { + return length && state[length - 1] == IRSanyoAc::calcChecksum(state, length); +} + +/// Calculate & set the checksum for the current internal state of the remote. +void IRSanyoAc::checksum(void) { + // Stored the checksum value in the last byte. + remote_state[kSanyoAcStateLength - 1] = calcChecksum(remote_state); +} + + +/// Set the requested power state of the A/C to on. +void IRSanyoAc::on(void) { setPower(true); } + +/// Set the requested power state of the A/C to off. +void IRSanyoAc::off(void) { setPower(false); } + +/// Change the power setting. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRSanyoAc::setPower(const bool on) { + setBits(&remote_state[kSanyoAcPowerByte], kSanyoAcPowerOffset, + kSanyoAcPowerSize, on ? kSanyoAcPowerOn : kSanyoAcPowerOff); +} + +/// Get the value of the current power setting. +/// @return true, the setting is on. false, the setting is off. +bool IRSanyoAc::getPower(void) { + return GETBITS8(remote_state[kSanyoAcPowerByte], kSanyoAcPowerOffset, + kSanyoAcPowerSize) == kSanyoAcPowerOn; +} + +/// Get the operating mode setting of the A/C. +/// @return The current operating mode setting. +uint8_t IRSanyoAc::getMode(void) { + return GETBITS8(remote_state[kSanyoAcModeByte], kSanyoAcModeOffset, + kSanyoAcModeSize); +} + +/// Set the operating mode of the A/C. +/// @param[in] mode The desired operating mode. +/// @note If we get an unexpected mode, default to AUTO. +void IRSanyoAc::setMode(const uint8_t mode) { + switch (mode) { + case kSanyoAcAuto: + case kSanyoAcCool: + case kSanyoAcDry: + case kSanyoAcHeat: + setBits(&remote_state[kSanyoAcModeByte], kSanyoAcModeOffset, + kSanyoAcModeSize, mode); + break; + default: setMode(kSanyoAcAuto); + } +} + +/// Convert a stdAc::opmode_t enum into its native mode. +/// @param[in] mode The enum to be converted. +/// @return The native equivilant of the enum. +uint8_t IRSanyoAc::convertMode(const stdAc::opmode_t mode) { + switch (mode) { + case stdAc::opmode_t::kCool: return kSanyoAcCool; + case stdAc::opmode_t::kHeat: return kSanyoAcHeat; + case stdAc::opmode_t::kDry: return kSanyoAcDry; + default: return kSanyoAcAuto; + } +} + +/// Convert a native mode into its stdAc equivilant. +/// @param[in] mode The native setting to be converted. +/// @return The stdAc equivilant of the native setting. +stdAc::opmode_t IRSanyoAc::toCommonMode(const uint8_t mode) { + switch (mode) { + case kSanyoAcCool: return stdAc::opmode_t::kCool; + case kSanyoAcHeat: return stdAc::opmode_t::kHeat; + case kSanyoAcDry: return stdAc::opmode_t::kDry; + default: return stdAc::opmode_t::kAuto; + } +} + +/// Set the temperature at a given location. +/// @param[out] ptr A pointer to a temperature byte. +/// @param[in] degrees The temperature in degrees celsius. +void IRSanyoAc::_setTemp(uint8_t *ptr, const uint8_t degrees) { + uint8_t temp = std::max((uint8_t)kSanyoAcTempMin, degrees); + temp = std::min((uint8_t)kSanyoAcTempMax, temp); + setBits(ptr, kSanyoAcTempOffset, kSanyoAcTempSize, temp - kSanyoAcTempDelta); +} + +/// Get the temperature from a given location. +/// @param[in] ptr A pointer to a temperature byte. +/// @return The current setting for temp. in degrees celsius. +uint8_t IRSanyoAc::_getTemp(uint8_t *ptr) { + return GETBITS8(*ptr, kSanyoAcTempOffset, kSanyoAcTempSize) + + kSanyoAcTempDelta; +} + +/// Set the desired temperature. +/// @param[in] degrees The temperature in degrees celsius. +void IRSanyoAc::setTemp(const uint8_t degrees) { + _setTemp(&remote_state[kSanyoAcTempByte], degrees); +} + +/// Get the current desired temperature setting. +/// @return The current setting for temp. in degrees celsius. +uint8_t IRSanyoAc::getTemp(void) { + return _getTemp(&remote_state[kSanyoAcTempByte]); +} + +/// Set the sensor temperature. +/// @param[in] degrees The temperature in degrees celsius. +void IRSanyoAc::setSensorTemp(const uint8_t degrees) { + _setTemp(&remote_state[kSanyoAcSensorByte], degrees); +} + +/// Get the current sensor temperature setting. +/// @return The current setting for temp. in degrees celsius. +uint8_t IRSanyoAc::getSensorTemp(void) { + return _getTemp(&remote_state[kSanyoAcSensorByte]); +} + +/// Set the speed of the fan. +/// @param[in] speed The desired setting. +void IRSanyoAc::setFan(const uint8_t speed) { + setBits(&remote_state[kSanyoAcModeByte], kSanyoAcFanOffset, kSanyoAcFanSize, + speed); +} + +/// Get the current fan speed setting. +/// @return The current fan speed/mode. +uint8_t IRSanyoAc::getFan(void) { + return GETBITS8(remote_state[kSanyoAcModeByte], kSanyoAcFanOffset, + kSanyoAcFanSize); +} + +/// Convert a stdAc::fanspeed_t enum into it's native speed. +/// @param[in] speed The enum to be converted. +/// @return The native equivilant of the enum. +uint8_t IRSanyoAc::convertFan(const stdAc::fanspeed_t speed) { + switch (speed) { + case stdAc::fanspeed_t::kMin: + case stdAc::fanspeed_t::kLow: return kSanyoAcFanLow; + case stdAc::fanspeed_t::kMedium: return kSanyoAcFanMedium; + case stdAc::fanspeed_t::kHigh: + case stdAc::fanspeed_t::kMax: return kSanyoAcFanHigh; + default: return kSanyoAcFanAuto; + } +} + +/// Convert a native fan speed into its stdAc equivilant. +/// @param[in] spd The native setting to be converted. +/// @return The stdAc equivilant of the native setting. +stdAc::fanspeed_t IRSanyoAc::toCommonFanSpeed(const uint8_t spd) { + switch (spd) { + case kSanyoAcFanHigh: return stdAc::fanspeed_t::kHigh; + case kSanyoAcFanMedium: return stdAc::fanspeed_t::kMedium; + case kSanyoAcFanLow: return stdAc::fanspeed_t::kLow; + default: return stdAc::fanspeed_t::kAuto; + } +} + +/// Get the vertical swing setting of the A/C. +/// @return The current swing mode setting. +uint8_t IRSanyoAc::getSwingV(void) { + return GETBITS8(remote_state[kSanyoAcPowerByte], kSanyoAcSwingVOffset, + kSanyoAcSwingVSize); +} + +/// Set the vertical swing setting of the A/C. +/// @param[in] setting The value of the desired setting. +void IRSanyoAc::setSwingV(const uint8_t setting) { + if (setting == kSanyoAcSwingVAuto || + (setting >= kSanyoAcSwingVLowest && setting <= kSanyoAcSwingVHighest)) + setBits(&remote_state[kSanyoAcPowerByte], kSanyoAcSwingVOffset, + kSanyoAcSwingVSize, setting); + + else + setSwingV(kSanyoAcSwingVAuto); +} + +/// Convert a stdAc::swingv_t enum into it's native setting. +/// @param[in] position The enum to be converted. +/// @return The native equivilant of the enum. +uint8_t IRSanyoAc::convertSwingV(const stdAc::swingv_t position) { + switch (position) { + case stdAc::swingv_t::kHighest: return kSanyoAcSwingVHighest; + case stdAc::swingv_t::kHigh: return kSanyoAcSwingVHigh; + case stdAc::swingv_t::kMiddle: return kSanyoAcSwingVUpperMiddle; + case stdAc::swingv_t::kLow: return kSanyoAcSwingVLow; + case stdAc::swingv_t::kLowest: return kSanyoAcSwingVLowest; + default: return kSanyoAcSwingVAuto; + } +} + +/// Convert a native vertical swing postion to it's common equivalent. +/// @param[in] setting A native position to convert. +/// @return The common vertical swing position. +stdAc::swingv_t IRSanyoAc::toCommonSwingV(const uint8_t setting) { + switch (setting) { + case kSanyoAcSwingVHighest: return stdAc::swingv_t::kHighest; + case kSanyoAcSwingVHigh: return stdAc::swingv_t::kHigh; + case kSanyoAcSwingVUpperMiddle: + case kSanyoAcSwingVLowerMiddle: return stdAc::swingv_t::kMiddle; + case kSanyoAcSwingVLow: return stdAc::swingv_t::kLow; + case kSanyoAcSwingVLowest: return stdAc::swingv_t::kLowest; + default: return stdAc::swingv_t::kAuto; + } +} + +/// Set the Sleep (Night Setback) setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRSanyoAc::setSleep(const bool on) { + setBit(&remote_state[kSanyoAcSleepByte], kSanyoAcSleepBit, on); +} + +/// Get the Sleep (Night Setback) setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRSanyoAc::getSleep(void) { + return GETBIT8(remote_state[kSanyoAcSleepByte], kSanyoAcSleepBit); +} + +/// Set the Sensor Location setting of the A/C. +/// i.e. Where the ambient temperature is measured. +/// @param[in] location true is Unit/Wall, false is Remote/Room. +void IRSanyoAc::setSensor(const bool location) { + setBit(&remote_state[kSanyoAcSensorByte], kSanyoAcSensorBit, location); +} + +/// Get the Sensor Location setting of the A/C. +/// i.e. Where the ambient temperature is measured. +/// @return true is Unit/Wall, false is Remote/Room. +bool IRSanyoAc::getSensor(void) { + return GETBIT8(remote_state[kSanyoAcSensorByte], kSanyoAcSensorBit); +} + +/// Set the Beep setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +void IRSanyoAc::setBeep(const bool on) { + setBit(&remote_state[kSanyoAcSensorByte], kSanyoAcBeepBit, on); +} + +/// Get the Beep setting of the A/C. +/// @return true, the setting is on. false, the setting is off. +bool IRSanyoAc::getBeep(void) { + return GETBIT8(remote_state[kSanyoAcSensorByte], kSanyoAcBeepBit); +} + +/// Get the nr of minutes the Off Timer is set to. +/// @return The timer time expressed as the number of minutes. +/// A value of 0 means the Off Timer is off/disabled. +/// @note The internal precission has a resolution of 1 hour. +uint16_t IRSanyoAc::getOffTimer(void) { + if (GETBIT8(remote_state[kSanyoAcModeByte], kSanyoAcOffTimerEnableBit)) + return GETBITS8(remote_state[kSanyoAcOffHourByte], kSanyoAcOffHourOffset, + kSanyoAcOffHourSize) * 60; + else + return 0; +} + +/// Set the nr of minutes for the Off Timer. +/// @param[in] mins The timer time expressed as nr. of minutes. +/// A value of 0 means the Off Timer is off/disabled. +/// @note The internal precission has a resolution of 1 hour. +void IRSanyoAc::setOffTimer(const uint16_t mins) { + const uint8_t hours = std::min((uint8_t)(mins / 60), kSanyoAcHourMax); + setBit(&remote_state[kSanyoAcModeByte], kSanyoAcOffTimerEnableBit, hours > 0); + setBits(&remote_state[kSanyoAcOffHourByte], kSanyoAcOffHourOffset, + kSanyoAcOffHourSize, hours); +} + +/// Convert the current internal state into its stdAc::state_t equivilant. +/// @return The stdAc equivilant of the native settings. +stdAc::state_t IRSanyoAc::toCommon(void) { + stdAc::state_t result; + result.protocol = decode_type_t::SANYO_AC; + result.model = -1; // Not supported. + result.power = getPower(); + result.mode = toCommonMode(getMode()); + result.celsius = true; + result.degrees = getTemp(); + result.fanspeed = toCommonFanSpeed(getFan()); + result.sleep = getSleep() ? 0 : -1; + result.swingv = toCommonSwingV(getSwingV()); + result.beep = getBeep(); + // Not supported. + result.swingh = stdAc::swingh_t::kOff; + result.turbo = false; + result.econo = false; + result.light = false; + result.filter = false; + result.quiet = false; + result.clean = false; + result.clock = -1; + return result; +} + +/// Convert the current internal state into a human readable string. +/// @return A human readable string. +String IRSanyoAc::toString(void) { + String result = ""; + result.reserve(140); + result += addBoolToString(getPower(), kPowerStr, false); + result += addModeToString(getMode(), kSanyoAcAuto, kSanyoAcCool, + kSanyoAcHeat, kSanyoAcDry, kSanyoAcAuto); + result += addTempToString(getTemp()); + result += addFanToString(getFan(), kSanyoAcFanHigh, kSanyoAcFanLow, + kSanyoAcFanAuto, kSanyoAcFanAuto, + kSanyoAcFanMedium); + result += addIntToString(getSwingV(), kSwingVStr); + result += kSpaceLBraceStr; + switch (getSwingV()) { + case kSanyoAcSwingVHighest: result += kHighestStr; break; + case kSanyoAcSwingVHigh: result += kHighStr; break; + case kSanyoAcSwingVUpperMiddle: + result += kUpperStr; + result += ' '; + result += kMiddleStr; + break; + case kSanyoAcSwingVLowerMiddle: + result += kLowerStr; + result += ' '; + result += kMiddleStr; + break; + case kSanyoAcSwingVLow: result += kLowStr; break; + case kSanyoAcSwingVLowest: result += kLowestStr; break; + case kSanyoAcSwingVAuto: result += kAutoStr; break; + default: result += kUnknownStr; + } + result += ')'; + result += addBoolToString(getSleep(), kSleepStr); + result += addBoolToString(getBeep(), kBeepStr); + result += addLabeledString(getSensor() ? kRoomStr : kWallStr, kSensorStr); + result += kCommaSpaceStr; + result += kSensorStr; + result += ' '; + result += addTempToString(getSensorTemp(), true, false); + const uint16_t offtime = getOffTimer(); + result += addLabeledString(offtime ? minsToString(offtime) : kOffStr, + kOffTimerStr); + return result; +} diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.h b/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.h new file mode 100644 index 000000000..9cdde61c8 --- /dev/null +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.h @@ -0,0 +1,163 @@ +// Copyright 2020 David Conran + +/// @file +/// @brief Support for Sanyo protocols. +/// Sanyo LC7461 support originally by marcosamarinho +/// Sanyo SA 8650B originally added from +/// https://github.com/shirriff/Arduino-IRremote/ +/// @see https://github.com/z3t0/Arduino-IRremote/blob/master/ir_Sanyo.cpp +/// @see http://pdf.datasheetcatalog.com/datasheet/sanyo/LC7461.pdf +/// @see https://github.com/marcosamarinho/IRremoteESP8266/blob/master/ir_Sanyo.cpp +/// @see http://slydiman.narod.ru/scr/kb/sanyo.htm +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1211 +/// @see https://docs.google.com/spreadsheets/d/1dYfLsnYvpjV-SgO8pdinpfuBIpSzm8Q1R5SabrLeskw/edit?usp=sharing + +// Supports: +// Brand: Sanyo, Model: SA 8650B - disabled +// Brand: Sanyo, Model: LC7461 transmitter IC (SANYO_LC7461) +// Brand: Sanyo, Model: SAP-K121AHA A/C (SANYO_AC) +// Brand: Sanyo, Model: RCS-2HS4E remote (SANYO_AC) +// Brand: Sanyo, Model: SAP-K242AH A/C (SANYO_AC) +// Brand: Sanyo, Model: RCS-2S4E remote (SANYO_AC) + +#ifndef IR_SANYO_H_ +#define IR_SANYO_H_ + +#define __STDC_LIMIT_MACROS +#include +#ifdef ARDUINO +#include +#endif +#include "IRremoteESP8266.h" +#include "IRsend.h" +#ifdef UNIT_TEST +#include "IRsend_test.h" +#endif + +// Constants + +// Sanyo A/C +// Ref: https://docs.google.com/spreadsheets/d/1dYfLsnYvpjV-SgO8pdinpfuBIpSzm8Q1R5SabrLeskw/edit?usp=sharing +// Byte[0] - 0x6A (Fixed?) +// Byte[1] - Address + Temperature +const uint8_t kSanyoAcTempByte = 1; ///< Index +const uint8_t kSanyoAcTempOffset = 0; ///< Mask 0b000xxxxx +const uint8_t kSanyoAcTempSize = 5; ///< Mask 0b000xxxxx +const uint8_t kSanyoAcTempMin = 16; ///< Celsius +const uint8_t kSanyoAcTempMax = 30; ///< Celsius +const uint8_t kSanyoAcTempDelta = 4; ///< Celsius to Native Temp difference. +// Byte[2] - Ambient Temp + Sensor +const uint8_t kSanyoAcSensorByte = 2; ///< Index +const uint8_t kSanyoAcSensorBit = 2; ///< Mask 0b00x00000 +// Ambient Temp Mask 0b000xxxxx +const uint8_t kSanyoAcBeepBit = 6; ///< Mask 0b0x000000 +// Byte[3] - Off Hour +const uint8_t kSanyoAcOffHourByte = 3; ///< Index +const uint8_t kSanyoAcOffHourOffset = 0; ///< Mask 0b0000xxxx +const uint8_t kSanyoAcOffHourSize = 4; ///< Mask 0b0000xxxx +const uint8_t kSanyoAcHourMax = 15; ///< 0b1111 +// Byte[4] - Mode + Fan + Timer Enables +const uint8_t kSanyoAcModeByte = 4; ///< Index +const uint8_t kSanyoAcModeOffset = 4; ///< Mask 0b0xxx0000 +const uint8_t kSanyoAcModeSize = 3; ///< Mask 0b0xxx0000 +const uint8_t kSanyoAcHeat = 1; ///< 0b001 +const uint8_t kSanyoAcCool = 2; ///< 0b010 +const uint8_t kSanyoAcDry = 3; ///< 0b011 +const uint8_t kSanyoAcAuto = 4; ///< 0b100 +const uint8_t kSanyoAcOffTimerEnableBit = 2; ///< Mask 0b00000x00 +const uint8_t kSanyoAcFanOffset = 0; ///< Mask 0b000000xx +const uint8_t kSanyoAcFanSize = 2; ///< Mask 0b000000xx +const uint8_t kSanyoAcFanAuto = 0; ///< 0b00 +const uint8_t kSanyoAcFanHigh = 1; ///< 0b01 +const uint8_t kSanyoAcFanLow = 2; ///< 0b10 +const uint8_t kSanyoAcFanMedium = 3; ///< 0b11 +// Byte[5] - Power + SwingV +const uint8_t kSanyoAcPowerByte = 5; ///< Index +const uint8_t kSanyoAcPowerOffset = 6; ///< Mask 0bxx000000 +const uint8_t kSanyoAcPowerSize = 2; ///< Mask 0bxx000000 +// const uint8_t kSanyoAcPowerStandby = 0b00; ///< Standby? +const uint8_t kSanyoAcPowerOff = 0b01; ///< Off +const uint8_t kSanyoAcPowerOn = 0b10; ///< On +const uint8_t kSanyoAcSwingVOffset = 0; ///< Mask 0b00000xxx +const uint8_t kSanyoAcSwingVSize = 3; ///< Mask 0b00000xxx +const uint8_t kSanyoAcSwingVAuto = 0; ///< 0b000 +const uint8_t kSanyoAcSwingVLowest = 2; ///< 0b010 +const uint8_t kSanyoAcSwingVLow = 3; ///< 0b011 +const uint8_t kSanyoAcSwingVLowerMiddle = 4; ///< 0b100 +const uint8_t kSanyoAcSwingVUpperMiddle = 5; ///< 0b101 +const uint8_t kSanyoAcSwingVHigh = 6; ///< 0b110 +const uint8_t kSanyoAcSwingVHighest = 7; ///< 0b111 +// Byte[6] - Sleep +const uint8_t kSanyoAcSleepByte = 6; ///< Index +const uint8_t kSanyoAcSleepBit = 3; ///< Mask 0b0000x000 +// Byte[8] - Checksum (8-bit Sum of all preceeding nibbles) + + +// Classes +/// Class for handling detailed Sanyo A/C messages. +class IRSanyoAc { + public: + explicit IRSanyoAc(const uint16_t pin, const bool inverted = false, + const bool use_modulation = true); + void stateReset(void); +#if SEND_SANYO_AC + void send(const uint16_t repeat = kNoRepeat); + /// Run the calibration to calculate uSec timing offsets for this platform. + /// @return The uSec timing offset needed per modulation of the IR Led. + /// @note This will produce a 65ms IR signal pulse at 38kHz. + /// Only ever needs to be run once per object instantiation, if at all. + int8_t calibrate(void) { return _irsend.calibrate(); } +#endif // SEND_SANYO_AC + void begin(void); + void on(void); + void off(void); + void setPower(const bool on); + bool getPower(void); + void setTemp(const uint8_t degrees); + uint8_t getTemp(void); + void setSensorTemp(const uint8_t degrees); + uint8_t getSensorTemp(void); + void setFan(const uint8_t speed); + uint8_t getFan(void); + void setMode(const uint8_t mode); + uint8_t getMode(void); + void setSleep(const bool on); + bool getSleep(void); + void setSensor(const bool location); + bool getSensor(void); + void setBeep(const bool on); + bool getBeep(void); + void setSwingV(const uint8_t setting); + uint8_t getSwingV(void); + void setRaw(const uint8_t newState[]); + uint8_t* getRaw(void); + uint16_t getOffTimer(void); + void setOffTimer(const uint16_t mins); + static bool validChecksum(const uint8_t state[], + const uint16_t length = kSanyoAcStateLength); + uint8_t convertMode(const stdAc::opmode_t mode); + uint8_t convertFan(const stdAc::fanspeed_t speed); + uint8_t convertSwingV(const stdAc::swingv_t position); + static stdAc::opmode_t toCommonMode(const uint8_t mode); + static stdAc::fanspeed_t toCommonFanSpeed(const uint8_t speed); + static stdAc::swingv_t toCommonSwingV(const uint8_t setting); + stdAc::state_t toCommon(void); + String toString(void); +#ifndef UNIT_TEST + + private: + IRsend _irsend; ///< Instance of the IR send class +#else // UNIT_TEST + /// @cond IGNORE + IRsendTest _irsend; ///< Instance of the testing IR send class + /// @endcond +#endif // UNIT_TEST + uint8_t remote_state[kSanyoAcStateLength]; ///< The state in IR code form. + void checksum(void); + static uint8_t calcChecksum(const uint8_t state[], + const uint16_t length = kSanyoAcStateLength); + void _setTemp(uint8_t *ptr, const uint8_t degrees); + uint8_t _getTemp(uint8_t *ptr); +}; + +#endif // IR_SANYO_H_ diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.cpp b/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.cpp index c28b700f8..f799885b3 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.cpp +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.cpp @@ -4,6 +4,9 @@ /// @brief Support for Toshiba protocols. /// @see https://github.com/r45635/HVAC-IR-Control /// @see https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266T.ino#L77 +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1205 +/// @see https://www.toshiba-carrier.co.jp/global/about/index.htm +/// @see http://www.toshiba-carrier.co.th/AboutUs/Pages/CompanyProfile.aspx #include "ir_Toshiba.h" #include @@ -21,10 +24,10 @@ // Toshiba A/C const uint16_t kToshibaAcHdrMark = 4400; const uint16_t kToshibaAcHdrSpace = 4300; -const uint16_t kToshibaAcBitMark = 543; -const uint16_t kToshibaAcOneSpace = 1623; -const uint16_t kToshibaAcZeroSpace = 472; -const uint16_t kToshibaAcMinGap = 7048; +const uint16_t kToshibaAcBitMark = 580; +const uint16_t kToshibaAcOneSpace = 1600; +const uint16_t kToshibaAcZeroSpace = 490; +const uint16_t kToshibaAcMinGap = 7400; using irutils::addBoolToString; using irutils::addFanToString; @@ -32,6 +35,8 @@ using irutils::addIntToString; using irutils::addLabeledString; using irutils::addModeToString; using irutils::addTempToString; +using irutils::checkInvertedBytePairs; +using irutils::invertBytePairs; using irutils::setBit; using irutils::setBits; @@ -41,10 +46,8 @@ using irutils::setBits; /// @param[in] data The message to be sent. /// @param[in] nbytes The number of bytes of message to be sent. /// @param[in] repeat The number of times the command is to be repeated. -void IRsend::sendToshibaAC(const unsigned char data[], const uint16_t nbytes, +void IRsend::sendToshibaAC(const uint8_t data[], const uint16_t nbytes, const uint16_t repeat) { - if (nbytes < kToshibaACStateLength) - return; // Not enough bytes to send a proper message. sendGeneric(kToshibaAcHdrMark, kToshibaAcHdrSpace, kToshibaAcBitMark, kToshibaAcOneSpace, kToshibaAcBitMark, kToshibaAcZeroSpace, kToshibaAcBitMark, kToshibaAcMinGap, data, nbytes, 38, true, @@ -58,7 +61,7 @@ void IRsend::sendToshibaAC(const unsigned char data[], const uint16_t nbytes, /// @param[in] use_modulation Is frequency modulation to be used? IRToshibaAC::IRToshibaAC(const uint16_t pin, const bool inverted, const bool use_modulation) - : _irsend(pin, inverted, use_modulation) { this->stateReset(); } + : _irsend(pin, inverted, use_modulation) { stateReset(); } /// Reset the state of the remote to a known good state/sequence. /// @see https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266T.ino#L103 @@ -66,24 +69,72 @@ void IRToshibaAC::stateReset(void) { static const uint8_t kReset[kToshibaACStateLength] = { 0xF2, 0x0D, 0x03, 0xFC, 0x01}; memcpy(remote_state, kReset, kToshibaACStateLength); - mode_state = getMode(true); + setTemp(22); // Remote defaults to 22C after factory reset. So do the same. + setSwing(kToshibaAcSwingOff); + prev_mode = getMode(); } /// Set up hardware to be able to send a message. void IRToshibaAC::begin(void) { _irsend.begin(); } #if SEND_TOSHIBA_AC -/// Send the current internal state as an IR message. +/// Send the current internal state as IR messages. /// @param[in] repeat Nr. of times the message will be repeated. void IRToshibaAC::send(const uint16_t repeat) { - _irsend.sendToshibaAC(getRaw(), kToshibaACStateLength, repeat); + _backupState(); + _irsend.sendToshibaAC(getRaw(), getStateLength(), repeat); + if (_send_swing && (getStateLength() != kToshibaACStateLengthShort)) { + setStateLength(kToshibaACStateLengthShort); + // Swing settings expect the min temp to be set. + // Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1205#issuecomment-653922374 + setTemp(kToshibaAcMinTemp); + setSwing(_swing_mode); + _irsend.sendToshibaAC(getRaw(), getStateLength(), repeat); + _restoreState(); + } + _send_swing = false; } #endif // SEND_TOSHIBA_AC -/// Get a PTR to the internal state/code for this protocol. +/// Get the length of the supplied Toshiba state per it's protocol structure. +/// @param[in] state The array to get the built-in length from. +/// @param[in] size The physical size of the state array. +/// @return Nr. of bytes in use for the provided state message. +uint16_t IRToshibaAC::getInternalStateLength(const uint8_t state[], + const uint16_t size) { + if (size < kToshibaAcLengthByte) return 0; + return std::min((uint16_t)(state[kToshibaAcLengthByte] + kToshibaAcMinLength), + kToshibaACStateLengthLong); +} + +/// Get the length of the current internal state per the protocol structure. +/// @return Nr. of bytes in use for the current internal state message. +uint16_t IRToshibaAC::getStateLength(void) { + return getInternalStateLength(remote_state, kToshibaACStateLengthLong); +} + +/// Set the internal length of the current internal state per the protocol. +/// @param[in] size Nr. of bytes in use for the current internal state message. +void IRToshibaAC::setStateLength(const uint16_t size) { + if (size < kToshibaAcMinLength) return; + remote_state[kToshibaAcLengthByte] = size - kToshibaAcMinLength; +} + +/// Make a copy of the internal code-form A/C state. +void IRToshibaAC::_backupState(void) { + memcpy(backup, remote_state, kToshibaACStateLengthLong); +} + +/// Recover the internal code-form A/C state from the backup. +void IRToshibaAC::_restoreState(void) { + memcpy(remote_state, backup, kToshibaACStateLengthLong); +} + +/// Get a PTR to the internal state/code for this protocol with all integrity +/// checks passing. /// @return PTR to a code for this protocol based on the current internal state. uint8_t* IRToshibaAC::getRaw(void) { - this->checksum(); + checksum(getStateLength()); return remote_state; } @@ -91,7 +142,8 @@ uint8_t* IRToshibaAC::getRaw(void) { /// @param[in] newState A valid code for this protocol. void IRToshibaAC::setRaw(const uint8_t newState[]) { memcpy(remote_state, newState, kToshibaACStateLength); - mode_state = this->getMode(true); + prev_mode = getMode(); + _send_swing = true; } /// Calculate the checksum for a given state. @@ -100,13 +152,7 @@ void IRToshibaAC::setRaw(const uint8_t newState[]) { /// @return The calculated checksum value. uint8_t IRToshibaAC::calcChecksum(const uint8_t state[], const uint16_t length) { - uint8_t checksum = 0; - // Only calculate it for valid lengths. - if (length > 1) { - // Checksum is simple XOR of all bytes except the last one. - for (uint8_t i = 0; i < length - 1; i++) checksum ^= state[i]; - } - return checksum; + return length ? xorBytes(state, length - 1) : 0; } /// Verify the checksum is valid for a given state. @@ -114,17 +160,27 @@ uint8_t IRToshibaAC::calcChecksum(const uint8_t state[], /// @param[in] length The length/size of the array. /// @return true, if the state has a valid checksum. Otherwise, false. bool IRToshibaAC::validChecksum(const uint8_t state[], const uint16_t length) { - return (length > 1 && state[length - 1] == IRToshibaAC::calcChecksum(state, - length)); + return length >= kToshibaAcMinLength && + state[length - 1] == IRToshibaAC::calcChecksum(state, length) && + checkInvertedBytePairs(state, kToshibaAcInvertedLength) && + IRToshibaAC::getInternalStateLength(state, length) == length; } /// Calculate & set the checksum for the current internal state of the remote. /// @param[in] length The length/size of the internal array to checksum. - void IRToshibaAC::checksum(const uint16_t length) { // Stored the checksum value in the last byte. - if (length > 1) remote_state[length - 1] = this->calcChecksum(remote_state, - length); + if (length >= kToshibaAcMinLength) { + // Set/clear the short msg bit. + setBit(&remote_state[4], kToshibaAcShortMsgBit, + getStateLength() == kToshibaACStateLengthShort); + // Set/clear the long msg bit. + setBit(&remote_state[4], kToshibaAcLongMsgBit, + getStateLength() == kToshibaACStateLengthLong); + invertBytePairs(remote_state, kToshibaAcInvertedLength); + // Always do the Xor checksum LAST! + remote_state[length - 1] = calcChecksum(remote_state, length); + } } /// Set the requested power state of the A/C to on. @@ -136,19 +192,18 @@ void IRToshibaAC::off(void) { setPower(false); } /// Change the power setting. /// @param[in] on true, the setting is on. false, the setting is off. void IRToshibaAC::setPower(const bool on) { - setBit(&remote_state[6], kToshibaAcPowerOffset, !on); // Cleared when on. - if (on) - setMode(mode_state); - else - setBits(&remote_state[6], kToshibaAcModeOffset, kToshibaAcModeSize, - kToshibaAcHeat); + if (on) { // On + // If not already on, pick the last non-off mode used + if (!getPower()) setMode(prev_mode); + } else { // Off + setMode(kToshibaAcOff); + } } - /// Get the value of the current power setting. /// @return true, the setting is on. false, the setting is off. bool IRToshibaAC::getPower(void) { - return !GETBIT8(remote_state[6], kToshibaAcPowerOffset); + return getMode(true) != kToshibaAcOff; } /// Set the temperature. @@ -187,32 +242,104 @@ uint8_t IRToshibaAC::getFan(void) { return --fan; } +/// Get the swing setting of the A/C. +/// @param[in] raw Calculate the answer from just the state data. +/// @return The current swing mode setting. +uint8_t IRToshibaAC::getSwing(const bool raw) { + return raw ? GETBITS8(remote_state[5], kToshibaAcSwingOffset, + kToshibaAcSwingSize) : _swing_mode; +} + +/// Set the swing setting of the A/C. +/// @param[in] setting The value of the desired setting. +void IRToshibaAC::setSwing(const uint8_t setting) { + switch (setting) { + case kToshibaAcSwingStep: + case kToshibaAcSwingOn: + case kToshibaAcSwingOff: + _send_swing = true; + _swing_mode = setting; + if (getStateLength() == kToshibaACStateLengthShort) + setBits(&remote_state[5], kToshibaAcSwingOffset, kToshibaAcSwingSize, + setting); + } +} + /// Get the operating mode setting of the A/C. -/// @param[in] useRaw Indicate to get the mode from the internal state array. +/// @param[in] raw Get the value without any intelligent processing. /// @return The current operating mode setting. -uint8_t IRToshibaAC::getMode(const bool useRaw) { - if (useRaw) - return GETBITS8(remote_state[6], kToshibaAcModeOffset, kToshibaAcModeSize); - else - return mode_state; +uint8_t IRToshibaAC::getMode(const bool raw) { + const uint8_t mode = GETBITS8(remote_state[6], kToshibaAcModeOffset, + kToshibaAcModeSize); + if (raw) return mode; + switch (mode) { + case kToshibaAcOff: return prev_mode; + default: return mode; + } } /// Set the operating mode of the A/C. /// @param[in] mode The desired operating mode. /// @note If we get an unexpected mode, default to AUTO. +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1205#issuecomment-654446771 void IRToshibaAC::setMode(const uint8_t mode) { + if (mode != prev_mode) + // Changing mode or power turns Econo & Turbo to off on a real remote. + // Setting the internal message length to "normal" will do that. + setStateLength(kToshibaACStateLength); switch (mode) { case kToshibaAcAuto: case kToshibaAcCool: case kToshibaAcDry: case kToshibaAcHeat: - mode_state = mode; - // Only adjust the remote_state if we have power set to on. - if (getPower()) - setBits(&remote_state[6], kToshibaAcModeOffset, kToshibaAcModeSize, - mode_state); - return; - default: this->setMode(kToshibaAcAuto); // There is no Fan mode. + case kToshibaAcFan: + prev_mode = mode; + // FALL-THRU + case kToshibaAcOff: + setBits(&remote_state[6], kToshibaAcModeOffset, kToshibaAcModeSize, + mode); + break; + default: setMode(kToshibaAcAuto); + } +} + +/// Get the Turbo (Powerful) setting of the A/C. +/// @return true, if the current setting is on. Otherwise, false. +bool IRToshibaAC::getTurbo(void) { + if (getStateLength() == kToshibaACStateLengthLong) + return remote_state[8] == kToshibaAcTurboOn; + return false; +} + +/// Set the Turbo (Powerful) setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +/// Note: Turbo mode is mutually exclusive with Economy mode. +void IRToshibaAC::setTurbo(const bool on) { + if (on) { + remote_state[8] = kToshibaAcTurboOn; + setStateLength(kToshibaACStateLengthLong); + } else { + if (!getEcono()) setStateLength(kToshibaACStateLength); + } +} + +/// Get the Economy mode setting of the A/C. +/// @return true, if the current setting is on. Otherwise, false. +bool IRToshibaAC::getEcono(void) { + if (getStateLength() == kToshibaACStateLengthLong) + return remote_state[8] == kToshibaAcEconoOn; + return false; +} + +/// Set the Economy mode setting of the A/C. +/// @param[in] on true, the setting is on. false, the setting is off. +/// Note: Economy mode is mutually exclusive with Turbo mode. +void IRToshibaAC::setEcono(const bool on) { + if (on) { + remote_state[8] = kToshibaAcEconoOn; + setStateLength(kToshibaACStateLengthLong); + } else { + if (!getTurbo()) setStateLength(kToshibaACStateLength); } } @@ -224,7 +351,8 @@ uint8_t IRToshibaAC::convertMode(const stdAc::opmode_t mode) { case stdAc::opmode_t::kCool: return kToshibaAcCool; case stdAc::opmode_t::kHeat: return kToshibaAcHeat; case stdAc::opmode_t::kDry: return kToshibaAcDry; - // No Fan mode. + case stdAc::opmode_t::kFan: return kToshibaAcFan; + case stdAc::opmode_t::kOff: return kToshibaAcOff; default: return kToshibaAcAuto; } } @@ -251,6 +379,8 @@ stdAc::opmode_t IRToshibaAC::toCommonMode(const uint8_t mode) { case kToshibaAcCool: return stdAc::opmode_t::kCool; case kToshibaAcHeat: return stdAc::opmode_t::kHeat; case kToshibaAcDry: return stdAc::opmode_t::kDry; + case kToshibaAcFan: return stdAc::opmode_t::kFan; + case kToshibaAcOff: return stdAc::opmode_t::kOff; default: return stdAc::opmode_t::kAuto; } } @@ -280,12 +410,13 @@ stdAc::state_t IRToshibaAC::toCommon(void) { result.celsius = true; result.degrees = this->getTemp(); result.fanspeed = this->toCommonFanSpeed(this->getFan()); + result.swingv = (getSwing() == kToshibaAcSwingOn) ? stdAc::swingv_t::kAuto + : stdAc::swingv_t::kOff; + result.turbo = getTurbo(); + result.econo = getEcono(); // Not supported. - result.turbo = false; result.light = false; result.filter = false; - result.econo = false; - result.swingv = stdAc::swingv_t::kOff; result.swingh = stdAc::swingh_t::kOff; result.quiet = false; result.clean = false; @@ -299,14 +430,33 @@ stdAc::state_t IRToshibaAC::toCommon(void) { /// @return A human readable string. String IRToshibaAC::toString(void) { String result = ""; - result.reserve(40); - result += addBoolToString(getPower(), kPowerStr, false); - result += addModeToString(getMode(), kToshibaAcAuto, kToshibaAcCool, - kToshibaAcHeat, kToshibaAcDry, kToshibaAcAuto); - result += addTempToString(getTemp()); - result += addFanToString(getFan(), kToshibaAcFanMax, kToshibaAcFanMin, - kToshibaAcFanAuto, kToshibaAcFanAuto, - kToshibaAcFanMed); + result.reserve(80); + result += addTempToString(getTemp(), true, false); + switch (getStateLength()) { + case kToshibaACStateLengthShort: + result += addIntToString(getSwing(true), kSwingVStr); + result += kSpaceLBraceStr; + switch (getSwing(true)) { + case kToshibaAcSwingOff: result += kOffStr; break; + case kToshibaAcSwingOn: result += kOnStr; break; + case kToshibaAcSwingStep: result += kStepStr; break; + default: result += kUnknownStr; + } + result += ')'; + break; + case kToshibaACStateLengthLong: + case kToshibaACStateLength: + default: + result += addBoolToString(getPower(), kPowerStr); + if (getPower()) + result += addModeToString(getMode(), kToshibaAcAuto, kToshibaAcCool, + kToshibaAcHeat, kToshibaAcDry, kToshibaAcFan); + result += addFanToString(getFan(), kToshibaAcFanMax, kToshibaAcFanMin, + kToshibaAcFanAuto, kToshibaAcFanAuto, + kToshibaAcFanMed); + result += addBoolToString(getTurbo(), kTurboStr); + result += addBoolToString(getEcono(), kEconoStr); + } return result; } @@ -322,8 +472,16 @@ String IRToshibaAC::toString(void) { bool IRrecv::decodeToshibaAC(decode_results* results, uint16_t offset, const uint16_t nbits, const bool strict) { // Compliance - if (strict && nbits != kToshibaACBits) - return false; // Must be called with the correct nr. of bytes. + if (strict) { + switch (nbits) { // Must be called with the correct nr. of bits. + case kToshibaACBits: + case kToshibaACBitsShort: + case kToshibaACBitsLong: + break; + default: + return false; + } + } // Match Header + Data + Footer if (!matchGeneric(results->rawbuf + offset, results->state, @@ -336,7 +494,7 @@ bool IRrecv::decodeToshibaAC(decode_results* results, uint16_t offset, // Compliance if (strict) { // Check that the checksum of the message is correct. - if (!IRToshibaAC::validChecksum(results->state)) return false; + if (!IRToshibaAC::validChecksum(results->state, nbits / 8)) return false; } // Success diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.h b/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.h index 0e5022ae7..803cc59b5 100644 --- a/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.h +++ b/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.h @@ -4,6 +4,10 @@ /// @brief Support for Toshiba protocols. /// @see https://github.com/r45635/HVAC-IR-Control /// @see https://github.com/r45635/HVAC-IR-Control/blob/master/HVAC_ESP8266/HVAC_ESP8266T.ino#L77 +/// @see https://github.com/crankyoldgit/IRremoteESP8266/issues/1205 +/// @see https://docs.google.com/spreadsheets/d/1yidE2fvaO9kpCHfKafIdH31q4uaskYR1OwwrkyOxbp0/edit?usp=drivesdk +/// @see https://www.toshiba-carrier.co.jp/global/about/index.htm +/// @see http://www.toshiba-carrier.co.th/AboutUs/Pages/CompanyProfile.aspx // Supports: // Brand: Toshiba, Model: RAS-B13N3KV2 @@ -12,6 +16,10 @@ // Brand: Toshiba, Model: RAS 18SKP-ES // Brand: Toshiba, Model: WH-TA04NE // Brand: Toshiba, Model: WC-L03SE +// Brand: Carrier, Model: 42NQV060M2 / 38NYV060M2 A/C +// Brand: Carrier, Model: 42NQV050M2 / 38NYV050M2 A/C +// Brand: Carrier, Model: 42NQV035M2 / 38NYV035M2 A/C +// Brand: Carrier, Model: 42NQV025M2 / 38NYV025M2 A/C #ifndef IR_TOSHIBA_H_ #define IR_TOSHIBA_H_ @@ -28,23 +36,53 @@ #endif // Constants +// Byte[0] - 0xF2 +// Byte[1] - 0x0D (inverted previous byte's value) +// Byte[2] - The expected payload length (in bytes) past the Byte[4]. +const uint8_t kToshibaAcLengthByte = 2; ///< Byte pos of the "length" attribute +const uint8_t kToshibaAcMinLength = 6; ///< Min Nr. of bytes in a message. +///< Known lengths are: +///< 1 (56 bit message) +///< 3 (72 bit message) +///< 4 (80 bit message) +// Byte[3] - The bit-inverted value of the "length" byte. +const uint16_t kToshibaAcInvertedLength = 4; ///< Nr. of leading bytes in + ///< inverted pairs. +// Byte[4] +const uint8_t kToshibaAcShortMsgBit = 5; ///< Mask 0b00x00000 +const uint8_t kToshibaAcLongMsgBit = 3; ///< Mask 0b00001000 +// Byte[5] +const uint8_t kToshibaAcSwingOffset = 0; ///< Bit offset. +const uint8_t kToshibaAcSwingSize = 2; ///< Mask 0b000000xx +const uint8_t kToshibaAcSwingStep = 0; ///< 0b00 +const uint8_t kToshibaAcSwingOn = 1; ///< 0b01 +const uint8_t kToshibaAcSwingOff = 2; ///< 0b10 + +const uint8_t kToshibaAcTempOffset = 4; ///< Bit offset. +const uint8_t kToshibaAcTempSize = 4; ///< Mask 0bxxxx0000 +const uint8_t kToshibaAcMinTemp = 17; ///< 17C +const uint8_t kToshibaAcMaxTemp = 30; ///< 30C +// Byte[6] const uint8_t kToshibaAcModeOffset = 0; -const uint8_t kToshibaAcModeSize = 2; // Nr. of bits -const uint8_t kToshibaAcAuto = 0; -const uint8_t kToshibaAcCool = 1; -const uint8_t kToshibaAcDry = 2; -const uint8_t kToshibaAcHeat = 3; -const uint8_t kToshibaAcPowerOffset = 2; +const uint8_t kToshibaAcModeSize = 3; // Mask 0b00000xxx +const uint8_t kToshibaAcAuto = 0; // 0b000 +const uint8_t kToshibaAcCool = 1; // 0b001 +const uint8_t kToshibaAcDry = 2; // 0b010 +const uint8_t kToshibaAcHeat = 3; // 0b011 +const uint8_t kToshibaAcFan = 4; // 0b100 +const uint8_t kToshibaAcOff = 7; // 0b111 const uint8_t kToshibaAcFanOffset = 5; -const uint8_t kToshibaAcFanSize = 3; // Nr. of bits -const uint8_t kToshibaAcFanAuto = 0b000; -const uint8_t kToshibaAcFanMin = 0b001; -const uint8_t kToshibaAcFanMed = 0b011; -const uint8_t kToshibaAcFanMax = 0b101; -const uint8_t kToshibaAcTempOffset = 4; -const uint8_t kToshibaAcTempSize = 4; // Nr. of bits -const uint8_t kToshibaAcMinTemp = 17; // 17C -const uint8_t kToshibaAcMaxTemp = 30; // 30C +const uint8_t kToshibaAcFanSize = 3; // Mask 0bxxx00000 +const uint8_t kToshibaAcFanAuto = 0; // 0b000 +const uint8_t kToshibaAcFanMin = 1; // 0b001 +const uint8_t kToshibaAcFanMed = 3; // 0b011 +const uint8_t kToshibaAcFanMax = 5; // 0b101 +// Byte[8] (Checksum for 72 bit messages, Eco/Turbo for long 80 bit messages) +const uint8_t kToshibaAcEcoTurboOffset = 0; +const uint8_t kToshibaAcEcoTurboSize = 2; // Mask 0b000000xx +const uint8_t kToshibaAcTurboOn = 1; // 0b01 +const uint8_t kToshibaAcEconoOn = 3; // 0b11 +// Byte[last] - Checksum (xor) // Legacy defines. (Deperecated) #define TOSHIBA_AC_AUTO kToshibaAcAuto @@ -81,12 +119,21 @@ class IRToshibaAC { uint8_t getTemp(void); void setFan(const uint8_t speed); uint8_t getFan(void); + void setTurbo(const bool on); + bool getTurbo(void); + void setEcono(const bool on); + bool getEcono(void); void setMode(const uint8_t mode); - uint8_t getMode(const bool useRaw = false); + uint8_t getMode(const bool raw = false); void setRaw(const uint8_t newState[]); uint8_t* getRaw(void); + static uint16_t getInternalStateLength(const uint8_t state[], + const uint16_t size); + uint16_t getStateLength(void); static bool validChecksum(const uint8_t state[], const uint16_t length = kToshibaACStateLength); + uint8_t getSwing(const bool raw = true); + void setSwing(const uint8_t setting); uint8_t convertMode(const stdAc::opmode_t mode); uint8_t convertFan(const stdAc::fanspeed_t speed); static stdAc::opmode_t toCommonMode(const uint8_t mode); @@ -102,11 +149,17 @@ class IRToshibaAC { IRsendTest _irsend; ///< Instance of the testing IR send class /// @endcond #endif // UNIT_TEST - uint8_t remote_state[kToshibaACStateLength]; ///< The state in IR code form. + uint8_t remote_state[kToshibaACStateLengthLong]; ///< The state in code form. + uint8_t backup[kToshibaACStateLengthLong]; ///< A backup copy of the state. + uint8_t prev_mode; ///< Store of the previously set mode. + bool _send_swing; ///< Flag indicating if we need to send a swing message. + uint8_t _swing_mode; ///< The saved swing state/mode/command. void checksum(const uint16_t length = kToshibaACStateLength); static uint8_t calcChecksum(const uint8_t state[], const uint16_t length = kToshibaACStateLength); - uint8_t mode_state; + void setStateLength(const uint16_t size); + void _backupState(void); + void _restoreState(void); }; #endif // IR_TOSHIBA_H_ diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/defaults.h b/lib/IRremoteESP8266-2.7.8/src/locale/defaults.h index 340e2b8fe..7fc0990e1 100644 --- a/lib/IRremoteESP8266-2.7.8/src/locale/defaults.h +++ b/lib/IRremoteESP8266-2.7.8/src/locale/defaults.h @@ -360,6 +360,9 @@ // Compound words/phrases/descriptions from pre-defined words. // Note: Obviously these need to be defined *after* their component words. +#ifndef D_STR_ECONOTOGGLE +#define D_STR_ECONOTOGGLE D_STR_ECONO " " D_STR_TOGGLE +#endif // D_STR_ECONOTOGGLE #ifndef D_STR_EYEAUTO #define D_STR_EYEAUTO D_STR_EYE " " D_STR_AUTO #endif // D_STR_EYEAUTO @@ -685,6 +688,9 @@ #ifndef D_STR_SANYO #define D_STR_SANYO "SANYO" #endif // D_STR_SANYO +#ifndef D_STR_SANYO_AC +#define D_STR_SANYO_AC "SANYO_AC" +#endif // D_STR_SANYO_AC #ifndef D_STR_SANYO_LC7461 #define D_STR_SANYO_LC7461 "SANYO_LC7461" #endif // D_STR_SANYO_LC7461 diff --git a/lib/IRremoteESP8266-2.7.8/test/IRac_test.cpp b/lib/IRremoteESP8266-2.7.8/test/IRac_test.cpp index a0f975666..f91be3459 100644 --- a/lib/IRremoteESP8266-2.7.8/test/IRac_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/IRac_test.cpp @@ -1,6 +1,7 @@ // Copyright 2019 David Conran #include +#include "ir_Airwell.h" #include "ir_Amcor.h" #include "ir_Argo.h" #include "ir_Carrier.h" @@ -39,10 +40,33 @@ // Tests for IRac class. +TEST(TestIRac, Airwell) { + IRAirwellAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + char expected[] = + "Power Toggle: On, Mode: 3 (Auto), Fan: 1 (Medium), Temp: 18C"; + + ac.begin(); + irac.airwell(&ac, + true, // Power + stdAc::opmode_t::kAuto, // Mode + 18, // Celsius + stdAc::fanspeed_t::kMedium); // Fan speed + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(AIRWELL, ac._irsend.capture.decode_type); + ASSERT_EQ(kAirwellBits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); +} + TEST(TestIRac, Amcor) { - IRAmcorAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRAmcorAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 5 (Auto), Fan: 3 (High), Temp: 19C, Max: Off"; @@ -63,8 +87,8 @@ TEST(TestIRac, Amcor) { } TEST(TestIRac, Argo) { - IRArgoAC ac(0); - IRac irac(0); + IRArgoAC ac(kGpioUnused); + IRac irac(kGpioUnused); ac.begin(); irac.argo(&ac, @@ -118,9 +142,9 @@ TEST(TestIRac, Carrier64) { } TEST(TestIRac, Coolix) { - IRCoolixAC ac(0); - IRac irac(0); - IRrecv capture(0); + IRCoolixAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 3 (Heat), Fan: 1 (Max), Temp: 21C, Zone Follow: Off, " "Sensor Temp: Off"; @@ -221,9 +245,9 @@ TEST(TestIRac, Corona) { } TEST(TestIRac, Daikin) { - IRDaikinESP ac(0); - IRac irac(0); - IRrecv capture(0); + IRDaikinESP ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 3 (Cool), Temp: 19C, Fan: 5 (High), Powerful: Off, " "Quiet: Off, Sensor: Off, Mould: On, Comfort: Off, " @@ -254,9 +278,9 @@ TEST(TestIRac, Daikin) { } TEST(TestIRac, Daikin128) { - IRDaikin128 ac(0); - IRac irac(0); - IRrecv capture(0); + IRDaikin128 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power Toggle: On, Mode: 8 (Heat), Temp: 27C, Fan: 9 (Quiet), " "Powerful: Off, Quiet: On, Swing(V): On, Sleep: On, " @@ -287,9 +311,9 @@ TEST(TestIRac, Daikin128) { } TEST(TestIRac, Daikin152) { - IRDaikin152 ac(0); - IRac irac(0); - IRrecv capture(0); + IRDaikin152 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 3 (Cool), Temp: 27C, Fan: 3 (Medium), Swing(V): On, " "Powerful: Off, Quiet: Off, Econo: On, Sensor: Off, Comfort: Off"; @@ -315,9 +339,9 @@ TEST(TestIRac, Daikin152) { } TEST(TestIRac, Daikin160) { - IRDaikin160 ac(0); - IRac irac(0); - IRrecv capture(0); + IRDaikin160 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 2 (Dry), Temp: 23C, Fan: 1 (Low), " "Swing(V): 3 (Middle)"; @@ -340,9 +364,9 @@ TEST(TestIRac, Daikin160) { } TEST(TestIRac, Daikin176) { - IRDaikin176 ac(0); - IRac irac(0); - IRrecv capture(0); + IRDaikin176 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 7 (Cool), Temp: 26C, Fan: 1 (Low), Swing(H): 5 (Auto)"; @@ -364,9 +388,9 @@ TEST(TestIRac, Daikin176) { } TEST(TestIRac, Daikin2) { - IRDaikin2 ac(0); - IRac irac(0); - IRrecv capture(0); + IRDaikin2 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 3 (Cool), Temp: 19C, Fan: 1 (Low), " "Swing(V): 14 (Auto), Swing(H): 170 (UNKNOWN), Clock: 00:00, " @@ -402,9 +426,9 @@ TEST(TestIRac, Daikin2) { } TEST(TestIRac, Daikin216) { - IRDaikin216 ac(0); - IRac irac(0); - IRrecv capture(0); + IRDaikin216 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 4 (Heat), Temp: 31C, Fan: 11 (Quiet), " "Swing(H): On, Swing(V): On, Quiet: On, Powerful: Off"; @@ -511,9 +535,9 @@ TEST(TestIRac, Electra) { } TEST(TestIRac, Fujitsu) { - IRFujitsuAC ac(0); - IRac irac(0); - IRrecv capture(0); + IRFujitsuAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); std::string ardb1_expected = "Model: 2 (ARDB1), Power: On, Mode: 1 (Cool), Temp: 19C, " "Fan: 2 (Medium), Command: N/A"; @@ -591,9 +615,9 @@ TEST(TestIRac, Fujitsu) { } TEST(TestIRac, Goodweather) { - IRGoodweatherAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRGoodweatherAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 1 (Cool), Temp: 19C, Fan: 2 (Medium), Turbo: Toggle, " "Light: Toggle, Sleep: Toggle, Swing: 1 (Slow), Command: 0 (Power)"; @@ -619,9 +643,9 @@ TEST(TestIRac, Goodweather) { } TEST(TestIRac, Gree) { - IRGreeAC ac(0); - IRac irac(0); - IRrecv capture(0); + IRGreeAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Model: 1 (YAW1F), Power: On, Mode: 1 (Cool), Temp: 71F, " "Fan: 2 (Medium), Turbo: Off, IFeel: Off, WiFi: Off, XFan: On, " @@ -652,9 +676,9 @@ TEST(TestIRac, Gree) { } TEST(TestIRac, Haier) { - IRHaierAC ac(0); - IRac irac(0); - IRrecv capture(0); + IRHaierAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Command: 1 (On), Mode: 1 (Cool), Temp: 24C, Fan: 2 (Medium), " "Swing: 1 (Up), Sleep: On, Health: On, Clock: 13:45, " @@ -682,9 +706,9 @@ TEST(TestIRac, Haier) { TEST(TestIRac, HaierYrwo2) { - IRHaierACYRW02 ac(0); - IRac irac(0); - IRrecv capture(0); + IRHaierACYRW02 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Button: 5 (Power), Mode: 1 (Cool), Temp: 23C, " "Fan: 2 (Medium), Turbo: 1 (High), Swing: 1 (Highest), Sleep: On, " @@ -711,9 +735,9 @@ TEST(TestIRac, HaierYrwo2) { } TEST(TestIRac, Hitachi) { - IRHitachiAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRHitachiAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 2 (Auto), Temp: 22C, Fan: 3 (Medium), " "Swing(V): Off, Swing(H): On"; @@ -821,9 +845,9 @@ TEST(TestIRac, Hitachi344) { } TEST(TestIRac, Hitachi424) { - IRHitachiAc424 ac(0); - IRac irac(0); - IRrecv capture(0); + IRHitachiAc424 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 6 (Heat), Temp: 25C, Fan: 6 (Max), " "Button: 19 (Power/Mode), Swing(V) Toggle: Off"; @@ -866,9 +890,9 @@ TEST(TestIRac, Hitachi424) { } TEST(TestIRac, Kelvinator) { - IRKelvinatorAC ac(0); - IRac irac(0); - IRrecv capture(0); + IRKelvinatorAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 1 (Cool), Temp: 19C, Fan: 3 (Medium), Turbo: Off, " "Quiet: Off, XFan: On, Ion: On, Light: On, " @@ -899,9 +923,9 @@ TEST(TestIRac, Kelvinator) { } TEST(TestIRac, LG) { - IRLgAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRLgAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Model: 1 (GE6711AR2853M), " "Power: On, Mode: 1 (Dry), Temp: 27C, Fan: 2 (Medium)"; @@ -925,12 +949,12 @@ TEST(TestIRac, LG) { } TEST(TestIRac, Midea) { - IRMideaAC ac(0); - IRac irac(0); - IRrecv capture(0); + IRMideaAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 1 (Dry), Celsius: On, Temp: 27C/80F, Fan: 2 (Medium), " - "Sleep: On, Swing(V) Toggle: Off"; + "Sleep: On, Swing(V) Toggle: Off, Econo Toggle: Off"; ac.begin(); irac.midea(&ac, @@ -940,6 +964,7 @@ TEST(TestIRac, Midea) { 27, // Degrees stdAc::fanspeed_t::kMedium, // Fan speed stdAc::swingv_t::kOff, // Swing(V) + false, // Econo 8 * 60 + 0); // Sleep time ASSERT_EQ(expected, ac.toString()); @@ -953,9 +978,9 @@ TEST(TestIRac, Midea) { } TEST(TestIRac, Mitsubishi) { - IRMitsubishiAC ac(0); - IRac irac(0); - IRrecv capture(0); + IRMitsubishiAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 2 (Medium), " "Swing(V): 0 (Auto), Swing(H): 3 (UNKNOWN), " @@ -982,9 +1007,9 @@ TEST(TestIRac, Mitsubishi) { } TEST(TestIRac, Mitsubishi136) { - IRMitsubishi136 ac(0); - IRac irac(0); - IRrecv capture(0); + IRMitsubishi136 ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 5 (Dry), Temp: 22C, Fan: 3 (High), " "Swing(V): 3 (Highest), Quiet: Off"; @@ -1008,9 +1033,9 @@ TEST(TestIRac, Mitsubishi136) { } TEST(TestIRac, MitsubishiHeavy88) { - IRMitsubishiHeavy88Ac ac(0); - IRac irac(0); - IRrecv capture(0); + IRMitsubishiHeavy88Ac ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 1 (Cool), Temp: 21C, Fan: 3 (Med), " "Swing(V): 4 (Auto), Swing(H): 0 (Off), Turbo: Off, Econo: Off, " @@ -1038,9 +1063,9 @@ TEST(TestIRac, MitsubishiHeavy88) { } TEST(TestIRac, MitsubishiHeavy152) { - IRMitsubishiHeavy152Ac ac(0); - IRac irac(0); - IRrecv capture(0); + IRMitsubishiHeavy152Ac ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 6 (Econo), " "Swing(V): 6 (Off), Swing(H): 0 (Auto), Silent: On, Turbo: Off, " @@ -1071,9 +1096,9 @@ TEST(TestIRac, MitsubishiHeavy152) { } TEST(TestIRac, Neoclima) { - IRNeoclimaAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRNeoclimaAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 1 (Cool), Temp: 20C, Fan: 3 (Low), " "Swing(V): Off, Swing(H): On, Sleep: On, Turbo: Off, Hold: Off, Ion: On, " @@ -1103,9 +1128,9 @@ TEST(TestIRac, Neoclima) { } TEST(TestIRac, Panasonic) { - IRPanasonicAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRPanasonicAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected_nke[] = "Model: 2 (NKE), Power: On, Mode: 4 (Heat), Temp: 28C, Fan: 2 (Medium), " "Swing(V): 15 (Auto), Swing(H): 6 (Middle), Quiet: On, " @@ -1161,9 +1186,9 @@ TEST(TestIRac, Panasonic) { } TEST(TestIRac, Samsung) { - IRSamsungAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRSamsungAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 0 (Auto), Temp: 28C, Fan: 6 (Auto), Swing: On, " "Beep: On, Clean: On, Quiet: On, Powerful: Off, Breeze: Off, " @@ -1223,10 +1248,38 @@ TEST(TestIRac, Samsung) { ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); } +TEST(TestIRac, Sanyo) { + IRSanyoAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + char expected[] = + "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), " + "Swing(V): 7 (Highest), Sleep: On, Beep: On, " + "Sensor: Wall, Sensor Temp: 28C, Off Timer: Off"; + + ac.begin(); + irac.sanyo(&ac, + true, // Power + stdAc::opmode_t::kCool, // Mode + 28, // Celsius + stdAc::fanspeed_t::kMedium, // Fan speed + stdAc::swingv_t::kHighest, // Vertical Swing + true, // Beep + 17); // Sleep + ASSERT_EQ(expected, ac.toString()); + ac._irsend.makeDecodeResult(); + EXPECT_TRUE(capture.decode(&ac._irsend.capture)); + ASSERT_EQ(SANYO_AC, ac._irsend.capture.decode_type); + ASSERT_EQ(kSanyoAcBits, ac._irsend.capture.bits); + ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); + stdAc::state_t r, p; + ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); +} + TEST(TestIRac, Sharp) { - IRSharpAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRSharpAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 2 (Cool), Temp: 28C, Fan: 3 (Medium), " "Turbo: Off, Swing(V) Toggle: On, Ion: On, Econo: -, Clean: Off"; @@ -1253,9 +1306,9 @@ TEST(TestIRac, Sharp) { } TEST(TestIRac, Tcl112) { - IRTcl112Ac ac(0); - IRac irac(0); - IRrecv capture(0); + IRTcl112Ac ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 3 (Cool), Temp: 20C, Fan: 3 (Medium), Econo: On, " "Health: On, Light: On, Turbo: Off, Swing(H): On, Swing(V): Off"; @@ -1283,9 +1336,9 @@ TEST(TestIRac, Tcl112) { } TEST(TestIRac, Teco) { - IRTecoAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRTecoAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 0 (Auto), Temp: 21C, Fan: 2 (Medium), Sleep: On, " "Swing: On, Light: On, Humid: Off, Save: Off, Timer: Off"; @@ -1310,31 +1363,82 @@ TEST(TestIRac, Teco) { } TEST(TestIRac, Toshiba) { - IRToshibaAC ac(0); - IRac irac(0); - IRrecv capture(0); - char expected[] = "Power: On, Mode: 2 (Dry), Temp: 29C, Fan: 2 (UNKNOWN)"; + IRToshibaAC ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + char expected[] = + "Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), " + "Turbo: Off, Econo: On"; ac.begin(); irac.toshiba(&ac, true, // Power stdAc::opmode_t::kDry, // Mode 29, // Celsius - stdAc::fanspeed_t::kLow); // Fan speed + stdAc::fanspeed_t::kLow, // Fan speed + stdAc::swingv_t::kOff, // Vertical Swing + false, // Turbo + true); // Econo ASSERT_EQ(expected, ac.toString()); + ASSERT_EQ(kToshibaACStateLengthLong, ac.getStateLength()); ac._irsend.makeDecodeResult(); EXPECT_TRUE(capture.decode(&ac._irsend.capture)); ASSERT_EQ(TOSHIBA_AC, ac._irsend.capture.decode_type); - ASSERT_EQ(kToshibaACBits, ac._irsend.capture.bits); + ASSERT_EQ(kToshibaACBitsLong, ac._irsend.capture.bits); ASSERT_EQ(expected, IRAcUtils::resultAcToString(&ac._irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); + EXPECT_EQ( + "f38000d50" + "m4400s4300" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s1600m580s490m580s490" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s1600m580s1600" + "m580s490m580s490m580s490m580s490m580s1600m580s490m580s490m580s1600" + "m580s1600m580s1600m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s1600m580s1600m580s490m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s490m580s1600m580s490m580s1600m580s490m580s490m580s490" + "m580s7400" + "m4400s4300" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s1600m580s490m580s490" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s1600m580s1600" + "m580s490m580s490m580s490m580s490m580s1600m580s490m580s490m580s1600" + "m580s1600m580s1600m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s1600m580s1600m580s490m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s490m580s1600m580s490m580s1600m580s490m580s490m580s490" + "m580s7400" + "m4400s4300" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490" + "m580s490m580s490m580s1600m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s1600m580s490m580s490m580s490m580s1600m580s1600" + "m580s7400" + "m4400s4300" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490" + "m580s490m580s490m580s1600m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s1600m580s490m580s490m580s490m580s1600m580s1600" + "m580s7400", + ac._irsend.outputStr()); } TEST(TestIRac, Trotec) { - IRTrotecESP ac(0); - IRac irac(0); - IRrecv capture(0); + IRTrotecESP ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 1 (Cool), Temp: 18C, Fan: 3 (High), Sleep: On"; @@ -1361,9 +1465,9 @@ TEST(TestIRac, Trotec) { } TEST(TestIRac, Vestel) { - IRVestelAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRVestelAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Power: On, Mode: 0 (Auto), Temp: 22C, Fan: 5 (Low), Sleep: On, " "Turbo: Off, Ion: On, Swing: On"; @@ -1452,9 +1556,9 @@ TEST(TestIRac, Vestel) { TEST(TestIRac, Whirlpool) { - IRWhirlpoolAc ac(0); - IRac irac(0); - IRrecv capture(0); + IRWhirlpoolAc ac(kGpioUnused); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); char expected[] = "Model: 1 (DG11J13A), Power Toggle: On, Mode: 1 (Auto), Temp: 21C, " "Fan: 3 (Low), Swing: On, Light: On, Clock: 23:58, On Timer: Off, " @@ -1755,9 +1859,9 @@ TEST(TestIRac, Issue821) { next = prev; next.light = true; - IRac irac(0); - IRrecv capture(0); - IRCoolixAC ac(0); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + IRCoolixAC ac(kGpioUnused); ac.begin(); result = irac.handleToggles(next, &prev); @@ -1844,9 +1948,9 @@ TEST(TestIRac, Issue1001) { desired = prev; desired.power = false; - IRac irac(0); - IRrecv capture(0); - IRWhirlpoolAc ac(0); + IRac irac(kGpioUnused); + IRrecv capture(kGpioUnused); + IRWhirlpoolAc ac(kGpioUnused); ac.begin(); ASSERT_TRUE(prev.power); diff --git a/lib/IRremoteESP8266-2.7.8/test/IRutils_test.cpp b/lib/IRremoteESP8266-2.7.8/test/IRutils_test.cpp index ecb23dbbf..0dde7ec04 100644 --- a/lib/IRremoteESP8266-2.7.8/test/IRutils_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/IRutils_test.cpp @@ -220,32 +220,32 @@ TEST(TestResultToSourceCode, ComplexProtocols) { ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); ASSERT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_EQ( - "uint16_t rawData[296] = {4400, 4300, 542, 1622, 542, 1622, " - "542, 1622, 542, 1622, 542, 472, 542, 472, 542, 1622, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 1622, 542, 1622, " - "542, 472, 542, 1622, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 1622, 542, 1622, 542, 1622, 542, 1622, " - "542, 1622, 542, 1622, 542, 1622, 542, 1622, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 1622, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 1622, 542, 7048, 4400, 4300, " - "542, 1622, 542, 1622, 542, 1622, 542, 1622, 542, 472, 542, 472, " - "542, 1622, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 1622, 542, 1622, 542, 472, 542, 1622, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 1622, 542, 1622, " - "542, 1622, 542, 1622, 542, 1622, 542, 1622, 542, 1622, 542, 1622, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 1622, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 472, " - "542, 472, 542, 472, 542, 472, 542, 472, 542, 472, 542, 1622, " - "542, 7048 }; // TOSHIBA_AC\n" + "uint16_t rawData[296] = {4400, 4300, 580, 1600, 580, 1600, " + "580, 1600, 580, 1600, 580, 490, 580, 490, 580, 1600, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 1600, 580, 1600, " + "580, 490, 580, 1600, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 1600, 580, 1600, 580, 1600, 580, 1600, " + "580, 1600, 580, 1600, 580, 1600, 580, 1600, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 1600, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 1600, 580, 7400, 4400, 4300, " + "580, 1600, 580, 1600, 580, 1600, 580, 1600, 580, 490, 580, 490, " + "580, 1600, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 1600, 580, 1600, 580, 490, 580, 1600, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 1600, 580, 1600, " + "580, 1600, 580, 1600, 580, 1600, 580, 1600, 580, 1600, 580, 1600, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 1600, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 490, " + "580, 490, 580, 490, 580, 490, 580, 490, 580, 490, 580, 1600, " + "580, 7400 }; // TOSHIBA_AC\n" "uint8_t state[9] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, " "0x01};\n", resultToSourceCode(&irsend.capture)); @@ -744,3 +744,35 @@ TEST(TestUtils, setBits64Bit) { irutils::setBits(&data, 32, 4, 0b1001); EXPECT_EQ(0x4000000900000013, data); } + +TEST(TestUtils, InvertedBytePairs) { + const uint8_t correct[] = {0x00, 0xFF, 0x01, 0xFE, 0xAA, 0x55}; + uint8_t wrong[] = {0x00, 0xFF, 0x01, 0xFD, 0xAA, 0x55}; + + ASSERT_TRUE(irutils::checkInvertedBytePairs(correct, 6)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(correct, 5)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(correct, 4)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(correct, 3)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(correct, 2)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(correct, 1)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(correct, 0)); + + ASSERT_FALSE(irutils::checkInvertedBytePairs(wrong, 6)); + ASSERT_FALSE(irutils::checkInvertedBytePairs(wrong, 5)); + ASSERT_FALSE(irutils::checkInvertedBytePairs(wrong, 4)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(wrong, 3)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(wrong, 2)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(wrong, 1)); + ASSERT_TRUE(irutils::checkInvertedBytePairs(wrong, 0)); + + irutils::invertBytePairs(wrong, 0); + ASSERT_FALSE(irutils::checkInvertedBytePairs(wrong, 6)); + irutils::invertBytePairs(wrong, 1); + ASSERT_FALSE(irutils::checkInvertedBytePairs(wrong, 6)); + irutils::invertBytePairs(wrong, 2); + ASSERT_FALSE(irutils::checkInvertedBytePairs(wrong, 6)); + + irutils::invertBytePairs(wrong, 6); + ASSERT_TRUE(irutils::checkInvertedBytePairs(wrong, 6)); + EXPECT_STATE_EQ(correct, wrong, 6 * 8); +} diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Airwell_test.cpp b/lib/IRremoteESP8266-2.7.8/test/ir_Airwell_test.cpp index 09300bac2..e5f28d4df 100644 --- a/lib/IRremoteESP8266-2.7.8/test/ir_Airwell_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/ir_Airwell_test.cpp @@ -1,5 +1,6 @@ // Copyright 2020 David Conran +#include "ir_Airwell.h" #include "IRac.h" #include "IRrecv.h" #include "IRrecv_test.h" @@ -44,6 +45,9 @@ TEST(TestDecodeAirwell, RealExample) { EXPECT_EQ(0x2B0D0181B, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_EQ( + "Power Toggle: On, Mode: 2 (Heat), Fan: 3 (Auto), Temp: 25C", + IRAcUtils::resultAcToString(&irsend.capture)); const uint16_t rawData_2[175] = { 2862, 3892, @@ -76,6 +80,9 @@ TEST(TestDecodeAirwell, RealExample) { EXPECT_EQ(0x270F8181B, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_EQ( + "Power Toggle: On, Mode: 1 (Cool), Fan: 3 (Auto), Temp: 30C", + IRAcUtils::resultAcToString(&irsend.capture)); } TEST(TestDecodeAirwell, SyntheticExample) { @@ -192,6 +199,9 @@ TEST(TestDecodeAirwell, RealExample2) { EXPECT_EQ(0xB0C0181B, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_EQ( + "Power Toggle: Off, Mode: 2 (Heat), Fan: 3 (Auto), Temp: 23C", + IRAcUtils::resultAcToString(&irsend.capture)); // Resend it as a synthetic to see if it decodes to the same value. irsend.reset(); @@ -210,7 +220,7 @@ TEST(TestUtils, Housekeeping) { ASSERT_EQ("AIRWELL", typeToString(decode_type_t::AIRWELL)); ASSERT_EQ(decode_type_t::AIRWELL, strToDecodeType("AIRWELL")); ASSERT_FALSE(hasACState(decode_type_t::AIRWELL)); - ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::AIRWELL)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::AIRWELL)); ASSERT_EQ(kAirwellBits, IRsend::defaultBits(decode_type_t::AIRWELL)); ASSERT_EQ(kAirwellMinRepeats, IRsend::minRepeats(decode_type_t::AIRWELL)); } @@ -250,4 +260,142 @@ TEST(TestDecodeAirwell, RealExample3) { EXPECT_EQ(0x60080002, irsend.capture.value); EXPECT_EQ(0x0, irsend.capture.address); EXPECT_EQ(0x0, irsend.capture.command); + EXPECT_EQ( + "Power Toggle: Off, Mode: 1 (Cool), Fan: 2 (High), Temp: 16C", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +// Tests for IRAirwellAc class. + +TEST(TestAirwellAcClass, PowerToggle) { + IRAirwellAc ac(kGpioUnused); + ac.begin(); + + ac.setPowerToggle(true); + EXPECT_TRUE(ac.getPowerToggle()); + ac.setPowerToggle(false); + EXPECT_FALSE(ac.getPowerToggle()); + ac.setPowerToggle(true); + EXPECT_TRUE(ac.getPowerToggle()); +} + +TEST(TestAirwellAcClass, Temperature) { + IRAirwellAc ac(kGpioUnused); + ac.begin(); + + ac.setTemp(0); + EXPECT_EQ(kAirwellMinTemp, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kAirwellMaxTemp, ac.getTemp()); + + ac.setTemp(kAirwellMinTemp); + EXPECT_EQ(kAirwellMinTemp, ac.getTemp()); + + ac.setTemp(kAirwellMaxTemp); + EXPECT_EQ(kAirwellMaxTemp, ac.getTemp()); + + ac.setTemp(kAirwellMinTemp - 1); + EXPECT_EQ(kAirwellMinTemp, ac.getTemp()); + + ac.setTemp(kAirwellMaxTemp + 1); + EXPECT_EQ(kAirwellMaxTemp, ac.getTemp()); + + ac.setTemp(17); + EXPECT_EQ(17, ac.getTemp()); + + ac.setTemp(21); + EXPECT_EQ(21, ac.getTemp()); + + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + + ac.setTemp(29); + EXPECT_EQ(29, ac.getTemp()); +} + +TEST(TestAirwellAcClass, OperatingMode) { + IRAirwellAc ac(kGpioUnused); + ac.begin(); + + ac.setMode(kAirwellAuto); + EXPECT_EQ(kAirwellAuto, ac.getMode()); + + ac.setMode(kAirwellCool); + EXPECT_EQ(kAirwellCool, ac.getMode()); + + ac.setMode(kAirwellHeat); + EXPECT_EQ(kAirwellHeat, ac.getMode()); + + ac.setMode(kAirwellDry); + EXPECT_EQ(kAirwellDry, ac.getMode()); + + ac.setMode(kAirwellFan); + EXPECT_EQ(kAirwellFan, ac.getMode()); + + ac.setMode(kAirwellFan + 1); + EXPECT_EQ(kAirwellAuto, ac.getMode()); + + ac.setMode(255); + EXPECT_EQ(kAirwellAuto, ac.getMode()); +} + +TEST(TestAirwellAcClass, FanSpeed) { + IRAirwellAc ac(0); + ac.begin(); + + ac.setFan(0); + EXPECT_EQ(kAirwellFanLow, ac.getFan()); + + ac.setFan(255); + EXPECT_EQ(kAirwellFanAuto, ac.getFan()); + + ac.setFan(kAirwellFanHigh); + EXPECT_EQ(kAirwellFanHigh, ac.getFan()); + + ac.setFan(kAirwellFanHigh + 2); + EXPECT_EQ(kAirwellFanAuto, ac.getFan()); + + ac.setFan(kAirwellFanHigh - 1); + EXPECT_EQ(kAirwellFanHigh - 1, ac.getFan()); + + ac.setFan(1); + EXPECT_EQ(1, ac.getFan()); + + ac.setFan(1); + EXPECT_EQ(1, ac.getFan()); + + ac.setFan(3); + EXPECT_EQ(3, ac.getFan()); +} + +// Test human readable output. +TEST(TestAirwellAcClass, HumanReadable) { + IRAirwellAc ac(kGpioUnused); + EXPECT_EQ( + "Power Toggle: Off, Mode: 5 (Fan), Fan: 0 (Low), Temp: 25C", + ac.toString()); + ac.setPowerToggle(true); + ac.setMode(kAirwellHeat); + ac.setTemp(30); + ac.setFan(kAirwellFanAuto); + EXPECT_EQ( + "Power Toggle: On, Mode: 2 (Heat), Fan: 3 (Auto), Temp: 30C", + ac.toString()); +} + +TEST(TestAirwellAcClass, ReconstructKnownState) { + IRAirwellAc ac(kGpioUnused); + const uint64_t expected = 0x240380002; + ac.begin(); + ac.stateReset(); + ASSERT_NE(expected, ac.getRaw()); + ac.setPowerToggle(true); + ac.setMode(kAirwellCool); + ac.setTemp(22); + ac.setFan(kAirwellFanLow); + EXPECT_EQ(expected, ac.getRaw()); + EXPECT_EQ( + "Power Toggle: On, Mode: 1 (Cool), Fan: 0 (Low), Temp: 22C", + ac.toString()); } diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_LG_test.cpp b/lib/IRremoteESP8266-2.7.8/test/ir_LG_test.cpp index d899576b9..8d5dc1246 100644 --- a/lib/IRremoteESP8266-2.7.8/test/ir_LG_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/ir_LG_test.cpp @@ -448,7 +448,7 @@ TEST(TestDecodeLG, Issue620) { // Resend the same code as the report is a sent code doesn't decode // to the same message code. - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); irsend.sendLG(0x8808721); irsend.makeDecodeResult(); ASSERT_TRUE(irrecv.decode(&irsend.capture)); @@ -477,7 +477,7 @@ TEST(TestDecodeLG, Issue620) { } TEST(TestIRLgAcClass, SetAndGetPower) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.on(); EXPECT_TRUE(ac.getPower()); ac.off(); @@ -489,7 +489,7 @@ TEST(TestIRLgAcClass, SetAndGetPower) { } TEST(TestIRLgAcClass, SetAndGetTemp) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setTemp(25); EXPECT_EQ(25, ac.getTemp()); ac.setTemp(kLgAcMinTemp); @@ -503,7 +503,7 @@ TEST(TestIRLgAcClass, SetAndGetTemp) { } TEST(TestIRLgAcClass, SetAndGetMode) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setMode(kLgAcCool); ac.setFan(kLgAcFanAuto); ac.setTemp(25); @@ -517,22 +517,22 @@ TEST(TestIRLgAcClass, SetAndGetMode) { } TEST(TestIRLgAcClass, SetAndGetFan) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setMode(kLgAcCool); ac.setFan(kLgAcFanAuto); EXPECT_EQ(kLgAcFanAuto, ac.getFan()); - ac.setFan(kLgAcFanLow); - EXPECT_EQ(kLgAcFanLow, ac.getFan()); + ac.setFan(kLgAcFanLowest); + EXPECT_EQ(kLgAcFanLowest, ac.getFan()); ac.setFan(kLgAcFanHigh); EXPECT_EQ(kLgAcFanHigh, ac.getFan()); ac.setFan(kLgAcFanAuto + 1); EXPECT_EQ(kLgAcFanAuto, ac.getFan()); - ac.setFan(kLgAcFanLow - 1); + ac.setFan(kLgAcFanLowest - 1); EXPECT_EQ(kLgAcFanAuto, ac.getFan()); } TEST(TestIRLgAcClass, toCommon) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setPower(true); ac.setMode(kLgAcCool); ac.setTemp(20); @@ -564,7 +564,7 @@ TEST(TestIRLgAcClass, toCommon) { } TEST(TestIRLgAcClass, HumanReadable) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); EXPECT_EQ( "Model: 1 (GE6711AR2853M), " @@ -583,17 +583,17 @@ TEST(TestIRLgAcClass, HumanReadable) { ac.setTemp(kLgAcMinTemp); EXPECT_EQ( "Model: 1 (GE6711AR2853M), " - "Power: On, Mode: 0 (Cool), Temp: 16C, Fan: 0 (Low)", + "Power: On, Mode: 0 (Cool), Temp: 16C, Fan: 1 (Low)", ac.toString()); ac.setTemp(ac.getTemp() + 1); EXPECT_EQ( "Model: 1 (GE6711AR2853M), " - "Power: On, Mode: 0 (Cool), Temp: 17C, Fan: 0 (Low)", + "Power: On, Mode: 0 (Cool), Temp: 17C, Fan: 1 (Low)", ac.toString()); ac.setTemp(ac.getTemp() - 1); EXPECT_EQ( "Model: 1 (GE6711AR2853M), " - "Power: On, Mode: 0 (Cool), Temp: 16C, Fan: 0 (Low)", + "Power: On, Mode: 0 (Cool), Temp: 16C, Fan: 1 (Low)", ac.toString()); ac.setPower(false); EXPECT_EQ( @@ -603,7 +603,7 @@ TEST(TestIRLgAcClass, HumanReadable) { } TEST(TestIRLgAcClass, SetAndGetRaw) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setRaw(0x8800A4E); ASSERT_EQ(0x8800A4E, ac.getRaw()); @@ -621,7 +621,7 @@ TEST(TestIRLgAcClass, SetAndGetRaw) { } TEST(TestIRLgAcClass, MessageConstruction) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.on(); ac.setMode(kLgAcCool); @@ -635,7 +635,7 @@ TEST(TestIRLgAcClass, MessageConstruction) { } TEST(TestIRLgAcClass, isValidLgAc) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setRaw(0x8800A4E); ASSERT_TRUE(ac.isValidLgAc()); @@ -670,7 +670,7 @@ TEST(TestUtils, Housekeeping) { } TEST(TestIRLgAcClass, KnownExamples) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); // Ref: // https://github.com/crankyoldgit/IRremoteESP8266/issues/1008#issuecomment-570646648 @@ -694,7 +694,7 @@ TEST(TestIRLgAcClass, KnownExamples) { ASSERT_TRUE(ac.isValidLgAc()); EXPECT_EQ( "Model: 1 (GE6711AR2853M), " - "Power: On, Mode: 1 (Dry), Temp: 21C, Fan: 0 (Low)", + "Power: On, Mode: 1 (Dry), Temp: 21C, Fan: 0 (Quiet)", ac.toString()); ac.setRaw(0x880C758); @@ -716,7 +716,7 @@ TEST(TestIRLgAcClass, KnownExamples) { ASSERT_TRUE(ac.isValidLgAc()); EXPECT_EQ( "Model: 1 (GE6711AR2853M), " - "Power: On, Mode: 0 (Cool), Temp: 22C, Fan: 0 (Low)", + "Power: On, Mode: 0 (Cool), Temp: 22C, Fan: 0 (Quiet)", ac.toString()); ac.setRaw(0x8808721); @@ -816,7 +816,7 @@ TEST(TestDecodeLG2, Issue1008) { EXPECT_EQ(0x8800347, irsend.capture.value); irsend.reset(); - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); ac.setRaw(0x8800347); ac.setModel(lg_ac_remote_model_t::AKB75215403); // aka. 2 ac.send(); @@ -835,7 +835,7 @@ TEST(TestDecodeLG2, Issue1008) { } TEST(TestIRLgAcClass, DifferentModels) { - IRLgAc ac(0); + IRLgAc ac(kGpioUnused); IRrecv capture(0); ac.setRaw(0x8800347); @@ -872,3 +872,12 @@ TEST(TestIRLgAcClass, DifferentModels) { ASSERT_EQ(expected2, IRAcUtils::resultAcToString(&ac._irsend.capture)); ASSERT_TRUE(IRAcUtils::decodeToState(&ac._irsend.capture, &r, &p)); } + +TEST(TestIRLgAcClass, FanSpeedIssue1214) { + EXPECT_EQ(kLgAcFanLowest, IRLgAc::convertFan(stdAc::fanspeed_t::kMin)); + EXPECT_EQ(kLgAcFanLow, IRLgAc::convertFan(stdAc::fanspeed_t::kLow)); + EXPECT_EQ(kLgAcFanMedium, IRLgAc::convertFan(stdAc::fanspeed_t::kMedium)); + EXPECT_EQ(kLgAcFanHigh, IRLgAc::convertFan(stdAc::fanspeed_t::kHigh)); + EXPECT_EQ(kLgAcFanHigh, IRLgAc::convertFan(stdAc::fanspeed_t::kMax)); + EXPECT_EQ(kLgAcFanAuto, IRLgAc::convertFan(stdAc::fanspeed_t::kAuto)); +} diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Midea_test.cpp b/lib/IRremoteESP8266-2.7.8/test/ir_Midea_test.cpp index 24c2610a4..adce3f9d9 100644 --- a/lib/IRremoteESP8266-2.7.8/test/ir_Midea_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/ir_Midea_test.cpp @@ -441,13 +441,13 @@ TEST(TestMideaACClass, Sleep) { } TEST(TestMideaACClass, HumanReadableOutput) { - IRMideaAC ac(0); + IRMideaAC ac(kGpioUnused); ac.begin(); ac.setRaw(0xA1826FFFFF62); EXPECT_EQ( "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " - "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); ac.off(); ac.setTemp(25, true); ac.setFan(kMideaACFanHigh); @@ -455,16 +455,16 @@ TEST(TestMideaACClass, HumanReadableOutput) { ac.setSleep(true); EXPECT_EQ( "Power: Off, Mode: 1 (Dry), Celsius: Off, Temp: 25C/77F, Fan: 3 (High), " - "Sleep: On, Swing(V) Toggle: Off", ac.toString()); + "Sleep: On, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); ac.setUseCelsius(true); EXPECT_EQ( "Power: Off, Mode: 1 (Dry), Celsius: On, Temp: 25C/77F, Fan: 3 (High), " - "Sleep: On, Swing(V) Toggle: Off", ac.toString()); + "Sleep: On, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); ac.setRaw(0xA19867FFFF7E); EXPECT_EQ( "Power: On, Mode: 0 (Cool), Celsius: Off, Temp: 21C/69F, Fan: 3 (High), " - "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); } // Tests for decodeMidea(). @@ -672,14 +672,14 @@ TEST(TestDecodeMidea, DecodeRealExample) { EXPECT_EQ(0xA18263FFFF6E, irsend.capture.value); EXPECT_EQ( "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 18C/65F, Fan: 0 (Auto), " - "Sleep: Off, Swing(V) Toggle: Off", + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); } TEST(TestMideaACClass, toCommon) { - IRMideaAC ac(0); + IRMideaAC ac(kGpioUnused); ac.setPower(true); ac.setMode(kMideaACCool); ac.setUseCelsius(true); @@ -709,7 +709,7 @@ TEST(TestMideaACClass, toCommon) { // https://github.com/crankyoldgit/IRremoteESP8266/issues/819 TEST(TestMideaACClass, CelsiusRemoteTemp) { - IRMideaAC ac(0); + IRMideaAC ac(kGpioUnused); uint64_t on_cool_low_17c = 0xA18840FFFF56; uint64_t on_cool_low_30c = 0xA1884DFFFF5D; ac.on(); @@ -722,13 +722,13 @@ TEST(TestMideaACClass, CelsiusRemoteTemp) { EXPECT_EQ(on_cool_low_17c, ac.getRaw()); EXPECT_EQ( "Power: On, Mode: 0 (Cool), Celsius: On, Temp: 17C/62F, Fan: 1 (Low), " - "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); ac.setRaw(on_cool_low_17c); EXPECT_EQ(17, ac.getTemp(true)); EXPECT_EQ(62, ac.getTemp(false)); EXPECT_EQ( "Power: On, Mode: 0 (Cool), Celsius: On, Temp: 17C/62F, Fan: 1 (Low), " - "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); ac.setTemp(17, true); EXPECT_EQ(17, ac.getTemp(true)); EXPECT_EQ(62, ac.getTemp(false)); @@ -737,26 +737,45 @@ TEST(TestMideaACClass, CelsiusRemoteTemp) { ac.setRaw(on_cool_low_30c); EXPECT_EQ( "Power: On, Mode: 0 (Cool), Celsius: On, Temp: 30C/86F, Fan: 1 (Low), " - "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); } // https://github.com/crankyoldgit/IRremoteESP8266/issues/819 TEST(TestMideaACClass, SwingV) { - IRMideaAC ac(0); + IRMideaAC ac(kGpioUnused); ac.setSwingVToggle(false); ASSERT_FALSE(ac.getSwingVToggle()); ac.setSwingVToggle(true); ASSERT_TRUE(ac.getSwingVToggle()); EXPECT_EQ( "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " - "Sleep: Off, Swing(V) Toggle: On", ac.toString()); + "Sleep: Off, Swing(V) Toggle: On, Econo Toggle: Off", ac.toString()); ac.setSwingVToggle(false); ASSERT_FALSE(ac.getSwingVToggle()); EXPECT_EQ( "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " - "Sleep: Off, Swing(V) Toggle: Off", ac.toString()); + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); ac.setRaw(kMideaACToggleSwingV); - EXPECT_EQ("Swing(V) Toggle: On", ac.toString()); + EXPECT_EQ("Swing(V) Toggle: On, Econo Toggle: Off", ac.toString()); +} + +// https://github.com/crankyoldgit/IRremoteESP8266/pull/1213 +TEST(TestMideaACClass, Econo) { + IRMideaAC ac(kGpioUnused); + ac.setEconoToggle(false); + ASSERT_FALSE(ac.getEconoToggle()); + ac.setEconoToggle(true); + ASSERT_TRUE(ac.getEconoToggle()); + EXPECT_EQ( + "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: On", ac.toString()); + ac.setEconoToggle(false); + ASSERT_FALSE(ac.getEconoToggle()); + EXPECT_EQ( + "Power: On, Mode: 2 (Auto), Celsius: Off, Temp: 25C/77F, Fan: 0 (Auto), " + "Sleep: Off, Swing(V) Toggle: Off, Econo Toggle: Off", ac.toString()); + ac.setRaw(kMideaACToggleEcono); + EXPECT_EQ("Swing(V) Toggle: Off, Econo Toggle: On", ac.toString()); } // Test abusing the protocol for sending 6 arbitary bytes. diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266-2.7.8/test/ir_Pioneer_test.cpp index 37cb56fa2..fce2503e4 100644 --- a/lib/IRremoteESP8266-2.7.8/test/ir_Pioneer_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/ir_Pioneer_test.cpp @@ -14,34 +14,34 @@ TEST(TestSendPioneer, SendDataOnly) { irsend.sendPioneer(0); EXPECT_EQ( "f40000d33" - "m8544s4272" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s37380" - "m8544s4272" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s37380", + "m8506s4191" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s37881" + "m8506s4191" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s37881", irsend.outputStr()); irsend.sendPioneer(0x55FF00AAAA00FF55); EXPECT_EQ( "f40000d33" - "m8544s4272" - "m534s534m534s1602m534s534m534s1602m534s534m534s1602m534s534m534s1602" - "m534s1602m534s1602m534s1602m534s1602m534s1602m534s1602m534s1602m534s1602" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s1602m534s534m534s1602m534s534m534s1602m534s534m534s1602m534s534" - "m534s25098" - "m8544s4272" - "m534s1602m534s534m534s1602m534s534m534s1602m534s534m534s1602m534s534" - "m534s534m534s534m534s534m534s534m534s534m534s534m534s534m534s534" - "m534s1602m534s1602m534s1602m534s1602m534s1602m534s1602m534s1602m534s1602" - "m534s534m534s1602m534s534m534s1602m534s534m534s1602m534s534m534s1602" - "m534s25098", + "m8506s4191" + "m568s487m568s1542m568s487m568s1542m568s487m568s1542m568s487m568s1542" + "m568s1542m568s1542m568s1542m568s1542m568s1542m568s1542m568s1542m568s1542" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s1542m568s487m568s1542m568s487m568s1542m568s487m568s1542m568s487" + "m568s25181" + "m8506s4191" + "m568s1542m568s487m568s1542m568s487m568s1542m568s487m568s1542m568s487" + "m568s487m568s487m568s487m568s487m568s487m568s487m568s487m568s487" + "m568s1542m568s1542m568s1542m568s1542m568s1542m568s1542m568s1542m568s1542" + "m568s487m568s1542m568s487m568s1542m568s487m568s1542m568s487m568s1542" + "m568s25181", irsend.outputStr()); } @@ -139,17 +139,91 @@ TEST(TestDecodePioneer, SyntheticPioneerMessage) { irsend.sendPioneer(0x659A857AF50A3DC2, 64, 0); EXPECT_EQ( "f40000d33" - "m8544s4272" - "m534s534m534s1602m534s1602m534s534m534s534m534s1602m534s534m534s1602" - "m534s1602m534s534m534s534m534s1602m534s1602m534s534m534s1602m534s534" - "m534s1602m534s534m534s534m534s534m534s534m534s1602m534s534m534s1602" - "m534s534m534s1602m534s1602m534s1602m534s1602m534s534m534s1602m534s534" - "m534s25098" - "m8544s4272" - "m534s1602m534s1602m534s1602m534s1602m534s534m534s1602m534s534m534s1602" - "m534s534m534s534m534s534m534s534m534s1602m534s534m534s1602m534s534" - "m534s534m534s534m534s1602m534s1602m534s1602m534s1602m534s534m534s1602" - "m534s1602m534s1602m534s534m534s534m534s534m534s534m534s1602m534s534" - "m534s25098", + "m8506s4191" + "m568s487m568s1542m568s1542m568s487m568s487m568s1542m568s487m568s1542" + "m568s1542m568s487m568s487m568s1542m568s1542m568s487m568s1542m568s487" + "m568s1542m568s487m568s487m568s487m568s487m568s1542m568s487m568s1542" + "m568s487m568s1542m568s1542m568s1542m568s1542m568s487m568s1542m568s487" + "m568s25181" + "m8506s4191" + "m568s1542m568s1542m568s1542m568s1542m568s487m568s1542m568s487m568s1542" + "m568s487m568s487m568s487m568s487m568s1542m568s487m568s1542m568s487" + "m568s487m568s487m568s1542m568s1542m568s1542m568s1542m568s487m568s1542" + "m568s1542m568s1542m568s487m568s487m568s487m568s487m568s1542m568s487" + "m568s25181", irsend.outputStr()); } + +// Ref: https://github.com/crankyoldgit/IRremoteESP8266/issues/1220#issuecomment-661598412 +TEST(TestDecodePioneer, Issue1220) { + IRsendTest irsend(0); + IRrecv irrecv(0); + irsend.begin(); + + irsend.reset(); + // Pwr Toggle {"IrReceived":{"Protocol":"PIONEER","Bits":64, + // "Data":"0xA55A38C7A55A38C7"}} + const uint16_t rawPowerToggle[203] = { + 8510, 4188, 580, 1544, 556, 470, 582, 1566, 556, 494, 560, 488, 556, 1542, + 580, 470, 584, 1540, 582, 492, 552, 1522, 578, 496, 558, 1564, 558, 1542, + 580, 470, 586, 1564, 536, 512, 532, 494, 560, 464, 582, 1542, 580, 1544, + 578, 1544, 578, 498, 558, 492, 562, 488, 556, 1518, 582, 1542, 582, 492, + 552, 498, 556, 494, 550, 1572, 560, 1538, 562, 1536, 586, 25188, + 8512, 4186, 584, 1540, 584, 468, 576, 1572, 528, 522, 532, 492, 552, 1546, + 584, 492, 550, 1548, 582, 494, 560, 1538, 580, 468, 586, 1514, 586, 1538, + 584, 490, 554, 1546, 586, 488, 554, 470, 584, 490, 556, 1542, 556, 1542, + 580, 1544, 578, 496, 560, 466, 578, 496, 560, 1538, 584, 1516, 584, 490, + 554, 472, 582, 492, 552, 1546, 586, 1536, 586, 1538, 586, 25162, + 8514, 4184, 582, 1542, 580, 496, 562, 1536, 584, 490, 554, 496, 560, 1538, + 562, 514, 530, 1542, 580, 496, 560, 1538, 584, 466, 578, 1546, 576, 1524, + 578, 496, 558, 1542, 586, 488, 554, 496, 558, 466, 576, 1546, 576, 1548, + 586, 1512, 578, 498, 558, 492, 552, 496, 558, 1540, 580, 1542, 578, 498, + 556, 494, 550, 498, 556, 1516, 584, 1540, 584, 1540, 580}; + irsend.sendRaw(rawPowerToggle, 203, 40); // Pioneer uses 40kHz + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PIONEER, irsend.capture.decode_type); + EXPECT_EQ(kPioneerBits, irsend.capture.bits); + EXPECT_EQ(0xA55A38C7A55A38C7, irsend.capture.value); + EXPECT_EQ(0xA51C, irsend.capture.address); + EXPECT_EQ(0xA51C, irsend.capture.command); + + irsend.reset(); + irsend.sendPioneer(0xA55A38C7A55A38C7, 64, 1); + irsend.makeDecodeResult(); + EXPECT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(PIONEER, irsend.capture.decode_type); + EXPECT_EQ(kPioneerBits, irsend.capture.bits); + EXPECT_EQ(0xA55A38C7A55A38C7, irsend.capture.value); + EXPECT_EQ(0xA51C, irsend.capture.address); + EXPECT_EQ(0xA51C, irsend.capture.command); + EXPECT_EQ( + "f40000d33" + "m8506s4191" + "m568s1542m568s487m568s1542m568s487m568s487m568s1542m568s487m568s1542" + "m568s487m568s1542m568s487m568s1542m568s1542m568s487m568s1542m568s487" + "m568s487m568s487m568s1542m568s1542m568s1542m568s487m568s487m568s487" + "m568s1542m568s1542m568s487m568s487m568s487m568s1542m568s1542m568s1542" + "m568s25181" + "m8506s4191" + "m568s1542m568s487m568s1542m568s487m568s487m568s1542m568s487m568s1542" + "m568s487m568s1542m568s487m568s1542m568s1542m568s487m568s1542m568s487" + "m568s487m568s487m568s1542m568s1542m568s1542m568s487m568s487m568s487" + "m568s1542m568s1542m568s487m568s487m568s487m568s1542m568s1542m568s1542" + "m568s25181" + "m8506s4191" + "m568s1542m568s487m568s1542m568s487m568s487m568s1542m568s487m568s1542" + "m568s487m568s1542m568s487m568s1542m568s1542m568s487m568s1542m568s487" + "m568s487m568s487m568s1542m568s1542m568s1542m568s487m568s487m568s487" + "m568s1542m568s1542m568s487m568s487m568s487m568s1542m568s1542m568s1542" + "m568s25181" + "m8506s4191" + "m568s1542m568s487m568s1542m568s487m568s487m568s1542m568s487m568s1542" + "m568s487m568s1542m568s487m568s1542m568s1542m568s487m568s1542m568s487" + "m568s487m568s487m568s1542m568s1542m568s1542m568s487m568s487m568s487" + "m568s1542m568s1542m568s487m568s487m568s487m568s1542m568s1542m568s1542" + "m568s25181", + irsend.outputStr()); + + EXPECT_EQ(0xA55A38C7A55A38C7, irsend.encodePioneer(0xA51C, 0xA51C)); +} diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266-2.7.8/test/ir_Samsung_test.cpp index 52165b780..59fc964e3 100644 --- a/lib/IRremoteESP8266-2.7.8/test/ir_Samsung_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/ir_Samsung_test.cpp @@ -12,8 +12,10 @@ // General housekeeping TEST(TestSamsung, Housekeeping) { - ASSERT_EQ("SAMSUNG", typeToString(SAMSUNG)); - ASSERT_FALSE(hasACState(SAMSUNG)); + ASSERT_EQ("SAMSUNG", typeToString(decode_type_t::SAMSUNG)); + ASSERT_EQ(decode_type_t::SAMSUNG, strToDecodeType("SAMSUNG")); + ASSERT_FALSE(hasACState(decode_type_t::SAMSUNG)); + ASSERT_EQ(kSamsungBits, IRsend::defaultBits(decode_type_t::SAMSUNG)); } // Tests for sendSAMSUNG(). @@ -307,8 +309,12 @@ TEST(TestDecodeSamsung, FailToDecodeNonSamsungExample) { // General housekeeping TEST(TestSamsungAC, Housekeeping) { - ASSERT_EQ("SAMSUNG_AC", typeToString(SAMSUNG_AC)); - ASSERT_TRUE(hasACState(SAMSUNG_AC)); + ASSERT_EQ("SAMSUNG_AC", typeToString(decode_type_t::SAMSUNG_AC)); + ASSERT_EQ(decode_type_t::SAMSUNG_AC, strToDecodeType("SAMSUNG_AC")); + ASSERT_TRUE(hasACState(decode_type_t::SAMSUNG_AC)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::SAMSUNG_AC)); + ASSERT_EQ(kSamsungAcBits, IRsend::defaultBits(decode_type_t::SAMSUNG_AC)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::SAMSUNG_AC)); } // Tests for sendSamsungAC(). @@ -1143,34 +1149,36 @@ TEST(TestSendSamsung36, SendDataOnly) { irsend.sendSamsung36(0); EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s4480" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560" - "m560s26880", + "m4515s4438" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s4438" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490" + "m512s26880", irsend.outputStr()); irsend.sendSamsung36(0x400E00FF); EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s1680" - "m560s26880", + "m4515s4438" + "m512s490m512s490m512s490m512s490m512s490m512s1468m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s4438" + "m512s1468m512s1468m512s1468m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s1468m512s1468m512s1468m512s1468" + "m512s1468m512s1468m512s1468m512s1468" + "m512s26880", irsend.outputStr()); irsend.reset(); } // General housekeeping TEST(TestSamsung36, Housekeeping) { - ASSERT_EQ("SAMSUNG36", typeToString(SAMSUNG36)); - ASSERT_FALSE(hasACState(SAMSUNG36)); + ASSERT_EQ("SAMSUNG36", typeToString(decode_type_t::SAMSUNG36)); + ASSERT_EQ(decode_type_t::SAMSUNG36, strToDecodeType("SAMSUNG36")); + ASSERT_FALSE(hasACState(decode_type_t::SAMSUNG36)); + ASSERT_EQ(kSamsung36Bits, IRsend::defaultBits(decode_type_t::SAMSUNG36)); } // Test sending with different repeats. @@ -1182,50 +1190,50 @@ TEST(TestSendSamsung36, SendWithRepeats) { irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 1); // 1 repeat. EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s1680" - "m560s26880" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s1680" - "m560s26880", + "m4515s4438" + "m512s490m512s490m512s490m512s490m512s490m512s1468m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s4438" + "m512s1468m512s1468m512s1468m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s1468m512s1468m512s1468m512s1468" + "m512s1468m512s1468m512s1468m512s1468" + "m512s26880" + "m4515s4438" + "m512s490m512s490m512s490m512s490m512s490m512s1468m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s4438" + "m512s1468m512s1468m512s1468m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s1468m512s1468m512s1468m512s1468" + "m512s1468m512s1468m512s1468m512s1468" + "m512s26880", irsend.outputStr()); irsend.sendSamsung36(0x400E00FF, kSamsung36Bits, 2); // 2 repeats. EXPECT_EQ( "f38000d50" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s1680" - "m560s26880" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s1680" - "m560s26880" - "m4480s4480" - "m560s560m560s560m560s560m560s560m560s560m560s1680m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s560m560s560m560s560m560s560" - "m560s4480" - "m560s1680m560s1680m560s1680m560s560m560s560m560s560m560s560m560s560" - "m560s560m560s560m560s560m560s560m560s1680m560s1680m560s1680m560s1680" - "m560s1680m560s1680m560s1680m560s1680" - "m560s26880", + "m4515s4438" + "m512s490m512s490m512s490m512s490m512s490m512s1468m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s4438" + "m512s1468m512s1468m512s1468m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s1468m512s1468m512s1468m512s1468" + "m512s1468m512s1468m512s1468m512s1468" + "m512s26880" + "m4515s4438" + "m512s490m512s490m512s490m512s490m512s490m512s1468m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s4438" + "m512s1468m512s1468m512s1468m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s1468m512s1468m512s1468m512s1468" + "m512s1468m512s1468m512s1468m512s1468" + "m512s26880" + "m4515s4438" + "m512s490m512s490m512s490m512s490m512s490m512s1468m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s490m512s490m512s490m512s490" + "m512s4438" + "m512s1468m512s1468m512s1468m512s490m512s490m512s490m512s490m512s490" + "m512s490m512s490m512s490m512s490m512s1468m512s1468m512s1468m512s1468" + "m512s1468m512s1468m512s1468m512s1468" + "m512s26880", irsend.outputStr()); } diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266-2.7.8/test/ir_Sanyo_test.cpp index c59113cda..cbdd6ba39 100644 --- a/lib/IRremoteESP8266-2.7.8/test/ir_Sanyo_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/ir_Sanyo_test.cpp @@ -1,5 +1,9 @@ -// Copyright 2017 David Conran +// Copyright 2017-2020 David Conran +#include "ir_Sanyo.h" +#include "IRac.h" +#include "IRrecv.h" +#include "IRrecv_test.h" #include "IRsend.h" #include "IRsend_test.h" #include "gtest/gtest.h" @@ -257,3 +261,272 @@ TEST(TestDecodeSanyoLC7461, FailToDecodeNonSanyoLC7461Example) { irrecv.decodeSanyoLC7461(&irsend.capture, kStartOffset, kSanyoLC7461Bits, false)); } + +TEST(TestUtils, Housekeeping) { + // Sanyo LC7461 + ASSERT_EQ("SANYO_LC7461", typeToString(decode_type_t::SANYO_LC7461)); + ASSERT_EQ(decode_type_t::SANYO_LC7461, strToDecodeType("SANYO_LC7461")); + ASSERT_FALSE(hasACState(decode_type_t::SANYO_LC7461)); + ASSERT_FALSE(IRac::isProtocolSupported(decode_type_t::SANYO_LC7461)); + ASSERT_EQ(kSanyoLC7461Bits, IRsend::defaultBits(decode_type_t::SANYO_LC7461)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::SANYO_LC7461)); + // Sanyo A/C + ASSERT_EQ("SANYO_AC", typeToString(decode_type_t::SANYO_AC)); + ASSERT_EQ(decode_type_t::SANYO_AC, strToDecodeType("SANYO_AC")); + ASSERT_TRUE(hasACState(decode_type_t::SANYO_AC)); + ASSERT_TRUE(IRac::isProtocolSupported(decode_type_t::SANYO_AC)); + ASSERT_EQ(kSanyoAcBits, IRsend::defaultBits(decode_type_t::SANYO_AC)); + ASSERT_EQ(kNoRepeat, IRsend::minRepeats(decode_type_t::SANYO_AC)); +} + +TEST(TestDecodeSanyoAc, DecodeRealExamples) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + // Ref: "On" from https://github.com/crankyoldgit/IRremoteESP8266/issues/1211#issue-650997449 + const uint16_t rawData[148] = { + 8456, 4192, + 624, 448, 584, 1508, 608, 452, 580, 1512, 628, 452, 604, 1468, 560, 1552, + 600, 472, 584, 1532, 580, 472, 528, 516, 512, 540, 576, 1516, 628, 1472, + 612, 1508, 612, 452, 580, 1512, 628, 1468, 612, 1496, 632, 444, 580, 480, + 580, 476, 580, 1496, 564, 508, 576, 480, 576, 480, 580, 476, 584, 472, + 584, 468, 584, 480, 520, 512, 580, 480, 576, 480, 580, 476, 584, 472, + 584, 472, 528, 508, 524, 1568, 600, 480, 576, 480, 584, 1492, 560, 512, + 580, 1536, 576, 480, 580, 476, 580, 476, 528, 528, 524, 1568, 580, 476, + 584, 476, 580, 476, 580, 472, 528, 512, 520, 536, 576, 480, 580, 480, + 576, 480, 576, 476, 532, 528, 520, 512, 576, 480, 584, 476, 580, 476, + 580, 480, 576, 472, 528, 1548, 600, 480, 576, 480, 576, 1520, 592, 1496, + 600, 476, 580, 480, 576}; + const uint8_t expectedState[kSanyoAcStateLength] = { + 0x6A, 0x71, 0x47, 0x00, 0x20, 0x85, 0x00, 0x00, 0x32}; + irsend.begin(); + irsend.reset(); + irsend.sendRaw(rawData, 148, 38000); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SANYO_AC, irsend.capture.decode_type); + EXPECT_EQ(kSanyoAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ( + "Power: On, Mode: 2 (Cool), Temp: 21C, Fan: 0 (Auto), " + "Swing(V): 5 (Upper Middle), Sleep: Off, Beep: On, Sensor: Room, " + "Sensor Temp: 11C, Off Timer: Off", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +TEST(TestDecodeSanyoAc, SyntheticSelfDecode) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + const uint8_t expectedState[kSanyoAcStateLength] = { + 0x6A, 0x71, 0x47, 0x00, 0x20, 0x85, 0x00, 0x00, 0x32}; + irsend.begin(); + irsend.reset(); + irsend.sendSanyoAc(expectedState); + irsend.makeDecodeResult(); + + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(SANYO_AC, irsend.capture.decode_type); + EXPECT_EQ(kSanyoAcBits, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_FALSE(irsend.capture.repeat); + EXPECT_EQ( + "Power: On, Mode: 2 (Cool), Temp: 21C, Fan: 0 (Auto), " + "Swing(V): 5 (Upper Middle), Sleep: Off, Beep: On, Sensor: Room, " + "Sensor Temp: 11C, Off Timer: Off", + IRAcUtils::resultAcToString(&irsend.capture)); + EXPECT_EQ( + "f38000d50" + "m8500s4200" + "m500s550m500s1600m500s550m500s1600m500s550m500s1600m500s1600m500s550" + "m500s1600m500s550m500s550m500s550m500s1600m500s1600m500s1600m500s550" + "m500s1600m500s1600m500s1600m500s550m500s550m500s550m500s1600m500s550" + "m500s550m500s550m500s550m500s550m500s550m500s550m500s550m500s550m500s550" + "m500s550m500s550m500s550m500s550m500s1600m500s550m500s550m500s1600" + "m500s550m500s1600m500s550m500s550m500s550m500s550m500s1600m500s550" + "m500s550m500s550m500s550m500s550m500s550m500s550m500s550m500s550m500s550" + "m500s550m500s550m500s550m500s550m500s550m500s550m500s550m500s1600" + "m500s550m500s550m500s1600m500s1600m500s550m500s550" + "m500s100000", + irsend.outputStr()); +} + +// Tests for IRSanyoAc class. + +TEST(TestSanyoAcClass, Power) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.on(); + EXPECT_TRUE(ac.getPower()); + + ac.off(); + EXPECT_FALSE(ac.getPower()); + + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); + + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); +} + +TEST(TestSanyoAcClass, Temperature) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.setTemp(0); + EXPECT_EQ(kSanyoAcTempMin, ac.getTemp()); + + ac.setTemp(255); + EXPECT_EQ(kSanyoAcTempMax, ac.getTemp()); + + ac.setTemp(kSanyoAcTempMin); + EXPECT_EQ(kSanyoAcTempMin, ac.getTemp()); + + ac.setTemp(kSanyoAcTempMax); + EXPECT_EQ(kSanyoAcTempMax, ac.getTemp()); + + ac.setTemp(kSanyoAcTempMin - 1); + EXPECT_EQ(kSanyoAcTempMin, ac.getTemp()); + + ac.setTemp(kSanyoAcTempMax + 1); + EXPECT_EQ(kSanyoAcTempMax, ac.getTemp()); + + ac.setTemp(17); + EXPECT_EQ(17, ac.getTemp()); + + ac.setTemp(21); + EXPECT_EQ(21, ac.getTemp()); + + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); + + ac.setTemp(30); + EXPECT_EQ(30, ac.getTemp()); +} + +TEST(TestSanyoAcClass, OperatingMode) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.setMode(kSanyoAcAuto); + EXPECT_EQ(kSanyoAcAuto, ac.getMode()); + + ac.setMode(kSanyoAcCool); + EXPECT_EQ(kSanyoAcCool, ac.getMode()); + + ac.setMode(kSanyoAcHeat); + EXPECT_EQ(kSanyoAcHeat, ac.getMode()); + + ac.setMode(kSanyoAcDry); + EXPECT_EQ(kSanyoAcDry, ac.getMode()); + + ac.setMode(kSanyoAcAuto + 1); + EXPECT_EQ(kSanyoAcAuto, ac.getMode()); + + ac.setMode(0); + EXPECT_EQ(kSanyoAcAuto, ac.getMode()); + + ac.setMode(255); + EXPECT_EQ(kSanyoAcAuto, ac.getMode()); +} + +TEST(TestSanyoAcClass, FanSpeed) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.setFan(kSanyoAcFanAuto); + EXPECT_EQ(kSanyoAcFanAuto, ac.getFan()); + + ac.setFan(kSanyoAcFanHigh); + EXPECT_EQ(kSanyoAcFanHigh, ac.getFan()); + + ac.setFan(kSanyoAcFanLow); + EXPECT_EQ(kSanyoAcFanLow, ac.getFan()); + + ac.setFan(kSanyoAcFanMedium); + EXPECT_EQ(kSanyoAcFanMedium, ac.getFan()); +} + +TEST(TestSanyoAcClass, Sleep) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); + ac.setSleep(false); + EXPECT_FALSE(ac.getSleep()); + ac.setSleep(true); + EXPECT_TRUE(ac.getSleep()); +} + +TEST(TestSanyoAcClass, SwingV) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.setSwingV(kSanyoAcSwingVAuto); + EXPECT_EQ(kSanyoAcSwingVAuto, ac.getSwingV()); + + ac.setSwingV(kSanyoAcSwingVHigh); + EXPECT_EQ(kSanyoAcSwingVHigh, ac.getSwingV()); + + ac.setSwingV(kSanyoAcSwingVLow); + EXPECT_EQ(kSanyoAcSwingVLow, ac.getSwingV()); + + ac.setSwingV(kSanyoAcSwingVUpperMiddle); + EXPECT_EQ(kSanyoAcSwingVUpperMiddle, ac.getSwingV()); + + ac.setSwingV(0); + EXPECT_EQ(kSanyoAcSwingVAuto, ac.getSwingV()); + ac.setSwingV(255); + EXPECT_EQ(kSanyoAcSwingVAuto, ac.getSwingV()); +} + +TEST(TestSanyoAcClass, Timers) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.setOffTimer(0); + EXPECT_EQ(0, ac.getOffTimer()); + ac.setOffTimer(59); + EXPECT_EQ(0, ac.getOffTimer()); + ac.setOffTimer(60); + EXPECT_EQ(60, ac.getOffTimer()); + ac.setOffTimer(61); + EXPECT_EQ(60, ac.getOffTimer()); + ac.setOffTimer(15 * 60 + 59); + EXPECT_EQ(15 * 60, ac.getOffTimer()); + ac.setOffTimer(16 * 60); + EXPECT_EQ(15 * 60, ac.getOffTimer()); + + const uint8_t offTimer2Hr[kSanyoAcStateLength] = { + 0x6A, 0x6D, 0x4F, 0x02, 0x14, 0x85, 0x00, 0x00, 0x4A}; + ac.setRaw(offTimer2Hr); + EXPECT_EQ(2 * 60, ac.getOffTimer()); + EXPECT_EQ( + "Power: On, Mode: 1 (Heat), Temp: 17C, Fan: 0 (Auto), " + "Swing(V): 5 (Upper Middle), Sleep: Off, Beep: On, " + "Sensor: Room, Sensor Temp: 19C, Off Timer: 02:00", + ac.toString()); +} + +TEST(TestSanyoAcClass, Beep) { + IRSanyoAc ac(kGpioUnused); + ac.begin(); + + ac.setBeep(true); + EXPECT_TRUE(ac.getBeep()); + ac.setBeep(false); + EXPECT_FALSE(ac.getBeep()); + ac.setBeep(true); + EXPECT_TRUE(ac.getBeep()); + + const uint8_t beep_off[kSanyoAcStateLength] = { + 0x6A, 0x6D, 0x11, 0x00, 0x10, 0x85, 0x00, 0x00, 0x33}; + ac.setRaw(beep_off); + EXPECT_FALSE(ac.getBeep()); + const uint8_t beep_on[kSanyoAcStateLength] = { + 0x6A, 0x6E, 0x54, 0x00, 0x10, 0x83, 0x00, 0x00, 0x39}; + ac.setRaw(beep_on); + EXPECT_TRUE(ac.getBeep()); +} diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266-2.7.8/test/ir_Toshiba_test.cpp index e0ae82987..fcd0e510e 100644 --- a/lib/IRremoteESP8266-2.7.8/test/ir_Toshiba_test.cpp +++ b/lib/IRremoteESP8266-2.7.8/test/ir_Toshiba_test.cpp @@ -11,7 +11,7 @@ // Test sending typical data only. TEST(TestSendToshibaAC, SendDataOnly) { - IRsendTest irsend(4); + IRsendTest irsend(kGpioUnused); irsend.begin(); uint8_t toshiba_code[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, @@ -21,33 +21,33 @@ TEST(TestSendToshibaAC, SendDataOnly) { EXPECT_EQ( "f38000d50" "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s7400" "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048", + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s7400", irsend.outputStr()); } // Test sending with repeats. TEST(TestSendToshibaAC, SendWithRepeats) { - IRsendTest irsend(4); + IRsendTest irsend(kGpioUnused); irsend.begin(); irsend.reset(); @@ -58,16 +58,16 @@ TEST(TestSendToshibaAC, SendWithRepeats) { EXPECT_EQ( "f38000d50" "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048", + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s7400", irsend.outputStr()); irsend.reset(); @@ -75,242 +75,200 @@ TEST(TestSendToshibaAC, SendWithRepeats) { EXPECT_EQ( "f38000d50" "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s7400" "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s7400" "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s7048", - irsend.outputStr()); -} - -// Test sending atypical sizes. -TEST(TestSendToshibaAC, SendUnexpectedSizes) { - IRsendTest irsend(4); - irsend.begin(); - - uint8_t toshiba_short_code[8] = {0x01, 0x02, 0x03, 0x04, - 0x05, 0x06, 0x07, 0x08}; - uint8_t toshiba_long_code[10] = {0x01, 0x02, 0x03, 0x04, 0x05, - 0x06, 0x07, 0x08, 0x09, 0x0A}; - irsend.reset(); - irsend.sendToshibaAC(toshiba_short_code, kToshibaACStateLength - 1); - ASSERT_EQ("", irsend.outputStr()); - - irsend.reset(); - irsend.sendToshibaAC(toshiba_long_code, kToshibaACStateLength + 1); - ASSERT_EQ( - "f38000d50" - "m4400s4300" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623m543s1623" - "m543s472m543s472m543s472m543s472m543s1623m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s1623m543s472m543s1623m543s472" - "m543s7048" - "m4400s4300" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623m543s1623" - "m543s472m543s472m543s472m543s472m543s1623m543s472m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s1623m543s472m543s1623m543s472" - "m543s7048", + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s1600m580s1600" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s7400", irsend.outputStr()); } // Tests for IRToshibaAC class. TEST(TestToshibaACClass, Power) { - IRToshibaAC toshiba(0); - toshiba.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); - toshiba.on(); - EXPECT_TRUE(toshiba.getPower()); + ac.on(); + EXPECT_TRUE(ac.getPower()); - toshiba.off(); - EXPECT_FALSE(toshiba.getPower()); + ac.off(); + EXPECT_FALSE(ac.getPower()); - toshiba.setPower(true); - EXPECT_TRUE(toshiba.getPower()); + ac.setPower(true); + EXPECT_TRUE(ac.getPower()); - toshiba.setPower(false); - EXPECT_FALSE(toshiba.getPower()); + ac.setPower(false); + EXPECT_FALSE(ac.getPower()); } TEST(TestToshibaACClass, Temperature) { - IRToshibaAC toshiba(0); - toshiba.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); - toshiba.setTemp(0); - EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); + ac.setTemp(0); + EXPECT_EQ(kToshibaAcMinTemp, ac.getTemp()); - toshiba.setTemp(255); - EXPECT_EQ(kToshibaAcMaxTemp, toshiba.getTemp()); + ac.setTemp(255); + EXPECT_EQ(kToshibaAcMaxTemp, ac.getTemp()); - toshiba.setTemp(kToshibaAcMinTemp); - EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); + ac.setTemp(kToshibaAcMinTemp); + EXPECT_EQ(kToshibaAcMinTemp, ac.getTemp()); - toshiba.setTemp(kToshibaAcMaxTemp); - EXPECT_EQ(kToshibaAcMaxTemp, toshiba.getTemp()); + ac.setTemp(kToshibaAcMaxTemp); + EXPECT_EQ(kToshibaAcMaxTemp, ac.getTemp()); - toshiba.setTemp(kToshibaAcMinTemp - 1); - EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); + ac.setTemp(kToshibaAcMinTemp - 1); + EXPECT_EQ(kToshibaAcMinTemp, ac.getTemp()); - toshiba.setTemp(kToshibaAcMaxTemp + 1); - EXPECT_EQ(kToshibaAcMaxTemp, toshiba.getTemp()); + ac.setTemp(kToshibaAcMaxTemp + 1); + EXPECT_EQ(kToshibaAcMaxTemp, ac.getTemp()); - toshiba.setTemp(17); - EXPECT_EQ(17, toshiba.getTemp()); + ac.setTemp(17); + EXPECT_EQ(17, ac.getTemp()); - toshiba.setTemp(21); - EXPECT_EQ(21, toshiba.getTemp()); + ac.setTemp(21); + EXPECT_EQ(21, ac.getTemp()); - toshiba.setTemp(25); - EXPECT_EQ(25, toshiba.getTemp()); + ac.setTemp(25); + EXPECT_EQ(25, ac.getTemp()); - toshiba.setTemp(30); - EXPECT_EQ(30, toshiba.getTemp()); + ac.setTemp(30); + EXPECT_EQ(30, ac.getTemp()); } TEST(TestToshibaACClass, OperatingMode) { - IRToshibaAC toshiba(0); - toshiba.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); - toshiba.setMode(kToshibaAcAuto); - EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); + ac.setMode(kToshibaAcAuto); + EXPECT_EQ(kToshibaAcAuto, ac.getMode()); - toshiba.setMode(kToshibaAcCool); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); + ac.setMode(kToshibaAcCool); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); - toshiba.setMode(kToshibaAcHeat); - EXPECT_EQ(kToshibaAcHeat, toshiba.getMode()); + ac.setMode(kToshibaAcHeat); + EXPECT_EQ(kToshibaAcHeat, ac.getMode()); - toshiba.setMode(kToshibaAcDry); - EXPECT_EQ(kToshibaAcDry, toshiba.getMode()); + ac.setMode(kToshibaAcDry); + EXPECT_EQ(kToshibaAcDry, ac.getMode()); - toshiba.setMode(kToshibaAcHeat + 1); - EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); + ac.setMode(kToshibaAcFan); + EXPECT_EQ(kToshibaAcFan, ac.getMode()); - toshiba.setMode(255); - EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); + ac.setMode(kToshibaAcFan + 1); + EXPECT_EQ(kToshibaAcAuto, ac.getMode()); - // Setting the power off changes the underlying mode in the state to heat. - toshiba.setPower(true); - toshiba.setMode(kToshibaAcCool); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode(true)); - toshiba.setPower(false); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); - EXPECT_EQ(kToshibaAcHeat, toshiba.getMode(true)); + ac.setMode(255); + EXPECT_EQ(kToshibaAcAuto, ac.getMode()); + + // Setting the power off changes the underlying mode in the state to a special + // off mode. + ac.setPower(true); + ac.setMode(kToshibaAcCool); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); + ac.setPower(false); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); } TEST(TestToshibaACClass, FanSpeed) { - IRToshibaAC toshiba(0); - toshiba.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); - toshiba.setFan(kToshibaAcFanAuto); - EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); + ac.setFan(kToshibaAcFanAuto); + EXPECT_EQ(kToshibaAcFanAuto, ac.getFan()); - toshiba.setFan(255); - EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); + ac.setFan(255); + EXPECT_EQ(kToshibaAcFanMax, ac.getFan()); - toshiba.setFan(kToshibaAcFanMax); - EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); + ac.setFan(kToshibaAcFanMax); + EXPECT_EQ(kToshibaAcFanMax, ac.getFan()); - toshiba.setFan(kToshibaAcFanMax - 1); - EXPECT_EQ(kToshibaAcFanMax - 1, toshiba.getFan()); + ac.setFan(kToshibaAcFanMax - 1); + EXPECT_EQ(kToshibaAcFanMax - 1, ac.getFan()); - toshiba.setFan(1); - EXPECT_EQ(1, toshiba.getFan()); + ac.setFan(1); + EXPECT_EQ(1, ac.getFan()); - toshiba.setFan(2); - EXPECT_EQ(2, toshiba.getFan()); + ac.setFan(2); + EXPECT_EQ(2, ac.getFan()); - toshiba.setFan(3); - EXPECT_EQ(3, toshiba.getFan()); + ac.setFan(3); + EXPECT_EQ(3, ac.getFan()); - toshiba.setFan(4); - EXPECT_EQ(4, toshiba.getFan()); + ac.setFan(4); + EXPECT_EQ(4, ac.getFan()); - toshiba.setFan(kToshibaAcFanMax + 1); - EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); + ac.setFan(kToshibaAcFanMax + 1); + EXPECT_EQ(kToshibaAcFanMax, ac.getFan()); } TEST(TestToshibaACClass, RawState) { - IRToshibaAC toshiba(0); - toshiba.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); uint8_t initial_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, - 0x00, 0x00, 0x00, 0x01}; + 0x50, 0x00, 0x00, 0x51}; uint8_t modified_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0xC1, 0x00, 0xC0}; // Verify the starting state. - EXPECT_STATE_EQ(initial_state, toshiba.getRaw(), kToshibaACBits); - EXPECT_TRUE(toshiba.getPower()); - EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); - EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); + EXPECT_STATE_EQ(initial_state, ac.getRaw(), kToshibaACBits); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(kToshibaAcAuto, ac.getMode()); + EXPECT_EQ(kToshibaAcFanAuto, ac.getFan()); // Change some settings. - toshiba.setMode(kToshibaAcCool); - toshiba.setFan(kToshibaAcFanMax); - toshiba.setTemp(kToshibaAcMinTemp); + ac.setMode(kToshibaAcCool); + ac.setFan(kToshibaAcFanMax); + ac.setTemp(kToshibaAcMinTemp); // Verify those were set. - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); - EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); - EXPECT_EQ(kToshibaAcMinTemp, toshiba.getTemp()); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); + EXPECT_EQ(kToshibaAcFanMax, ac.getFan()); + EXPECT_EQ(kToshibaAcMinTemp, ac.getTemp()); // Retrieve the modified state. - EXPECT_STATE_EQ(modified_state, toshiba.getRaw(), kToshibaACBits); + EXPECT_STATE_EQ(modified_state, ac.getRaw(), kToshibaACBits); // Set it back to the initial state. - toshiba.setRaw(initial_state); + ac.setRaw(initial_state); // Check the new state was set correctly. - EXPECT_TRUE(toshiba.getPower()); - EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); - EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); - EXPECT_STATE_EQ(initial_state, toshiba.getRaw(), kToshibaACBits); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(kToshibaAcAuto, ac.getMode()); + EXPECT_EQ(kToshibaAcFanAuto, ac.getFan()); + EXPECT_STATE_EQ(initial_state, ac.getRaw(), kToshibaACBits); } TEST(TestToshibaACClass, Checksums) { - IRToshibaAC toshiba(0); - toshiba.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); uint8_t initial_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; @@ -319,8 +277,8 @@ TEST(TestToshibaACClass, Checksums) { uint8_t invalid_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x00}; - EXPECT_EQ(0x01, toshiba.calcChecksum(initial_state)); - EXPECT_EQ(0xC0, toshiba.calcChecksum(modified_state)); + EXPECT_EQ(0x01, ac.calcChecksum(initial_state)); + EXPECT_EQ(0xC0, ac.calcChecksum(modified_state)); // Check we can call it without instantiating the object. EXPECT_EQ(0x01, IRToshibaAC::calcChecksum(initial_state)); // Use different lengths. @@ -344,150 +302,69 @@ TEST(TestToshibaACClass, Checksums) { } TEST(TestToshibaACClass, HumanReadableOutput) { - IRToshibaAC toshiba(0); - toshiba.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); uint8_t initial_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0x00, 0x00, 0x01}; uint8_t modified_state[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, 0x00, 0xC1, 0x00, 0xC0}; - toshiba.setRaw(initial_state); - EXPECT_EQ("Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto)", - toshiba.toString()); - toshiba.setRaw(modified_state); - EXPECT_EQ("Power: On, Mode: 1 (Cool), Temp: 17C, Fan: 5 (High)", - toshiba.toString()); - toshiba.off(); - toshiba.setTemp(25); - toshiba.setFan(3); - toshiba.setMode(kToshibaAcDry); - EXPECT_EQ("Power: Off, Mode: 2 (Dry), Temp: 25C, Fan: 3 (Medium)", - toshiba.toString()); + ac.setRaw(initial_state); + EXPECT_EQ("Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), " + "Turbo: Off, Econo: Off", + ac.toString()); + ac.setRaw(modified_state); + EXPECT_EQ("Temp: 17C, Power: On, Mode: 1 (Cool), Fan: 5 (High), " + "Turbo: Off, Econo: Off", + ac.toString()); + ac.setTemp(25); + ac.setFan(3); + ac.setMode(kToshibaAcDry); + EXPECT_EQ("Temp: 25C, Power: On, Mode: 2 (Dry), Fan: 3 (Medium), " + "Turbo: Off, Econo: Off", + ac.toString()); + ac.off(); + EXPECT_EQ("Temp: 25C, Power: Off, Fan: 3 (Medium), Turbo: Off, Econo: Off", + ac.toString()); } TEST(TestToshibaACClass, MessageConstuction) { - IRToshibaAC toshiba(0); - IRsendTest irsend(4); - toshiba.begin(); - irsend.begin(); + IRToshibaAC ac(kGpioUnused); + ac.begin(); - toshiba.setFan(1); - toshiba.setMode(kToshibaAcCool); - toshiba.setTemp(27); - toshiba.on(); + ac.on(); + ac.setFan(1); + ac.setMode(kToshibaAcCool); + ac.setTemp(27); // Check everything for kicks. - EXPECT_EQ(1, toshiba.getFan()); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); - EXPECT_EQ(27, toshiba.getTemp()); - EXPECT_TRUE(toshiba.getPower()); - - irsend.reset(); - irsend.sendToshibaAC(toshiba.getRaw()); - EXPECT_EQ( - "f38000d50" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s1623m543s472m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s1623m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s1623m543s1623m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s7048" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s1623m543s472m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s1623m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s1623m543s1623m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s7048", - irsend.outputStr()); + EXPECT_EQ(1, ac.getFan()); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); + EXPECT_EQ(27, ac.getTemp()); + EXPECT_TRUE(ac.getPower()); // Turn off the power and re-check. - toshiba.setPower(false); + ac.setPower(false); // Check everything for kicks. - EXPECT_EQ(1, toshiba.getFan()); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); - EXPECT_EQ(27, toshiba.getTemp()); - EXPECT_FALSE(toshiba.getPower()); - - irsend.reset(); - irsend.sendToshibaAC(toshiba.getRaw()); - EXPECT_EQ( - "f38000d50" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s1623m543s472m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s1623m543s472m543s472m543s472m543s1623m543s1623m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s1623m543s472" - "m543s7048" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s1623m543s472m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s1623m543s472m543s472m543s472m543s1623m543s1623m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s1623m543s472" - "m543s7048", - irsend.outputStr()); + EXPECT_EQ(1, ac.getFan()); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); + EXPECT_EQ(27, ac.getTemp()); + EXPECT_FALSE(ac.getPower()); // Turn the power back on, and check nothing changed. - toshiba.on(); + ac.on(); - EXPECT_EQ(1, toshiba.getFan()); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); - EXPECT_EQ(27, toshiba.getTemp()); - EXPECT_TRUE(toshiba.getPower()); - - irsend.reset(); - irsend.sendToshibaAC(toshiba.getRaw()); - EXPECT_EQ( - "f38000d50" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s1623m543s472m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s1623m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s1623m543s1623m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s7048" - "m4400s4300" - "m543s1623m543s1623m543s1623m543s1623m543s472m543s472m543s1623m543s472" - "m543s472m543s472m543s472m543s472m543s1623m543s1623m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s1623m543s1623" - "m543s1623m543s1623m543s1623m543s1623m543s1623m543s1623m543s472m543s472" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s1623m543s472m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s472m543s1623m543s472m543s472m543s472m543s472m543s472m543s1623" - "m543s472m543s472m543s472m543s472m543s472m543s472m543s472m543s472" - "m543s1623m543s1623m543s1623m543s472m543s472m543s472m543s472m543s472" - "m543s7048", - irsend.outputStr()); + EXPECT_EQ(1, ac.getFan()); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); + EXPECT_EQ(27, ac.getTemp()); + EXPECT_TRUE(ac.getPower()); } // Decoding a message we entirely constructed based solely on a given state. TEST(TestDecodeToshibaAC, SyntheticExample) { - IRsendTest irsend(4); - IRrecv irrecv(4); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); uint8_t expectedState[kToshibaACStateLength] = {0xF2, 0x0D, 0x03, 0xFC, 0x01, @@ -501,7 +378,8 @@ TEST(TestDecodeToshibaAC, SyntheticExample) { ASSERT_EQ(kToshibaACBits, irsend.capture.bits); EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); EXPECT_EQ( - "Power: On, Mode: 0 (Auto), Temp: 17C, Fan: 0 (Auto)", + "Temp: 17C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: Off, " + "Econo: Off", IRAcUtils::resultAcToString(&irsend.capture)); stdAc::state_t r, p; ASSERT_TRUE(IRAcUtils::decodeToState(&irsend.capture, &r, &p)); @@ -510,9 +388,9 @@ TEST(TestDecodeToshibaAC, SyntheticExample) { // Test decoding against captures from a real Toshiba A/C remote. // Recorded by @mwildbolz TEST(TestDecodeToshibaAC, RealExamples) { - IRToshibaAC toshiba(0); - IRsendTest irsend(4); - IRrecv irrecv(4); + IRToshibaAC ac(kGpioUnused); + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); irsend.begin(); uint16_t rawData1[295] = { @@ -548,11 +426,11 @@ TEST(TestDecodeToshibaAC, RealExamples) { EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); ASSERT_EQ(kToshibaACBits, irsend.capture.bits); - toshiba.setRaw(irsend.capture.state); - EXPECT_TRUE(toshiba.getPower()); - EXPECT_EQ(23, toshiba.getTemp()); - EXPECT_EQ(kToshibaAcFanAuto, toshiba.getFan()); - EXPECT_EQ(kToshibaAcAuto, toshiba.getMode()); + ac.setRaw(irsend.capture.state); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(23, ac.getTemp()); + EXPECT_EQ(kToshibaAcFanAuto, ac.getFan()); + EXPECT_EQ(kToshibaAcAuto, ac.getMode()); uint16_t rawData2[295] = { 4500, 4236, 636, 1520, 642, 1520, 640, 1520, 664, 1492, 642, 440, @@ -587,11 +465,11 @@ TEST(TestDecodeToshibaAC, RealExamples) { EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); ASSERT_EQ(kToshibaACBits, irsend.capture.bits); - toshiba.setRaw(irsend.capture.state); - EXPECT_TRUE(toshiba.getPower()); - EXPECT_EQ(17, toshiba.getTemp()); - EXPECT_EQ(3, toshiba.getFan()); - EXPECT_EQ(kToshibaAcCool, toshiba.getMode()); + ac.setRaw(irsend.capture.state); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(17, ac.getTemp()); + EXPECT_EQ(3, ac.getFan()); + EXPECT_EQ(kToshibaAcCool, ac.getMode()); uint16_t rawData3[295] = { 4474, 4262, 642, 1514, 642, 1520, 642, 1520, 642, 1514, 642, 438, @@ -626,11 +504,11 @@ TEST(TestDecodeToshibaAC, RealExamples) { EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); ASSERT_EQ(kToshibaACBits, irsend.capture.bits); - toshiba.setRaw(irsend.capture.state); - EXPECT_TRUE(toshiba.getPower()); - EXPECT_EQ(24, toshiba.getTemp()); - EXPECT_EQ(kToshibaAcFanMax, toshiba.getFan()); - EXPECT_EQ(kToshibaAcHeat, toshiba.getMode()); + ac.setRaw(irsend.capture.state); + EXPECT_TRUE(ac.getPower()); + EXPECT_EQ(24, ac.getTemp()); + EXPECT_EQ(kToshibaAcFanMax, ac.getFan()); + EXPECT_EQ(kToshibaAcHeat, ac.getMode()); uint16_t rawData4[295] = { 4474, 4262, 636, 1520, 640, 1520, 640, 1520, 638, 1518, 642, 438, @@ -665,16 +543,10 @@ TEST(TestDecodeToshibaAC, RealExamples) { EXPECT_TRUE(irrecv.decode(&irsend.capture)); ASSERT_EQ(TOSHIBA_AC, irsend.capture.decode_type); ASSERT_EQ(kToshibaACBits, irsend.capture.bits); - toshiba.setRaw(irsend.capture.state); - EXPECT_FALSE(toshiba.getPower()); - EXPECT_EQ(22, toshiba.getTemp()); - EXPECT_EQ(4, toshiba.getFan()); - - // Confirming the quirky behaviour that the 'Power OFF' signal - // sets the mode to heat. - // The previous state the remote was in was 'AUTO' just prior to - // sending the power off message. - EXPECT_EQ(kToshibaAcHeat, toshiba.getMode()); + ac.setRaw(irsend.capture.state); + EXPECT_FALSE(ac.getPower()); + EXPECT_EQ(22, ac.getTemp()); + EXPECT_EQ(4, ac.getFan()); } TEST(TestToshibaACClass, toCommon) { @@ -704,3 +576,166 @@ TEST(TestToshibaACClass, toCommon) { ASSERT_EQ(-1, ac.toCommon().sleep); ASSERT_EQ(-1, ac.toCommon().clock); } + +// Tests for CarrierAc2 +/// Decode a "real" long example message. +TEST(TestDecodeToshibaAC, RealLongExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Data from: + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1205#issuecomment-650475434 + const uint16_t high_power_on[327] = { + 4424, 4320, + 582, 1574, 588, 1578, 582, 1574, 586, 1578, 586, 496, 582, 492, 586, 1576, + 586, 492, 586, 492, 588, 496, 584, 496, 584, 496, 584, 1626, 534, 1626, + 534, 494, 586, 1578, 582, 494, 586, 494, 586, 494, 588, 492, 586, 492, + 586, 1576, 586, 494, 588, 492, 588, 1574, 588, 1576, 584, 1578, 584, 1574, + 588, 1574, 588, 492, 588, 1572, 590, 1570, 590, 492, 588, 492, 590, 488, + 590, 494, 584, 1570, 592, 492, 586, 490, 590, 1572, 590, 490, 590, 1570, + 590, 490, 590, 1570, 590, 492, 588, 490, 588, 492, 588, 492, 590, 490, + 590, 494, 586, 490, 590, 490, 588, 490, 590, 490, 588, 492, 590, 490, + 588, 492, 590, 490, 590, 490, 590, 494, 584, 490, 590, 490, 590, 490, + 590, 490, 588, 490, 588, 492, 588, 492, 586, 492, 588, 490, 588, 492, + 588, 490, 590, 1572, 588, 494, 586, 1574, 588, 492, 588, 1572, 590, 1572, + 588, 492, 588, 492, 586, 494, 588, + 7422, + 4424, 4320, + 586, 1572, 588, 1572, 588, 1576, 584, 1574, 588, 494, 586, 492, 588, 1572, + 588, 492, 588, 492, 588, 492, 588, 494, 586, 496, 584, 1574, 586, 1578, + 582, 494, 586, 1578, 584, 494, 586, 492, 588, 492, 586, 496, 584, 494, + 586, 1578, 584, 494, 586, 494, 584, 1574, 588, 1572, 586, 1574, 588, 1574, + 588, 1572, 588, 494, 590, 1572, 588, 1574, 588, 492, 588, 492, 588, 492, + 586, 492, 588, 1572, 588, 498, 582, 492, 588, 1576, 586, 492, 588, 1572, + 588, 494, 588, 1572, 588, 492, 586, 492, 588, 492, 590, 490, 588, 492, + 586, 492, 588, 492, 590, 490, 588, 490, 588, 492, 590, 490, 588, 492, + 590, 490, 588, 490, 590, 490, 590, 490, 592, 488, 592, 494, 584, 494, + 586, 490, 590, 494, 586, 494, 588, 488, 592, 490, 588, 492, 586, 490, + 592, 490, 588, 1576, 584, 494, 586, 1570, 590, 494, 586, 1576, 582, 1572, + 590, 490, 590, 490, 588, 490, 590}; // UNKNOWN 54926187 + + const uint8_t expectedState[kToshibaACStateLengthLong] = { + 0xF2, 0x0D, 0x04, 0xFB, 0x09, 0x50, 0x00, 0x00, 0x01, 0x58}; + irsend.sendRaw(high_power_on, 327, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::TOSHIBA_AC, irsend.capture.decode_type); + EXPECT_EQ(kToshibaACBitsLong, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Temp: 22C, Power: On, Mode: 0 (Auto), Fan: 0 (Auto), Turbo: On, " + "Econo: Off", + IRAcUtils::resultAcToString(&irsend.capture)); +} + + +/// Decode a synthetic long message. +TEST(TestDecodeToshibaAC, SyntheticLongExample) { + IRsendTest irsend(0); + IRrecv irrecv(0); + + const uint8_t expectedState[kToshibaACStateLengthLong] = { + 0xF2, 0x0D, 0x04, 0xFB, 0x09, 0x50, 0x00, 0x00, 0x01, 0x58}; + irsend.begin(); + irsend.reset(); + irsend.sendToshibaAC(expectedState, kToshibaACStateLengthLong); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::TOSHIBA_AC, irsend.capture.decode_type); + EXPECT_EQ(kToshibaACBitsLong, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "f38000d50" + // 4424 4320 + "m4400s4300" + // 582 1574 588 1578 582 1574 586 1578 586 496 582 492 586 1576 586 492 + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + // 586 492 588 496 584 496 584 496 584 1626 534 1626 534 494 586 1578 + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + // 582 494 586 494 586 494 588 492 586 492 586 1576 586 494 588 492 + "m580s490m580s490m580s490m580s490m580s490m580s1600m580s490m580s490" + // 588 1574 588 1576 584 1578 584 1574 588 1574 588 492 588 1572 590 1570 + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s1600m580s1600" + // 590 492 588 492 590 488 590 494 584 1570 592 492 586 490 590 1572 + "m580s490m580s490m580s490m580s490m580s1600m580s490m580s490m580s1600" + // 590 490 590 1570 590 490 590 1570 590 492 588 490 588 492 588 492 + "m580s490m580s1600m580s490m580s1600m580s490m580s490m580s490m580s490" + // 590 490 590 494 586 490 590 490 588 490 590 490 588 492 590 490 + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + // 588 492 590 490 590 490 590 494 584 490 590 490 590 490 590 490 + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + // 588 490 588 492 588 492 586 492 588 490 588 492 588 490 590 1572 + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + // 588 494 586 1574 588 492 588 1572 590 1572 588 492 588 492 586 494 + "m580s490m580s1600m580s490m580s1600m580s1600m580s490m580s490m580s490" + // 588 7422 + "m580s7400" + "m4400s4300" + "m580s1600m580s1600m580s1600m580s1600m580s490m580s490m580s1600m580s490" + "m580s490m580s490m580s490m580s490m580s1600m580s1600m580s490m580s1600" + "m580s490m580s490m580s490m580s490m580s490m580s1600m580s490m580s490" + "m580s1600m580s1600m580s1600m580s1600m580s1600m580s490m580s1600m580s1600" + "m580s490m580s490m580s490m580s490m580s1600m580s490m580s490m580s1600" + "m580s490m580s1600m580s490m580s1600m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s490" + "m580s490m580s490m580s490m580s490m580s490m580s490m580s490m580s1600" + "m580s490m580s1600m580s490m580s1600m580s1600m580s490m580s490m580s490" + "m580s7400", + irsend.outputStr()); +} + +/// Decode a "real" short example message. +TEST(TestDecodeToshibaAC, RealShortExample) { + IRsendTest irsend(kGpioUnused); + IRrecv irrecv(kGpioUnused); + irsend.begin(); + + irsend.reset(); + // Data from: + // https://github.com/crankyoldgit/IRremoteESP8266/issues/1205#issuecomment-650475096 + const uint16_t air_direction[115] = { + 4424, 4318, + 588, 1574, 588, 1572, 588, 1574, 586, 1572, 590, 490, 586, 494, 586, 1574, + 588, 492, 586, 494, 586, 494, 586, 496, 584, 492, 588, 1572, 588, 1572, + 590, 492, 588, 1572, 590, 490, 588, 492, 586, 494, 588, 492, 588, 492, + 588, 494, 584, 492, 588, 1572, 588, 1574, 588, 1574, 588, 1572, 588, 1572, + 588, 1572, 588, 1574, 590, 1570, 588, 494, 586, 496, 584, 494, 588, 1572, + 588, 492, 588, 492, 588, 490, 588, 492, 590, 1572, 588, 492, 588, 496, + 586, 492, 588, 492, 586, 492, 588, 492, 588, 490, 590, 490, 588, 492, + 588, 490, 588, 1572, 588, 492, 588, 492, 588, 490, 588, 492, 588, 1572, + 586}; // UNKNOWN DEB8845C + const uint8_t expectedState[kToshibaACStateLengthShort] = { + 0xF2, 0x0D, 0x01, 0xFE, 0x21, 0x00, 0x21}; + irsend.sendRaw(air_direction, 115, 38000); + irsend.makeDecodeResult(); + ASSERT_TRUE(irrecv.decode(&irsend.capture)); + EXPECT_EQ(decode_type_t::TOSHIBA_AC, irsend.capture.decode_type); + EXPECT_EQ(kToshibaACBitsShort, irsend.capture.bits); + EXPECT_STATE_EQ(expectedState, irsend.capture.state, irsend.capture.bits); + EXPECT_EQ( + "Temp: 17C, Swing(V): 0 (Step)", + IRAcUtils::resultAcToString(&irsend.capture)); +} + +TEST(TestToshibaACClass, ConstructLongState) { + IRToshibaAC ac(kGpioUnused); + ac.setPower(true); + ac.setMode(kToshibaAcDry); + ac.setTemp(29); + ac.setFan(2); + ac.setSwing(false); + ac.setTurbo(false); + ac.setEcono(true); + EXPECT_EQ( + "Temp: 29C, Power: On, Mode: 2 (Dry), Fan: 2 (UNKNOWN), " + "Turbo: Off, Econo: On", + ac.toString()); + EXPECT_EQ(kToshibaACStateLengthLong, ac.getStateLength()); + const uint8_t expectedState[kToshibaACStateLengthLong] = { + 0xF2, 0x0D, 0x04, 0xFB, 0x09, 0xC0, 0x62, 0x00, 0x03, 0xA8}; + EXPECT_STATE_EQ(expectedState, ac.getRaw(), kToshibaACBitsLong); + EXPECT_EQ(kToshibaACStateLengthLong, ac.getStateLength()); +} diff --git a/lib/IRremoteESP8266-2.7.8/tools/RawToGlobalCache.sh b/lib/IRremoteESP8266-2.7.8/tools/RawToGlobalCache.sh old mode 100644 new mode 100755 diff --git a/lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data.py old mode 100644 new mode 100755 diff --git a/lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data_test.py old mode 100644 new mode 100755 diff --git a/lib/IRremoteESP8266-2.7.8/tools/generate_irtext_h.sh b/lib/IRremoteESP8266-2.7.8/tools/generate_irtext_h.sh old mode 100644 new mode 100755 diff --git a/lib/IRremoteESP8266-2.7.8/tools/mkkeywords b/lib/IRremoteESP8266-2.7.8/tools/mkkeywords old mode 100644 new mode 100755 diff --git a/lib/IRremoteESP8266-2.7.8/tools/scrape_supported_devices.py b/lib/IRremoteESP8266-2.7.8/tools/scrape_supported_devices.py old mode 100644 new mode 100755 diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 6a9520fcc..0f13cfe48 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -13,6 +13,7 @@ - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command (``S``)``SerialSend6`` \ (#8937) - Add support for Sonoff Zigbee Bridge as module 75 (#8583) +- Change IRRemoteESP8266 IR lib to pre-2.7.9, fixing Samsung and Pioneer protocols (#8938) ### 8.3.1.6 20200617 From 8e4d0adbd42a7ca73d37be52bb2a2f92647d83bb Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 29 Jul 2020 14:01:16 +0200 Subject: [PATCH 64/91] Use Tasmota Core 2.7.3.2... for development after release 8.4 is done --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index e7284356b..b0b047144 100644 --- a/platformio.ini +++ b/platformio.ini @@ -125,6 +125,6 @@ build_flags = -DUSE_IR_REMOTE_FULL [core] ; *** Esp8266 Tasmota modified Arduino core based on core 2.7.2 platform = espressif8266@2.5.1 -platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.2.1/esp8266-2.7.2.1.zip +platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.2/esp8266-2.7.3.2.zip build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} From cea0a47802060c441de2f14bf5ec1b07209aa630 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 29 Jul 2020 14:02:31 +0200 Subject: [PATCH 65/91] Core 2.7.3.2 --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index fa3a182c3..181254a59 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -6,7 +6,7 @@ - [ ] The pull request is done against the latest dev branch - [ ] Only relevant files were touched - [ ] Only one feature/fix was added per PR. - - [ ] The code change is tested and works on Tasmota core ESP8266 V.2.7.2.1 + - [ ] The code change is tested and works on Tasmota core ESP8266 V.2.7.3.2 - [ ] The code change is tested and works on core ESP32 V.1.12.2 - [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla). From ba3856d900d48365ab8bd3ec2d0069dbb893db49 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 29 Jul 2020 14:44:45 +0200 Subject: [PATCH 66/91] Change IRRemoteESP8266 library Change IRRemoteESP8266 library from v2.7.6 to v2.7.8.10, fixing Samsung and Pioneer protocols (#8938) --- RELEASENOTES.md | 2 +- .../CPPLINT.cfg | 0 .../Doxyfile | 0 .../LICENSE.txt | 0 .../README.md | 0 .../README_fr.md | 0 .../ReleaseNotes.md | 0 .../SupportedProtocols.md | 0 .../docs/README.md | 0 .../docs/README_fr.md | 0 .../docs/_config.yml | 0 .../docs/doxygen/html/IRac_8cpp.html | 0 .../docs/doxygen/html/IRac_8h.html | 0 .../docs/doxygen/html/IRac_8h_source.html | 0 .../docs/doxygen/html/IRrecv_8cpp.html | 0 .../docs/doxygen/html/IRrecv_8h.html | 0 .../docs/doxygen/html/IRrecv_8h_source.html | 0 .../docs/doxygen/html/IRremoteESP8266_8h.html | 0 .../html/IRremoteESP8266_8h_source.html | 0 .../docs/doxygen/html/IRsend_8cpp.html | 0 .../docs/doxygen/html/IRsend_8h.html | 0 .../docs/doxygen/html/IRsend_8h_source.html | 0 .../docs/doxygen/html/IRtext_8cpp.html | 0 .../docs/doxygen/html/IRtext_8h.html | 0 .../docs/doxygen/html/IRtext_8h_source.html | 0 .../docs/doxygen/html/IRtimer_8cpp.html | 0 .../docs/doxygen/html/IRtimer_8h.html | 0 .../docs/doxygen/html/IRtimer_8h_source.html | 0 .../docs/doxygen/html/IRutils_8cpp.html | 0 .../docs/doxygen/html/IRutils_8h.html | 0 .../docs/doxygen/html/IRutils_8h_source.html | 0 .../docs/doxygen/html/README_8md.html | 0 .../docs/doxygen/html/annotated.html | 0 .../docs/doxygen/html/bc_s.png | Bin .../docs/doxygen/html/bdwn.png | Bin .../doxygen/html/classIRAmcorAc-members.html | 0 .../docs/doxygen/html/classIRAmcorAc.html | 0 .../html/classIRAmcorAc__coll__graph.map | 0 .../html/classIRAmcorAc__coll__graph.md5 | 0 .../html/classIRAmcorAc__coll__graph.png | Bin .../doxygen/html/classIRArgoAC-members.html | 0 .../docs/doxygen/html/classIRArgoAC.html | 0 .../html/classIRArgoAC__coll__graph.map | 0 .../html/classIRArgoAC__coll__graph.md5 | 0 .../html/classIRArgoAC__coll__graph.png | Bin .../html/classIRCarrierAc64-members.html | 0 .../docs/doxygen/html/classIRCarrierAc64.html | 0 .../html/classIRCarrierAc64__coll__graph.map | 0 .../html/classIRCarrierAc64__coll__graph.md5 | 0 .../html/classIRCarrierAc64__coll__graph.png | Bin .../doxygen/html/classIRCoolixAC-members.html | 0 .../docs/doxygen/html/classIRCoolixAC.html | 0 .../html/classIRCoolixAC__coll__graph.map | 0 .../html/classIRCoolixAC__coll__graph.md5 | 0 .../html/classIRCoolixAC__coll__graph.png | Bin .../doxygen/html/classIRCoronaAc-members.html | 0 .../docs/doxygen/html/classIRCoronaAc.html | 0 .../html/classIRCoronaAc__coll__graph.map | 0 .../html/classIRCoronaAc__coll__graph.md5 | 0 .../html/classIRCoronaAc__coll__graph.png | Bin .../html/classIRDaikin128-members.html | 0 .../docs/doxygen/html/classIRDaikin128.html | 0 .../html/classIRDaikin128__coll__graph.map | 0 .../html/classIRDaikin128__coll__graph.md5 | 0 .../html/classIRDaikin128__coll__graph.png | Bin .../html/classIRDaikin152-members.html | 0 .../docs/doxygen/html/classIRDaikin152.html | 0 .../html/classIRDaikin152__coll__graph.map | 0 .../html/classIRDaikin152__coll__graph.md5 | 0 .../html/classIRDaikin152__coll__graph.png | Bin .../html/classIRDaikin160-members.html | 0 .../docs/doxygen/html/classIRDaikin160.html | 0 .../html/classIRDaikin160__coll__graph.map | 0 .../html/classIRDaikin160__coll__graph.md5 | 0 .../html/classIRDaikin160__coll__graph.png | Bin .../html/classIRDaikin176-members.html | 0 .../docs/doxygen/html/classIRDaikin176.html | 0 .../html/classIRDaikin176__coll__graph.map | 0 .../html/classIRDaikin176__coll__graph.md5 | 0 .../html/classIRDaikin176__coll__graph.png | Bin .../doxygen/html/classIRDaikin2-members.html | 0 .../docs/doxygen/html/classIRDaikin2.html | 0 .../html/classIRDaikin216-members.html | 0 .../docs/doxygen/html/classIRDaikin216.html | 0 .../html/classIRDaikin216__coll__graph.map | 0 .../html/classIRDaikin216__coll__graph.md5 | 0 .../html/classIRDaikin216__coll__graph.png | Bin .../html/classIRDaikin2__coll__graph.map | 0 .../html/classIRDaikin2__coll__graph.md5 | 0 .../html/classIRDaikin2__coll__graph.png | Bin .../doxygen/html/classIRDaikin64-members.html | 0 .../docs/doxygen/html/classIRDaikin64.html | 0 .../html/classIRDaikin64__coll__graph.map | 0 .../html/classIRDaikin64__coll__graph.md5 | 0 .../html/classIRDaikin64__coll__graph.png | Bin .../html/classIRDaikinESP-members.html | 0 .../docs/doxygen/html/classIRDaikinESP.html | 0 .../html/classIRDaikinESP__coll__graph.map | 0 .../html/classIRDaikinESP__coll__graph.md5 | 0 .../html/classIRDaikinESP__coll__graph.png | Bin .../html/classIRDelonghiAc-members.html | 0 .../docs/doxygen/html/classIRDelonghiAc.html | 0 .../html/classIRDelonghiAc__coll__graph.map | 0 .../html/classIRDelonghiAc__coll__graph.md5 | 0 .../html/classIRDelonghiAc__coll__graph.png | Bin .../html/classIRElectraAc-members.html | 0 .../docs/doxygen/html/classIRElectraAc.html | 0 .../html/classIRElectraAc__coll__graph.map | 0 .../html/classIRElectraAc__coll__graph.md5 | 0 .../html/classIRElectraAc__coll__graph.png | Bin .../html/classIRFujitsuAC-members.html | 0 .../docs/doxygen/html/classIRFujitsuAC.html | 0 .../html/classIRFujitsuAC__coll__graph.map | 0 .../html/classIRFujitsuAC__coll__graph.md5 | 0 .../html/classIRFujitsuAC__coll__graph.png | Bin .../html/classIRGoodweatherAc-members.html | 0 .../doxygen/html/classIRGoodweatherAc.html | 0 .../classIRGoodweatherAc__coll__graph.map | 0 .../classIRGoodweatherAc__coll__graph.md5 | 0 .../classIRGoodweatherAc__coll__graph.png | Bin .../doxygen/html/classIRGreeAC-members.html | 0 .../docs/doxygen/html/classIRGreeAC.html | 0 .../html/classIRGreeAC__coll__graph.map | 0 .../html/classIRGreeAC__coll__graph.md5 | 0 .../html/classIRGreeAC__coll__graph.png | Bin .../doxygen/html/classIRHaierAC-members.html | 0 .../docs/doxygen/html/classIRHaierAC.html | 0 .../html/classIRHaierACYRW02-members.html | 0 .../doxygen/html/classIRHaierACYRW02.html | 0 .../html/classIRHaierACYRW02__coll__graph.map | 0 .../html/classIRHaierACYRW02__coll__graph.md5 | 0 .../html/classIRHaierACYRW02__coll__graph.png | Bin .../html/classIRHaierAC__coll__graph.map | 0 .../html/classIRHaierAC__coll__graph.md5 | 0 .../html/classIRHaierAC__coll__graph.png | Bin .../html/classIRHitachiAc-members.html | 0 .../docs/doxygen/html/classIRHitachiAc.html | 0 .../html/classIRHitachiAc1-members.html | 0 .../docs/doxygen/html/classIRHitachiAc1.html | 0 .../html/classIRHitachiAc1__coll__graph.map | 0 .../html/classIRHitachiAc1__coll__graph.md5 | 0 .../html/classIRHitachiAc1__coll__graph.png | Bin .../html/classIRHitachiAc3-members.html | 0 .../docs/doxygen/html/classIRHitachiAc3.html | 0 .../html/classIRHitachiAc344-members.html | 0 .../doxygen/html/classIRHitachiAc344.html | 0 .../html/classIRHitachiAc344__coll__graph.map | 0 .../html/classIRHitachiAc344__coll__graph.md5 | 0 .../html/classIRHitachiAc344__coll__graph.png | Bin .../classIRHitachiAc344__inherit__graph.map | 0 .../classIRHitachiAc344__inherit__graph.md5 | 0 .../classIRHitachiAc344__inherit__graph.png | Bin .../html/classIRHitachiAc3__coll__graph.map | 0 .../html/classIRHitachiAc3__coll__graph.md5 | 0 .../html/classIRHitachiAc3__coll__graph.png | Bin .../html/classIRHitachiAc424-members.html | 0 .../doxygen/html/classIRHitachiAc424.html | 0 .../html/classIRHitachiAc424__coll__graph.map | 0 .../html/classIRHitachiAc424__coll__graph.md5 | 0 .../html/classIRHitachiAc424__coll__graph.png | Bin .../classIRHitachiAc424__inherit__graph.map | 0 .../classIRHitachiAc424__inherit__graph.md5 | 0 .../classIRHitachiAc424__inherit__graph.png | Bin .../html/classIRHitachiAc__coll__graph.map | 0 .../html/classIRHitachiAc__coll__graph.md5 | 0 .../html/classIRHitachiAc__coll__graph.png | Bin .../html/classIRKelvinatorAC-members.html | 0 .../doxygen/html/classIRKelvinatorAC.html | 0 .../html/classIRKelvinatorAC__coll__graph.map | 0 .../html/classIRKelvinatorAC__coll__graph.md5 | 0 .../html/classIRKelvinatorAC__coll__graph.png | Bin .../doxygen/html/classIRLgAc-members.html | 0 .../docs/doxygen/html/classIRLgAc.html | 0 .../doxygen/html/classIRLgAc__coll__graph.map | 0 .../doxygen/html/classIRLgAc__coll__graph.md5 | 0 .../doxygen/html/classIRLgAc__coll__graph.png | Bin .../doxygen/html/classIRMideaAC-members.html | 0 .../docs/doxygen/html/classIRMideaAC.html | 0 .../html/classIRMideaAC__coll__graph.map | 0 .../html/classIRMideaAC__coll__graph.md5 | 0 .../html/classIRMideaAC__coll__graph.png | Bin .../html/classIRMitsubishi112-members.html | 0 .../doxygen/html/classIRMitsubishi112.html | 0 .../classIRMitsubishi112__coll__graph.map | 0 .../classIRMitsubishi112__coll__graph.md5 | 0 .../classIRMitsubishi112__coll__graph.png | Bin .../html/classIRMitsubishi136-members.html | 0 .../doxygen/html/classIRMitsubishi136.html | 0 .../classIRMitsubishi136__coll__graph.map | 0 .../classIRMitsubishi136__coll__graph.md5 | 0 .../classIRMitsubishi136__coll__graph.png | Bin .../html/classIRMitsubishiAC-members.html | 0 .../doxygen/html/classIRMitsubishiAC.html | 0 .../html/classIRMitsubishiAC__coll__graph.map | 0 .../html/classIRMitsubishiAC__coll__graph.md5 | 0 .../html/classIRMitsubishiAC__coll__graph.png | Bin .../classIRMitsubishiHeavy152Ac-members.html | 0 .../html/classIRMitsubishiHeavy152Ac.html | 0 ...assIRMitsubishiHeavy152Ac__coll__graph.map | 0 ...assIRMitsubishiHeavy152Ac__coll__graph.md5 | 0 ...assIRMitsubishiHeavy152Ac__coll__graph.png | Bin .../classIRMitsubishiHeavy88Ac-members.html | 0 .../html/classIRMitsubishiHeavy88Ac.html | 0 ...lassIRMitsubishiHeavy88Ac__coll__graph.map | 0 ...lassIRMitsubishiHeavy88Ac__coll__graph.md5 | 0 ...lassIRMitsubishiHeavy88Ac__coll__graph.png | Bin .../html/classIRNeoclimaAc-members.html | 0 .../docs/doxygen/html/classIRNeoclimaAc.html | 0 .../html/classIRNeoclimaAc__coll__graph.map | 0 .../html/classIRNeoclimaAc__coll__graph.md5 | 0 .../html/classIRNeoclimaAc__coll__graph.png | Bin .../html/classIRPanasonicAc-members.html | 0 .../docs/doxygen/html/classIRPanasonicAc.html | 0 .../html/classIRPanasonicAc__coll__graph.map | 0 .../html/classIRPanasonicAc__coll__graph.md5 | 0 .../html/classIRPanasonicAc__coll__graph.png | Bin .../html/classIRSamsungAc-members.html | 0 .../docs/doxygen/html/classIRSamsungAc.html | 0 .../html/classIRSamsungAc__coll__graph.map | 0 .../html/classIRSamsungAc__coll__graph.md5 | 0 .../html/classIRSamsungAc__coll__graph.png | Bin .../doxygen/html/classIRSharpAc-members.html | 0 .../docs/doxygen/html/classIRSharpAc.html | 0 .../html/classIRSharpAc__coll__graph.map | 0 .../html/classIRSharpAc__coll__graph.md5 | 0 .../html/classIRSharpAc__coll__graph.png | Bin .../doxygen/html/classIRTcl112Ac-members.html | 0 .../docs/doxygen/html/classIRTcl112Ac.html | 0 .../html/classIRTcl112Ac__coll__graph.map | 0 .../html/classIRTcl112Ac__coll__graph.md5 | 0 .../html/classIRTcl112Ac__coll__graph.png | Bin .../doxygen/html/classIRTecoAc-members.html | 0 .../docs/doxygen/html/classIRTecoAc.html | 0 .../html/classIRTecoAc__coll__graph.map | 0 .../html/classIRTecoAc__coll__graph.md5 | 0 .../html/classIRTecoAc__coll__graph.png | Bin .../html/classIRToshibaAC-members.html | 0 .../docs/doxygen/html/classIRToshibaAC.html | 0 .../html/classIRToshibaAC__coll__graph.map | 0 .../html/classIRToshibaAC__coll__graph.md5 | 0 .../html/classIRToshibaAC__coll__graph.png | Bin .../html/classIRTrotecESP-members.html | 0 .../docs/doxygen/html/classIRTrotecESP.html | 0 .../html/classIRTrotecESP__coll__graph.map | 0 .../html/classIRTrotecESP__coll__graph.md5 | 0 .../html/classIRTrotecESP__coll__graph.png | Bin .../doxygen/html/classIRVestelAc-members.html | 0 .../docs/doxygen/html/classIRVestelAc.html | 0 .../html/classIRVestelAc__coll__graph.map | 0 .../html/classIRVestelAc__coll__graph.md5 | 0 .../html/classIRVestelAc__coll__graph.png | Bin .../html/classIRWhirlpoolAc-members.html | 0 .../docs/doxygen/html/classIRWhirlpoolAc.html | 0 .../html/classIRWhirlpoolAc__coll__graph.map | 0 .../html/classIRWhirlpoolAc__coll__graph.md5 | 0 .../html/classIRWhirlpoolAc__coll__graph.png | Bin .../docs/doxygen/html/classIRac-members.html | 0 .../docs/doxygen/html/classIRac.html | 0 .../doxygen/html/classIRac__coll__graph.map | 0 .../doxygen/html/classIRac__coll__graph.md5 | 0 .../doxygen/html/classIRac__coll__graph.png | Bin .../doxygen/html/classIRrecv-members.html | 0 .../docs/doxygen/html/classIRrecv.html | 0 .../doxygen/html/classIRrecv__coll__graph.map | 0 .../doxygen/html/classIRrecv__coll__graph.md5 | 0 .../doxygen/html/classIRrecv__coll__graph.png | Bin .../doxygen/html/classIRsend-members.html | 0 .../docs/doxygen/html/classIRsend.html | 0 .../doxygen/html/classIRtimer-members.html | 0 .../docs/doxygen/html/classIRtimer.html | 0 .../doxygen/html/classTimerMs-members.html | 0 .../docs/doxygen/html/classTimerMs.html | 0 .../html/classdecode__results-members.html | 0 .../doxygen/html/classdecode__results.html | 0 .../docs/doxygen/html/classes.html | 0 .../docs/doxygen/html/closed.png | Bin .../docs/doxygen/html/de-CH_8h.html | 0 .../docs/doxygen/html/de-CH_8h_source.html | 0 .../docs/doxygen/html/de-DE_8h.html | 0 .../docs/doxygen/html/de-DE_8h_source.html | 0 .../docs/doxygen/html/defaults_8h.html | 0 .../docs/doxygen/html/defaults_8h_source.html | 0 .../docs/doxygen/html/deprecated.html | 0 .../dir_49e56c817e5e54854c35e136979f97ca.html | 0 .../dir_68267d1309a1af8e8297ef4c3efbcdba.html | 0 .../dir_84fe998d1eb06414cc389ad334e77e63.html | 0 .../docs/doxygen/html/doc.png | Bin .../docs/doxygen/html/doxygen.css | 0 .../docs/doxygen/html/doxygen.png | Bin .../docs/doxygen/html/doxygen__index_8md.html | 0 .../docs/doxygen/html/dynsections.js | 0 .../docs/doxygen/html/en-AU_8h.html | 0 .../docs/doxygen/html/en-AU_8h_source.html | 0 .../docs/doxygen/html/en-IE_8h.html | 0 .../docs/doxygen/html/en-IE_8h_source.html | 0 .../docs/doxygen/html/en-UK_8h.html | 0 .../docs/doxygen/html/en-UK_8h_source.html | 0 .../docs/doxygen/html/en-US_8h.html | 0 .../docs/doxygen/html/en-US_8h_source.html | 0 .../docs/doxygen/html/es-ES_8h.html | 0 .../docs/doxygen/html/es-ES_8h_source.html | 0 .../docs/doxygen/html/files.html | 0 .../docs/doxygen/html/folderclosed.png | Bin .../docs/doxygen/html/folderopen.png | Bin .../docs/doxygen/html/fr-FR_8h.html | 0 .../docs/doxygen/html/fr-FR_8h_source.html | 0 .../docs/doxygen/html/functions.html | 0 .../docs/doxygen/html/functions_a.html | 0 .../docs/doxygen/html/functions_b.html | 0 .../docs/doxygen/html/functions_c.html | 0 .../docs/doxygen/html/functions_d.html | 0 .../docs/doxygen/html/functions_e.html | 0 .../docs/doxygen/html/functions_f.html | 0 .../docs/doxygen/html/functions_func.html | 0 .../docs/doxygen/html/functions_func_a.html | 0 .../docs/doxygen/html/functions_func_b.html | 0 .../docs/doxygen/html/functions_func_c.html | 0 .../docs/doxygen/html/functions_func_d.html | 0 .../docs/doxygen/html/functions_func_e.html | 0 .../docs/doxygen/html/functions_func_f.html | 0 .../docs/doxygen/html/functions_func_g.html | 0 .../docs/doxygen/html/functions_func_h.html | 0 .../docs/doxygen/html/functions_func_i.html | 0 .../docs/doxygen/html/functions_func_k.html | 0 .../docs/doxygen/html/functions_func_l.html | 0 .../docs/doxygen/html/functions_func_m.html | 0 .../docs/doxygen/html/functions_func_n.html | 0 .../docs/doxygen/html/functions_func_o.html | 0 .../docs/doxygen/html/functions_func_p.html | 0 .../docs/doxygen/html/functions_func_r.html | 0 .../docs/doxygen/html/functions_func_s.html | 0 .../docs/doxygen/html/functions_func_t.html | 0 .../docs/doxygen/html/functions_func_u.html | 0 .../docs/doxygen/html/functions_func_v.html | 0 .../docs/doxygen/html/functions_func_w.html | 0 .../docs/doxygen/html/functions_func_~.html | 0 .../docs/doxygen/html/functions_g.html | 0 .../docs/doxygen/html/functions_h.html | 0 .../docs/doxygen/html/functions_i.html | 0 .../docs/doxygen/html/functions_k.html | 0 .../docs/doxygen/html/functions_l.html | 0 .../docs/doxygen/html/functions_m.html | 0 .../docs/doxygen/html/functions_n.html | 0 .../docs/doxygen/html/functions_o.html | 0 .../docs/doxygen/html/functions_p.html | 0 .../docs/doxygen/html/functions_q.html | 0 .../docs/doxygen/html/functions_r.html | 0 .../docs/doxygen/html/functions_rela.html | 0 .../docs/doxygen/html/functions_s.html | 0 .../docs/doxygen/html/functions_t.html | 0 .../docs/doxygen/html/functions_u.html | 0 .../docs/doxygen/html/functions_v.html | 0 .../docs/doxygen/html/functions_vars.html | 0 .../docs/doxygen/html/functions_vars_a.html | 0 .../docs/doxygen/html/functions_vars_b.html | 0 .../docs/doxygen/html/functions_vars_c.html | 0 .../docs/doxygen/html/functions_vars_d.html | 0 .../docs/doxygen/html/functions_vars_e.html | 0 .../docs/doxygen/html/functions_vars_f.html | 0 .../docs/doxygen/html/functions_vars_h.html | 0 .../docs/doxygen/html/functions_vars_i.html | 0 .../docs/doxygen/html/functions_vars_l.html | 0 .../docs/doxygen/html/functions_vars_m.html | 0 .../docs/doxygen/html/functions_vars_n.html | 0 .../docs/doxygen/html/functions_vars_o.html | 0 .../docs/doxygen/html/functions_vars_p.html | 0 .../docs/doxygen/html/functions_vars_q.html | 0 .../docs/doxygen/html/functions_vars_r.html | 0 .../docs/doxygen/html/functions_vars_s.html | 0 .../docs/doxygen/html/functions_vars_t.html | 0 .../docs/doxygen/html/functions_vars_u.html | 0 .../docs/doxygen/html/functions_vars_v.html | 0 .../docs/doxygen/html/functions_vars_w.html | 0 .../docs/doxygen/html/functions_vars_z.html | 0 .../docs/doxygen/html/functions_w.html | 0 .../docs/doxygen/html/functions_z.html | 0 .../docs/doxygen/html/functions_~.html | 0 .../docs/doxygen/html/globals.html | 0 .../docs/doxygen/html/globals_a.html | 0 .../docs/doxygen/html/globals_c.html | 0 .../docs/doxygen/html/globals_d.html | 0 .../docs/doxygen/html/globals_e.html | 0 .../docs/doxygen/html/globals_enum.html | 0 .../docs/doxygen/html/globals_eval.html | 0 .../docs/doxygen/html/globals_f.html | 0 .../docs/doxygen/html/globals_func.html | 0 .../docs/doxygen/html/globals_g.html | 0 .../docs/doxygen/html/globals_h.html | 0 .../docs/doxygen/html/globals_i.html | 0 .../docs/doxygen/html/globals_j.html | 0 .../docs/doxygen/html/globals_k.html | 0 .../docs/doxygen/html/globals_l.html | 0 .../docs/doxygen/html/globals_m.html | 0 .../docs/doxygen/html/globals_n.html | 0 .../docs/doxygen/html/globals_p.html | 0 .../docs/doxygen/html/globals_r.html | 0 .../docs/doxygen/html/globals_s.html | 0 .../docs/doxygen/html/globals_t.html | 0 .../docs/doxygen/html/globals_type.html | 0 .../docs/doxygen/html/globals_u.html | 0 .../docs/doxygen/html/globals_v.html | 0 .../docs/doxygen/html/globals_vars.html | 0 .../docs/doxygen/html/globals_vars_i.html | 0 .../docs/doxygen/html/globals_vars_k.html | 0 .../docs/doxygen/html/globals_w.html | 0 .../docs/doxygen/html/globals_x.html | 0 .../docs/doxygen/html/globals_y.html | 0 .../docs/doxygen/html/globals_z.html | 0 .../docs/doxygen/html/graph_legend.html | 0 .../docs/doxygen/html/graph_legend.md5 | 0 .../docs/doxygen/html/graph_legend.png | Bin .../docs/doxygen/html/hierarchy.html | 0 .../docs/doxygen/html/i18n_8h.html | 0 .../docs/doxygen/html/i18n_8h_source.html | 0 .../docs/doxygen/html/index.html | 0 .../docs/doxygen/html/inherit_graph_0.map | 0 .../docs/doxygen/html/inherit_graph_0.md5 | 0 .../docs/doxygen/html/inherit_graph_0.png | Bin .../docs/doxygen/html/inherit_graph_1.map | 0 .../docs/doxygen/html/inherit_graph_1.md5 | 0 .../docs/doxygen/html/inherit_graph_1.png | Bin .../docs/doxygen/html/inherit_graph_10.map | 0 .../docs/doxygen/html/inherit_graph_10.md5 | 0 .../docs/doxygen/html/inherit_graph_10.png | Bin .../docs/doxygen/html/inherit_graph_11.map | 0 .../docs/doxygen/html/inherit_graph_11.md5 | 0 .../docs/doxygen/html/inherit_graph_11.png | Bin .../docs/doxygen/html/inherit_graph_12.map | 0 .../docs/doxygen/html/inherit_graph_12.md5 | 0 .../docs/doxygen/html/inherit_graph_12.png | Bin .../docs/doxygen/html/inherit_graph_13.map | 0 .../docs/doxygen/html/inherit_graph_13.md5 | 0 .../docs/doxygen/html/inherit_graph_13.png | Bin .../docs/doxygen/html/inherit_graph_14.map | 0 .../docs/doxygen/html/inherit_graph_14.md5 | 0 .../docs/doxygen/html/inherit_graph_14.png | Bin .../docs/doxygen/html/inherit_graph_15.map | 0 .../docs/doxygen/html/inherit_graph_15.md5 | 0 .../docs/doxygen/html/inherit_graph_15.png | Bin .../docs/doxygen/html/inherit_graph_16.map | 0 .../docs/doxygen/html/inherit_graph_16.md5 | 0 .../docs/doxygen/html/inherit_graph_16.png | Bin .../docs/doxygen/html/inherit_graph_17.map | 0 .../docs/doxygen/html/inherit_graph_17.md5 | 0 .../docs/doxygen/html/inherit_graph_17.png | Bin .../docs/doxygen/html/inherit_graph_18.map | 0 .../docs/doxygen/html/inherit_graph_18.md5 | 0 .../docs/doxygen/html/inherit_graph_18.png | Bin .../docs/doxygen/html/inherit_graph_19.map | 0 .../docs/doxygen/html/inherit_graph_19.md5 | 0 .../docs/doxygen/html/inherit_graph_19.png | Bin .../docs/doxygen/html/inherit_graph_2.map | 0 .../docs/doxygen/html/inherit_graph_2.md5 | 0 .../docs/doxygen/html/inherit_graph_2.png | Bin .../docs/doxygen/html/inherit_graph_20.map | 0 .../docs/doxygen/html/inherit_graph_20.md5 | 0 .../docs/doxygen/html/inherit_graph_20.png | Bin .../docs/doxygen/html/inherit_graph_21.map | 0 .../docs/doxygen/html/inherit_graph_21.md5 | 0 .../docs/doxygen/html/inherit_graph_21.png | Bin .../docs/doxygen/html/inherit_graph_22.map | 0 .../docs/doxygen/html/inherit_graph_22.md5 | 0 .../docs/doxygen/html/inherit_graph_22.png | Bin .../docs/doxygen/html/inherit_graph_23.map | 0 .../docs/doxygen/html/inherit_graph_23.md5 | 0 .../docs/doxygen/html/inherit_graph_23.png | Bin .../docs/doxygen/html/inherit_graph_24.map | 0 .../docs/doxygen/html/inherit_graph_24.md5 | 0 .../docs/doxygen/html/inherit_graph_24.png | Bin .../docs/doxygen/html/inherit_graph_25.map | 0 .../docs/doxygen/html/inherit_graph_25.md5 | 0 .../docs/doxygen/html/inherit_graph_25.png | Bin .../docs/doxygen/html/inherit_graph_26.map | 0 .../docs/doxygen/html/inherit_graph_26.md5 | 0 .../docs/doxygen/html/inherit_graph_26.png | Bin .../docs/doxygen/html/inherit_graph_27.map | 0 .../docs/doxygen/html/inherit_graph_27.md5 | 0 .../docs/doxygen/html/inherit_graph_27.png | Bin .../docs/doxygen/html/inherit_graph_28.map | 0 .../docs/doxygen/html/inherit_graph_28.md5 | 0 .../docs/doxygen/html/inherit_graph_28.png | Bin .../docs/doxygen/html/inherit_graph_29.map | 0 .../docs/doxygen/html/inherit_graph_29.md5 | 0 .../docs/doxygen/html/inherit_graph_29.png | Bin .../docs/doxygen/html/inherit_graph_3.map | 0 .../docs/doxygen/html/inherit_graph_3.md5 | 0 .../docs/doxygen/html/inherit_graph_3.png | Bin .../docs/doxygen/html/inherit_graph_30.map | 0 .../docs/doxygen/html/inherit_graph_30.md5 | 0 .../docs/doxygen/html/inherit_graph_30.png | Bin .../docs/doxygen/html/inherit_graph_31.map | 0 .../docs/doxygen/html/inherit_graph_31.md5 | 0 .../docs/doxygen/html/inherit_graph_31.png | Bin .../docs/doxygen/html/inherit_graph_32.map | 0 .../docs/doxygen/html/inherit_graph_32.md5 | 0 .../docs/doxygen/html/inherit_graph_32.png | Bin .../docs/doxygen/html/inherit_graph_33.map | 0 .../docs/doxygen/html/inherit_graph_33.md5 | 0 .../docs/doxygen/html/inherit_graph_33.png | Bin .../docs/doxygen/html/inherit_graph_34.map | 0 .../docs/doxygen/html/inherit_graph_34.md5 | 0 .../docs/doxygen/html/inherit_graph_34.png | Bin .../docs/doxygen/html/inherit_graph_35.map | 0 .../docs/doxygen/html/inherit_graph_35.md5 | 0 .../docs/doxygen/html/inherit_graph_35.png | Bin .../docs/doxygen/html/inherit_graph_36.map | 0 .../docs/doxygen/html/inherit_graph_36.md5 | 0 .../docs/doxygen/html/inherit_graph_36.png | Bin .../docs/doxygen/html/inherit_graph_37.map | 0 .../docs/doxygen/html/inherit_graph_37.md5 | 0 .../docs/doxygen/html/inherit_graph_37.png | Bin .../docs/doxygen/html/inherit_graph_38.map | 0 .../docs/doxygen/html/inherit_graph_38.md5 | 0 .../docs/doxygen/html/inherit_graph_38.png | Bin .../docs/doxygen/html/inherit_graph_39.map | 0 .../docs/doxygen/html/inherit_graph_39.md5 | 0 .../docs/doxygen/html/inherit_graph_39.png | Bin .../docs/doxygen/html/inherit_graph_4.map | 0 .../docs/doxygen/html/inherit_graph_4.md5 | 0 .../docs/doxygen/html/inherit_graph_4.png | Bin .../docs/doxygen/html/inherit_graph_40.map | 0 .../docs/doxygen/html/inherit_graph_40.md5 | 0 .../docs/doxygen/html/inherit_graph_40.png | Bin .../docs/doxygen/html/inherit_graph_41.map | 0 .../docs/doxygen/html/inherit_graph_41.md5 | 0 .../docs/doxygen/html/inherit_graph_41.png | Bin .../docs/doxygen/html/inherit_graph_42.map | 0 .../docs/doxygen/html/inherit_graph_42.md5 | 0 .../docs/doxygen/html/inherit_graph_42.png | Bin .../docs/doxygen/html/inherit_graph_43.map | 0 .../docs/doxygen/html/inherit_graph_43.md5 | 0 .../docs/doxygen/html/inherit_graph_43.png | Bin .../docs/doxygen/html/inherit_graph_44.map | 0 .../docs/doxygen/html/inherit_graph_44.md5 | 0 .../docs/doxygen/html/inherit_graph_44.png | Bin .../docs/doxygen/html/inherit_graph_45.map | 0 .../docs/doxygen/html/inherit_graph_45.md5 | 0 .../docs/doxygen/html/inherit_graph_45.png | Bin .../docs/doxygen/html/inherit_graph_46.map | 0 .../docs/doxygen/html/inherit_graph_46.md5 | 0 .../docs/doxygen/html/inherit_graph_46.png | Bin .../docs/doxygen/html/inherit_graph_47.map | 0 .../docs/doxygen/html/inherit_graph_47.md5 | 0 .../docs/doxygen/html/inherit_graph_47.png | Bin .../docs/doxygen/html/inherit_graph_48.map | 0 .../docs/doxygen/html/inherit_graph_48.md5 | 0 .../docs/doxygen/html/inherit_graph_48.png | Bin .../docs/doxygen/html/inherit_graph_49.map | 0 .../docs/doxygen/html/inherit_graph_49.md5 | 0 .../docs/doxygen/html/inherit_graph_49.png | Bin .../docs/doxygen/html/inherit_graph_5.map | 0 .../docs/doxygen/html/inherit_graph_5.md5 | 0 .../docs/doxygen/html/inherit_graph_5.png | Bin .../docs/doxygen/html/inherit_graph_50.map | 0 .../docs/doxygen/html/inherit_graph_50.md5 | 0 .../docs/doxygen/html/inherit_graph_50.png | Bin .../docs/doxygen/html/inherit_graph_51.map | 0 .../docs/doxygen/html/inherit_graph_51.md5 | 0 .../docs/doxygen/html/inherit_graph_51.png | Bin .../docs/doxygen/html/inherit_graph_6.map | 0 .../docs/doxygen/html/inherit_graph_6.md5 | 0 .../docs/doxygen/html/inherit_graph_6.png | Bin .../docs/doxygen/html/inherit_graph_7.map | 0 .../docs/doxygen/html/inherit_graph_7.md5 | 0 .../docs/doxygen/html/inherit_graph_7.png | Bin .../docs/doxygen/html/inherit_graph_8.map | 0 .../docs/doxygen/html/inherit_graph_8.md5 | 0 .../docs/doxygen/html/inherit_graph_8.png | Bin .../docs/doxygen/html/inherit_graph_9.map | 0 .../docs/doxygen/html/inherit_graph_9.md5 | 0 .../docs/doxygen/html/inherit_graph_9.png | Bin .../docs/doxygen/html/inherits.html | 0 .../docs/doxygen/html/ir__Airwell_8cpp.html | 0 .../docs/doxygen/html/ir__Aiwa_8cpp.html | 0 .../docs/doxygen/html/ir__Amcor_8cpp.html | 0 .../docs/doxygen/html/ir__Amcor_8h.html | 0 .../doxygen/html/ir__Amcor_8h_source.html | 0 .../docs/doxygen/html/ir__Argo_8cpp.html | 0 .../docs/doxygen/html/ir__Argo_8h.html | 0 .../docs/doxygen/html/ir__Argo_8h_source.html | 0 .../docs/doxygen/html/ir__Carrier_8cpp.html | 0 .../docs/doxygen/html/ir__Carrier_8h.html | 0 .../doxygen/html/ir__Carrier_8h_source.html | 0 .../docs/doxygen/html/ir__Coolix_8cpp.html | 0 .../docs/doxygen/html/ir__Coolix_8h.html | 0 .../doxygen/html/ir__Coolix_8h_source.html | 0 .../docs/doxygen/html/ir__Corona_8cpp.html | 0 .../docs/doxygen/html/ir__Corona_8h.html | 0 .../doxygen/html/ir__Corona_8h_source.html | 0 .../docs/doxygen/html/ir__Daikin_8cpp.html | 0 .../docs/doxygen/html/ir__Daikin_8h.html | 0 .../doxygen/html/ir__Daikin_8h_source.html | 0 .../docs/doxygen/html/ir__Delonghi_8cpp.html | 0 .../docs/doxygen/html/ir__Delonghi_8h.html | 0 .../doxygen/html/ir__Delonghi_8h_source.html | 0 .../docs/doxygen/html/ir__Denon_8cpp.html | 0 .../docs/doxygen/html/ir__Dish_8cpp.html | 0 .../docs/doxygen/html/ir__Doshisha_8cpp.html | 0 .../docs/doxygen/html/ir__Electra_8cpp.html | 0 .../docs/doxygen/html/ir__Electra_8h.html | 0 .../doxygen/html/ir__Electra_8h_source.html | 0 .../docs/doxygen/html/ir__Epson_8cpp.html | 0 .../docs/doxygen/html/ir__Fujitsu_8cpp.html | 0 .../docs/doxygen/html/ir__Fujitsu_8h.html | 0 .../doxygen/html/ir__Fujitsu_8h_source.html | 0 .../docs/doxygen/html/ir__GICable_8cpp.html | 0 .../doxygen/html/ir__GlobalCache_8cpp.html | 0 .../doxygen/html/ir__Goodweather_8cpp.html | 0 .../docs/doxygen/html/ir__Goodweather_8h.html | 0 .../html/ir__Goodweather_8h_source.html | 0 .../docs/doxygen/html/ir__Gree_8cpp.html | 0 .../docs/doxygen/html/ir__Gree_8h.html | 0 .../docs/doxygen/html/ir__Gree_8h_source.html | 0 .../docs/doxygen/html/ir__Haier_8cpp.html | 0 .../docs/doxygen/html/ir__Haier_8h.html | 0 .../doxygen/html/ir__Haier_8h_source.html | 0 .../docs/doxygen/html/ir__Hitachi_8cpp.html | 0 .../docs/doxygen/html/ir__Hitachi_8h.html | 0 .../doxygen/html/ir__Hitachi_8h_source.html | 0 .../docs/doxygen/html/ir__Inax_8cpp.html | 0 .../docs/doxygen/html/ir__JVC_8cpp.html | 0 .../doxygen/html/ir__Kelvinator_8cpp.html | 0 .../docs/doxygen/html/ir__Kelvinator_8h.html | 0 .../html/ir__Kelvinator_8h_source.html | 0 .../docs/doxygen/html/ir__LG_8cpp.html | 0 .../docs/doxygen/html/ir__LG_8h.html | 0 .../docs/doxygen/html/ir__LG_8h_source.html | 0 .../docs/doxygen/html/ir__Lasertag_8cpp.html | 0 .../docs/doxygen/html/ir__Lego_8cpp.html | 0 .../docs/doxygen/html/ir__Lutron_8cpp.html | 0 .../docs/doxygen/html/ir__MWM_8cpp.html | 0 .../docs/doxygen/html/ir__Magiquest_8cpp.html | 0 .../docs/doxygen/html/ir__Magiquest_8h.html | 0 .../doxygen/html/ir__Magiquest_8h_source.html | 0 .../docs/doxygen/html/ir__Midea_8cpp.html | 0 .../docs/doxygen/html/ir__Midea_8h.html | 0 .../doxygen/html/ir__Midea_8h_source.html | 0 .../html/ir__MitsubishiHeavy_8cpp.html | 0 .../doxygen/html/ir__MitsubishiHeavy_8h.html | 0 .../html/ir__MitsubishiHeavy_8h_source.html | 0 .../doxygen/html/ir__Mitsubishi_8cpp.html | 0 .../docs/doxygen/html/ir__Mitsubishi_8h.html | 0 .../html/ir__Mitsubishi_8h_source.html | 0 .../doxygen/html/ir__Multibrackets_8cpp.html | 0 .../docs/doxygen/html/ir__NEC_8cpp.html | 0 .../docs/doxygen/html/ir__NEC_8h.html | 0 .../docs/doxygen/html/ir__NEC_8h_source.html | 0 .../docs/doxygen/html/ir__Neoclima_8cpp.html | 0 .../docs/doxygen/html/ir__Neoclima_8h.html | 0 .../doxygen/html/ir__Neoclima_8h_source.html | 0 .../docs/doxygen/html/ir__Nikai_8cpp.html | 0 .../docs/doxygen/html/ir__Panasonic_8cpp.html | 0 .../docs/doxygen/html/ir__Panasonic_8h.html | 0 .../doxygen/html/ir__Panasonic_8h_source.html | 0 .../docs/doxygen/html/ir__Pioneer_8cpp.html | 0 .../docs/doxygen/html/ir__Pronto_8cpp.html | 0 .../docs/doxygen/html/ir__RC5__RC6_8cpp.html | 0 .../docs/doxygen/html/ir__RCMM_8cpp.html | 0 .../docs/doxygen/html/ir__Samsung_8cpp.html | 0 .../docs/doxygen/html/ir__Samsung_8h.html | 0 .../doxygen/html/ir__Samsung_8h_source.html | 0 .../docs/doxygen/html/ir__Sanyo_8cpp.html | 0 .../docs/doxygen/html/ir__Sharp_8cpp.html | 0 .../docs/doxygen/html/ir__Sharp_8h.html | 0 .../doxygen/html/ir__Sharp_8h_source.html | 0 .../docs/doxygen/html/ir__Sherwood_8cpp.html | 0 .../docs/doxygen/html/ir__Sony_8cpp.html | 0 .../docs/doxygen/html/ir__Symphony_8cpp.html | 0 .../docs/doxygen/html/ir__Tcl_8cpp.html | 0 .../docs/doxygen/html/ir__Tcl_8h.html | 0 .../docs/doxygen/html/ir__Tcl_8h_source.html | 0 .../docs/doxygen/html/ir__Teco_8cpp.html | 0 .../docs/doxygen/html/ir__Teco_8h.html | 0 .../docs/doxygen/html/ir__Teco_8h_source.html | 0 .../docs/doxygen/html/ir__Toshiba_8cpp.html | 0 .../docs/doxygen/html/ir__Toshiba_8h.html | 0 .../doxygen/html/ir__Toshiba_8h_source.html | 0 .../docs/doxygen/html/ir__Trotec_8cpp.html | 0 .../docs/doxygen/html/ir__Trotec_8h.html | 0 .../doxygen/html/ir__Trotec_8h_source.html | 0 .../docs/doxygen/html/ir__Vestel_8cpp.html | 0 .../docs/doxygen/html/ir__Vestel_8h.html | 0 .../doxygen/html/ir__Vestel_8h_source.html | 0 .../docs/doxygen/html/ir__Whirlpool_8cpp.html | 0 .../docs/doxygen/html/ir__Whirlpool_8h.html | 0 .../doxygen/html/ir__Whirlpool_8h_source.html | 0 .../docs/doxygen/html/ir__Whynter_8cpp.html | 0 .../docs/doxygen/html/ir__Zepeal_8cpp.html | 0 .../docs/doxygen/html/it-IT_8h.html | 0 .../docs/doxygen/html/it-IT_8h_source.html | 0 .../docs/doxygen/html/jquery.js | 0 .../doxygen/html/md_src_locale_README.html | 0 .../docs/doxygen/html/menu.js | 0 .../docs/doxygen/html/menudata.js | 0 .../docs/doxygen/html/namespaceIRAcUtils.html | 0 .../docs/doxygen/html/namespaceirutils.html | 0 .../docs/doxygen/html/namespacemembers.html | 0 .../doxygen/html/namespacemembers_enum.html | 0 .../doxygen/html/namespacemembers_func.html | 0 .../docs/doxygen/html/namespaces.html | 0 .../docs/doxygen/html/namespacestdAc.html | 0 .../docs/doxygen/html/nav_f.png | Bin .../docs/doxygen/html/nav_g.png | Bin .../docs/doxygen/html/nav_h.png | Bin .../docs/doxygen/html/open.png | Bin .../docs/doxygen/html/pages.html | 0 .../docs/doxygen/html/search/all_0.html | 0 .../docs/doxygen/html/search/all_0.js | 0 .../docs/doxygen/html/search/all_1.html | 0 .../docs/doxygen/html/search/all_1.js | 0 .../docs/doxygen/html/search/all_10.html | 0 .../docs/doxygen/html/search/all_10.js | 0 .../docs/doxygen/html/search/all_11.html | 0 .../docs/doxygen/html/search/all_11.js | 0 .../docs/doxygen/html/search/all_12.html | 0 .../docs/doxygen/html/search/all_12.js | 0 .../docs/doxygen/html/search/all_13.html | 0 .../docs/doxygen/html/search/all_13.js | 0 .../docs/doxygen/html/search/all_14.html | 0 .../docs/doxygen/html/search/all_14.js | 0 .../docs/doxygen/html/search/all_15.html | 0 .../docs/doxygen/html/search/all_15.js | 0 .../docs/doxygen/html/search/all_16.html | 0 .../docs/doxygen/html/search/all_16.js | 0 .../docs/doxygen/html/search/all_17.html | 0 .../docs/doxygen/html/search/all_17.js | 0 .../docs/doxygen/html/search/all_18.html | 0 .../docs/doxygen/html/search/all_18.js | 0 .../docs/doxygen/html/search/all_19.html | 0 .../docs/doxygen/html/search/all_19.js | 0 .../docs/doxygen/html/search/all_1a.html | 0 .../docs/doxygen/html/search/all_1a.js | 0 .../docs/doxygen/html/search/all_1b.html | 0 .../docs/doxygen/html/search/all_1b.js | 0 .../docs/doxygen/html/search/all_2.html | 0 .../docs/doxygen/html/search/all_2.js | 0 .../docs/doxygen/html/search/all_3.html | 0 .../docs/doxygen/html/search/all_3.js | 0 .../docs/doxygen/html/search/all_4.html | 0 .../docs/doxygen/html/search/all_4.js | 0 .../docs/doxygen/html/search/all_5.html | 0 .../docs/doxygen/html/search/all_5.js | 0 .../docs/doxygen/html/search/all_6.html | 0 .../docs/doxygen/html/search/all_6.js | 0 .../docs/doxygen/html/search/all_7.html | 0 .../docs/doxygen/html/search/all_7.js | 0 .../docs/doxygen/html/search/all_8.html | 0 .../docs/doxygen/html/search/all_8.js | 0 .../docs/doxygen/html/search/all_9.html | 0 .../docs/doxygen/html/search/all_9.js | 0 .../docs/doxygen/html/search/all_a.html | 0 .../docs/doxygen/html/search/all_a.js | 0 .../docs/doxygen/html/search/all_b.html | 0 .../docs/doxygen/html/search/all_b.js | 0 .../docs/doxygen/html/search/all_c.html | 0 .../docs/doxygen/html/search/all_c.js | 0 .../docs/doxygen/html/search/all_d.html | 0 .../docs/doxygen/html/search/all_d.js | 0 .../docs/doxygen/html/search/all_e.html | 0 .../docs/doxygen/html/search/all_e.js | 0 .../docs/doxygen/html/search/all_f.html | 0 .../docs/doxygen/html/search/all_f.js | 0 .../docs/doxygen/html/search/classes_0.html | 0 .../docs/doxygen/html/search/classes_0.js | 0 .../docs/doxygen/html/search/classes_1.html | 0 .../docs/doxygen/html/search/classes_1.js | 0 .../docs/doxygen/html/search/classes_2.html | 0 .../docs/doxygen/html/search/classes_2.js | 0 .../docs/doxygen/html/search/classes_3.html | 0 .../docs/doxygen/html/search/classes_3.js | 0 .../docs/doxygen/html/search/classes_4.html | 0 .../docs/doxygen/html/search/classes_4.js | 0 .../docs/doxygen/html/search/close.png | Bin .../docs/doxygen/html/search/enums_0.html | 0 .../docs/doxygen/html/search/enums_0.js | 0 .../docs/doxygen/html/search/enums_1.html | 0 .../docs/doxygen/html/search/enums_1.js | 0 .../docs/doxygen/html/search/enums_2.html | 0 .../docs/doxygen/html/search/enums_2.js | 0 .../docs/doxygen/html/search/enums_3.html | 0 .../docs/doxygen/html/search/enums_3.js | 0 .../docs/doxygen/html/search/enums_4.html | 0 .../docs/doxygen/html/search/enums_4.js | 0 .../docs/doxygen/html/search/enums_5.html | 0 .../docs/doxygen/html/search/enums_5.js | 0 .../docs/doxygen/html/search/enums_6.html | 0 .../docs/doxygen/html/search/enums_6.js | 0 .../docs/doxygen/html/search/enums_7.html | 0 .../docs/doxygen/html/search/enums_7.js | 0 .../docs/doxygen/html/search/enums_8.html | 0 .../docs/doxygen/html/search/enums_8.js | 0 .../doxygen/html/search/enumvalues_0.html | 0 .../docs/doxygen/html/search/enumvalues_0.js | 0 .../doxygen/html/search/enumvalues_1.html | 0 .../docs/doxygen/html/search/enumvalues_1.js | 0 .../doxygen/html/search/enumvalues_10.html | 0 .../docs/doxygen/html/search/enumvalues_10.js | 0 .../doxygen/html/search/enumvalues_11.html | 0 .../docs/doxygen/html/search/enumvalues_11.js | 0 .../doxygen/html/search/enumvalues_12.html | 0 .../docs/doxygen/html/search/enumvalues_12.js | 0 .../doxygen/html/search/enumvalues_13.html | 0 .../docs/doxygen/html/search/enumvalues_13.js | 0 .../doxygen/html/search/enumvalues_14.html | 0 .../docs/doxygen/html/search/enumvalues_14.js | 0 .../doxygen/html/search/enumvalues_15.html | 0 .../docs/doxygen/html/search/enumvalues_15.js | 0 .../doxygen/html/search/enumvalues_2.html | 0 .../docs/doxygen/html/search/enumvalues_2.js | 0 .../doxygen/html/search/enumvalues_3.html | 0 .../docs/doxygen/html/search/enumvalues_3.js | 0 .../doxygen/html/search/enumvalues_4.html | 0 .../docs/doxygen/html/search/enumvalues_4.js | 0 .../doxygen/html/search/enumvalues_5.html | 0 .../docs/doxygen/html/search/enumvalues_5.js | 0 .../doxygen/html/search/enumvalues_6.html | 0 .../docs/doxygen/html/search/enumvalues_6.js | 0 .../doxygen/html/search/enumvalues_7.html | 0 .../docs/doxygen/html/search/enumvalues_7.js | 0 .../doxygen/html/search/enumvalues_8.html | 0 .../docs/doxygen/html/search/enumvalues_8.js | 0 .../doxygen/html/search/enumvalues_9.html | 0 .../docs/doxygen/html/search/enumvalues_9.js | 0 .../doxygen/html/search/enumvalues_a.html | 0 .../docs/doxygen/html/search/enumvalues_a.js | 0 .../doxygen/html/search/enumvalues_b.html | 0 .../docs/doxygen/html/search/enumvalues_b.js | 0 .../doxygen/html/search/enumvalues_c.html | 0 .../docs/doxygen/html/search/enumvalues_c.js | 0 .../doxygen/html/search/enumvalues_d.html | 0 .../docs/doxygen/html/search/enumvalues_d.js | 0 .../doxygen/html/search/enumvalues_e.html | 0 .../docs/doxygen/html/search/enumvalues_e.js | 0 .../doxygen/html/search/enumvalues_f.html | 0 .../docs/doxygen/html/search/enumvalues_f.js | 0 .../docs/doxygen/html/search/files_0.html | 0 .../docs/doxygen/html/search/files_0.js | 0 .../docs/doxygen/html/search/files_1.html | 0 .../docs/doxygen/html/search/files_1.js | 0 .../docs/doxygen/html/search/files_2.html | 0 .../docs/doxygen/html/search/files_2.js | 0 .../docs/doxygen/html/search/files_3.html | 0 .../docs/doxygen/html/search/files_3.js | 0 .../docs/doxygen/html/search/files_4.html | 0 .../docs/doxygen/html/search/files_4.js | 0 .../docs/doxygen/html/search/files_5.html | 0 .../docs/doxygen/html/search/files_5.js | 0 .../docs/doxygen/html/search/functions_0.html | 0 .../docs/doxygen/html/search/functions_0.js | 0 .../docs/doxygen/html/search/functions_1.html | 0 .../docs/doxygen/html/search/functions_1.js | 0 .../doxygen/html/search/functions_10.html | 0 .../docs/doxygen/html/search/functions_10.js | 0 .../doxygen/html/search/functions_11.html | 0 .../docs/doxygen/html/search/functions_11.js | 0 .../doxygen/html/search/functions_12.html | 0 .../docs/doxygen/html/search/functions_12.js | 0 .../doxygen/html/search/functions_13.html | 0 .../docs/doxygen/html/search/functions_13.js | 0 .../doxygen/html/search/functions_14.html | 0 .../docs/doxygen/html/search/functions_14.js | 0 .../doxygen/html/search/functions_15.html | 0 .../docs/doxygen/html/search/functions_15.js | 0 .../doxygen/html/search/functions_16.html | 0 .../docs/doxygen/html/search/functions_16.js | 0 .../doxygen/html/search/functions_17.html | 0 .../docs/doxygen/html/search/functions_17.js | 0 .../docs/doxygen/html/search/functions_2.html | 0 .../docs/doxygen/html/search/functions_2.js | 0 .../docs/doxygen/html/search/functions_3.html | 0 .../docs/doxygen/html/search/functions_3.js | 0 .../docs/doxygen/html/search/functions_4.html | 0 .../docs/doxygen/html/search/functions_4.js | 0 .../docs/doxygen/html/search/functions_5.html | 0 .../docs/doxygen/html/search/functions_5.js | 0 .../docs/doxygen/html/search/functions_6.html | 0 .../docs/doxygen/html/search/functions_6.js | 0 .../docs/doxygen/html/search/functions_7.html | 0 .../docs/doxygen/html/search/functions_7.js | 0 .../docs/doxygen/html/search/functions_8.html | 0 .../docs/doxygen/html/search/functions_8.js | 0 .../docs/doxygen/html/search/functions_9.html | 0 .../docs/doxygen/html/search/functions_9.js | 0 .../docs/doxygen/html/search/functions_a.html | 0 .../docs/doxygen/html/search/functions_a.js | 0 .../docs/doxygen/html/search/functions_b.html | 0 .../docs/doxygen/html/search/functions_b.js | 0 .../docs/doxygen/html/search/functions_c.html | 0 .../docs/doxygen/html/search/functions_c.js | 0 .../docs/doxygen/html/search/functions_d.html | 0 .../docs/doxygen/html/search/functions_d.js | 0 .../docs/doxygen/html/search/functions_e.html | 0 .../docs/doxygen/html/search/functions_e.js | 0 .../docs/doxygen/html/search/functions_f.html | 0 .../docs/doxygen/html/search/functions_f.js | 0 .../docs/doxygen/html/search/mag_sel.png | Bin .../doxygen/html/search/namespaces_0.html | 0 .../docs/doxygen/html/search/namespaces_0.js | 0 .../doxygen/html/search/namespaces_1.html | 0 .../docs/doxygen/html/search/namespaces_1.js | 0 .../docs/doxygen/html/search/nomatches.html | 0 .../docs/doxygen/html/search/pages_0.html | 0 .../docs/doxygen/html/search/pages_0.js | 0 .../docs/doxygen/html/search/pages_1.html | 0 .../docs/doxygen/html/search/pages_1.js | 0 .../docs/doxygen/html/search/pages_2.html | 0 .../docs/doxygen/html/search/pages_2.js | 0 .../docs/doxygen/html/search/related_0.html | 0 .../docs/doxygen/html/search/related_0.js | 0 .../docs/doxygen/html/search/search.css | 0 .../docs/doxygen/html/search/search.js | 0 .../docs/doxygen/html/search/search_l.png | Bin .../docs/doxygen/html/search/search_m.png | Bin .../docs/doxygen/html/search/search_r.png | Bin .../docs/doxygen/html/search/searchdata.js | 0 .../docs/doxygen/html/search/typedefs_0.html | 0 .../docs/doxygen/html/search/typedefs_0.js | 0 .../docs/doxygen/html/search/variables_0.html | 0 .../docs/doxygen/html/search/variables_0.js | 0 .../docs/doxygen/html/search/variables_1.html | 0 .../docs/doxygen/html/search/variables_1.js | 0 .../doxygen/html/search/variables_10.html | 0 .../docs/doxygen/html/search/variables_10.js | 0 .../doxygen/html/search/variables_11.html | 0 .../docs/doxygen/html/search/variables_11.js | 0 .../doxygen/html/search/variables_12.html | 0 .../docs/doxygen/html/search/variables_12.js | 0 .../doxygen/html/search/variables_13.html | 0 .../docs/doxygen/html/search/variables_13.js | 0 .../doxygen/html/search/variables_14.html | 0 .../docs/doxygen/html/search/variables_14.js | 0 .../doxygen/html/search/variables_15.html | 0 .../docs/doxygen/html/search/variables_15.js | 0 .../doxygen/html/search/variables_16.html | 0 .../docs/doxygen/html/search/variables_16.js | 0 .../docs/doxygen/html/search/variables_2.html | 0 .../docs/doxygen/html/search/variables_2.js | 0 .../docs/doxygen/html/search/variables_3.html | 0 .../docs/doxygen/html/search/variables_3.js | 0 .../docs/doxygen/html/search/variables_4.html | 0 .../docs/doxygen/html/search/variables_4.js | 0 .../docs/doxygen/html/search/variables_5.html | 0 .../docs/doxygen/html/search/variables_5.js | 0 .../docs/doxygen/html/search/variables_6.html | 0 .../docs/doxygen/html/search/variables_6.js | 0 .../docs/doxygen/html/search/variables_7.html | 0 .../docs/doxygen/html/search/variables_7.js | 0 .../docs/doxygen/html/search/variables_8.html | 0 .../docs/doxygen/html/search/variables_8.js | 0 .../docs/doxygen/html/search/variables_9.html | 0 .../docs/doxygen/html/search/variables_9.js | 0 .../docs/doxygen/html/search/variables_a.html | 0 .../docs/doxygen/html/search/variables_a.js | 0 .../docs/doxygen/html/search/variables_b.html | 0 .../docs/doxygen/html/search/variables_b.js | 0 .../docs/doxygen/html/search/variables_c.html | 0 .../docs/doxygen/html/search/variables_c.js | 0 .../docs/doxygen/html/search/variables_d.html | 0 .../docs/doxygen/html/search/variables_d.js | 0 .../docs/doxygen/html/search/variables_e.html | 0 .../docs/doxygen/html/search/variables_e.js | 0 .../docs/doxygen/html/search/variables_f.html | 0 .../docs/doxygen/html/search/variables_f.js | 0 .../docs/doxygen/html/splitbar.png | Bin .../html/structirparams__t-members.html | 0 .../docs/doxygen/html/structirparams__t.html | 0 .../html/structmatch__result__t-members.html | 0 .../doxygen/html/structmatch__result__t.html | 0 .../html/structstdAc_1_1state__t-members.html | 0 .../doxygen/html/structstdAc_1_1state__t.html | 0 .../docs/doxygen/html/sync_off.png | Bin .../docs/doxygen/html/sync_on.png | Bin .../docs/doxygen/html/tab_a.png | Bin .../docs/doxygen/html/tab_b.png | Bin .../docs/doxygen/html/tab_h.png | Bin .../docs/doxygen/html/tab_s.png | Bin .../docs/doxygen/html/tabs.css | 0 .../docs/doxygen/html/todo.html | 0 .../doxygen/html/unionmagiquest-members.html | 0 .../docs/doxygen/html/unionmagiquest.html | 0 .../docs/doxygen/html/zh-CN_8h.html | 0 .../docs/doxygen/html/zh-CN_8h_source.html | 0 .../docs/doxygen_index.md | 0 .../examples/BlynkIrRemote/BlynkIrRemote.ino | 392 +++++++++--------- .../examples/BlynkIrRemote/platformio.ini | 0 .../CommonAcControl/CommonAcControl.ino | 0 .../examples/CommonAcControl/platformio.ini | 0 .../ControlSamsungAC/ControlSamsungAC.ino | 0 .../examples/ControlSamsungAC/platformio.ini | 0 .../DumbIRRepeater/DumbIRRepeater.ino | 0 .../examples/DumbIRRepeater/platformio.ini | 0 .../examples/IRGCSendDemo/IRGCSendDemo.ino | 0 .../examples/IRGCSendDemo/platformio.ini | 0 .../examples/IRGCTCPServer/IRGCTCPServer.ino | 0 .../examples/IRGCTCPServer/platformio.ini | 0 .../examples/IRMQTTServer/IRMQTTServer.h | 0 .../examples/IRMQTTServer/IRMQTTServer.ino | 0 .../examples/IRMQTTServer/platformio.ini | 0 .../examples/IRServer/IRServer.ino | 0 .../examples/IRServer/platformio.ini | 0 .../examples/IRrecvDemo/IRrecvDemo.ino | 0 .../examples/IRrecvDemo/platformio.ini | 0 .../examples/IRrecvDump/IRrecvDump.ino | 0 .../examples/IRrecvDump/platformio.ini | 0 .../examples/IRrecvDumpV2/IRrecvDumpV2.ino | 0 .../examples/IRrecvDumpV2/platformio.ini | 0 .../examples/IRrecvDumpV3/BaseOTA.h | 0 .../examples/IRrecvDumpV3/IRrecvDumpV3.ino | 0 .../examples/IRrecvDumpV3/platformio.ini | 0 .../examples/IRsendDemo/IRsendDemo.ino | 0 .../examples/IRsendDemo/platformio.ini | 0 .../IRsendProntoDemo/IRsendProntoDemo.ino | 0 .../examples/IRsendProntoDemo/platformio.ini | 0 .../JVCPanasonicSendDemo.ino | 0 .../JVCPanasonicSendDemo/platformio.ini | 0 .../examples/LGACSend/LGACSend.ino | 0 .../examples/LGACSend/platformio.ini | 0 .../SmartIRRepeater/SmartIRRepeater.ino | 0 .../examples/SmartIRRepeater/platformio.ini | 0 .../examples/TurnOnArgoAC/TurnOnArgoAC.ino | 0 .../examples/TurnOnArgoAC/platformio.ini | 0 .../TurnOnDaikinAC/TurnOnDaikinAC.ino | 0 .../examples/TurnOnDaikinAC/platformio.ini | 0 .../TurnOnFujitsuAC/TurnOnFujitsuAC.ino | 0 .../examples/TurnOnFujitsuAC/platformio.ini | 0 .../examples/TurnOnGreeAC/TurnOnGreeAC.ino | 154 +++---- .../examples/TurnOnGreeAC/platformio.ini | 0 .../TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino | 0 .../TurnOnKelvinatorAC/platformio.ini | 0 .../TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino | 0 .../TurnOnMitsubishiAC/platformio.ini | 0 .../TurnOnMitsubishiHeavyAc.ino | 0 .../TurnOnMitsubishiHeavyAc/platformio.ini | 0 .../TurnOnPanasonicAC/TurnOnPanasonicAC.ino | 0 .../examples/TurnOnPanasonicAC/platformio.ini | 0 .../TurnOnToshibaAC/TurnOnToshibaAC.ino | 0 .../examples/TurnOnToshibaAC/platformio.ini | 0 .../TurnOnTrotecAC/TurnOnTrotecAC.ino | 0 .../examples/TurnOnTrotecAC/platformio.ini | 0 .../examples/Web-AC-control/README.md | 0 .../Web-AC-control/Web-AC-control.ino | 0 .../examples/Web-AC-control/platformio.ini | 0 .../examples/Web-AC-control/printscreen.png | Bin .../Web-AC-control/upload/favicon.ico | Bin .../Web-AC-control/upload/level_1_off.svg | 0 .../Web-AC-control/upload/level_1_on.svg | 0 .../Web-AC-control/upload/level_2_off.svg | 0 .../Web-AC-control/upload/level_2_on.svg | 0 .../Web-AC-control/upload/level_3_off.svg | 0 .../Web-AC-control/upload/level_3_on.svg | 0 .../Web-AC-control/upload/level_4_off.svg | 0 .../Web-AC-control/upload/level_4_on.svg | 0 .../examples/Web-AC-control/upload/ui.html | 0 .../examples/Web-AC-control/upload/ui.js | 0 .../keywords.txt | 0 .../library.json | 0 .../library.properties | 0 .../platformio.ini | 0 .../pylintrc | 0 .../src/CPPLINT.cfg | 0 .../src/IRac.cpp | 0 .../src/IRac.h | 0 .../src/IRrecv.cpp | 0 .../src/IRrecv.h | 0 .../src/IRremoteESP8266.h | 0 .../src/IRsend.cpp | 0 .../src/IRsend.h | 0 .../src/IRtext.cpp | 0 .../src/IRtext.h | 0 .../src/IRtimer.cpp | 0 .../src/IRtimer.h | 0 .../src/IRutils.cpp | 0 .../src/IRutils.h | 0 .../src/i18n.h | 0 .../src/ir_Airwell.cpp | 0 .../src/ir_Airwell.h | 0 .../src/ir_Aiwa.cpp | 0 .../src/ir_Amcor.cpp | 0 .../src/ir_Amcor.h | 0 .../src/ir_Argo.cpp | 0 .../src/ir_Argo.h | 0 .../src/ir_Carrier.cpp | 0 .../src/ir_Carrier.h | 0 .../src/ir_Coolix.cpp | 0 .../src/ir_Coolix.h | 0 .../src/ir_Corona.cpp | 0 .../src/ir_Corona.h | 0 .../src/ir_Daikin.cpp | 0 .../src/ir_Daikin.h | 0 .../src/ir_Delonghi.cpp | 0 .../src/ir_Delonghi.h | 0 .../src/ir_Denon.cpp | 0 .../src/ir_Dish.cpp | 0 .../src/ir_Doshisha.cpp | 0 .../src/ir_Electra.cpp | 0 .../src/ir_Electra.h | 0 .../src/ir_Epson.cpp | 0 .../src/ir_Fujitsu.cpp | 0 .../src/ir_Fujitsu.h | 0 .../src/ir_GICable.cpp | 0 .../src/ir_GlobalCache.cpp | 0 .../src/ir_Goodweather.cpp | 0 .../src/ir_Goodweather.h | 0 .../src/ir_Gree.cpp | 0 .../src/ir_Gree.h | 0 .../src/ir_Haier.cpp | 0 .../src/ir_Haier.h | 0 .../src/ir_Hitachi.cpp | 0 .../src/ir_Hitachi.h | 0 .../src/ir_Inax.cpp | 0 .../src/ir_JVC.cpp | 0 .../src/ir_Kelvinator.cpp | 0 .../src/ir_Kelvinator.h | 0 .../src/ir_LG.cpp | 0 .../src/ir_LG.h | 0 .../src/ir_Lasertag.cpp | 0 .../src/ir_Lego.cpp | 0 .../src/ir_Lutron.cpp | 0 .../src/ir_MWM.cpp | 0 .../src/ir_Magiquest.cpp | 0 .../src/ir_Magiquest.h | 0 .../src/ir_Midea.cpp | 0 .../src/ir_Midea.h | 0 .../src/ir_Mitsubishi.cpp | 0 .../src/ir_Mitsubishi.h | 0 .../src/ir_MitsubishiHeavy.cpp | 0 .../src/ir_MitsubishiHeavy.h | 0 .../src/ir_Multibrackets.cpp | 0 .../src/ir_NEC.cpp | 0 .../src/ir_NEC.h | 0 .../src/ir_Neoclima.cpp | 0 .../src/ir_Neoclima.h | 0 .../src/ir_Nikai.cpp | 0 .../src/ir_Panasonic.cpp | 0 .../src/ir_Panasonic.h | 0 .../src/ir_Pioneer.cpp | 0 .../src/ir_Pronto.cpp | 0 .../src/ir_RC5_RC6.cpp | 0 .../src/ir_RCMM.cpp | 0 .../src/ir_Samsung.cpp | 0 .../src/ir_Samsung.h | 0 .../src/ir_Sanyo.cpp | 0 .../src/ir_Sanyo.h | 0 .../src/ir_Sharp.cpp | 0 .../src/ir_Sharp.h | 0 .../src/ir_Sherwood.cpp | 0 .../src/ir_Sony.cpp | 0 .../src/ir_Symphony.cpp | 0 .../src/ir_Tcl.cpp | 0 .../src/ir_Tcl.h | 0 .../src/ir_Teco.cpp | 0 .../src/ir_Teco.h | 0 .../src/ir_Toshiba.cpp | 0 .../src/ir_Toshiba.h | 0 .../src/ir_Trotec.cpp | 0 .../src/ir_Trotec.h | 0 .../src/ir_Vestel.cpp | 0 .../src/ir_Vestel.h | 0 .../src/ir_Whirlpool.cpp | 0 .../src/ir_Whirlpool.h | 0 .../src/ir_Whynter.cpp | 0 .../src/ir_Zepeal.cpp | 0 .../src/locale/README.md | 0 .../src/locale/de-CH.h | 0 .../src/locale/de-DE.h | 0 .../src/locale/defaults.h | 0 .../src/locale/en-AU.h | 0 .../src/locale/en-IE.h | 0 .../src/locale/en-UK.h | 0 .../src/locale/en-US.h | 0 .../src/locale/es-ES.h | 0 .../src/locale/fr-FR.h | 0 .../src/locale/it-IT.h | 0 .../src/locale/zh-CN.h | 0 .../test/IRac_test.cpp | 0 .../test/IRrecv_test.cpp | 0 .../test/IRrecv_test.h | 0 .../test/IRsend_test.cpp | 0 .../test/IRsend_test.h | 0 .../test/IRutils_test.cpp | 0 .../test/Makefile | 0 .../test/ir_Airwell_test.cpp | 0 .../test/ir_Aiwa_test.cpp | 0 .../test/ir_Amcor_test.cpp | 0 .../test/ir_Argo_test.cpp | 0 .../test/ir_Carrier_test.cpp | 0 .../test/ir_Coolix_test.cpp | 0 .../test/ir_Corona_test.cpp | 0 .../test/ir_Daikin_test.cpp | 0 .../test/ir_Delonghi_test.cpp | 0 .../test/ir_Denon_test.cpp | 0 .../test/ir_Dish_test.cpp | 0 .../test/ir_Doshisha_test.cpp | 0 .../test/ir_Electra_test.cpp | 0 .../test/ir_Epson_test.cpp | 0 .../test/ir_Fujitsu_test.cpp | 0 .../test/ir_GICable_test.cpp | 0 .../test/ir_GlobalCache_test.cpp | 0 .../test/ir_Goodweather_test.cpp | 0 .../test/ir_Gree_test.cpp | 0 .../test/ir_Haier_test.cpp | 0 .../test/ir_Hitachi_test.cpp | 0 .../test/ir_Inax_test.cpp | 0 .../test/ir_JVC_test.cpp | 0 .../test/ir_Kelvinator_test.cpp | 0 .../test/ir_LG_test.cpp | 0 .../test/ir_Lasertag_test.cpp | 0 .../test/ir_Lego_test.cpp | 0 .../test/ir_Lutron_test.cpp | 0 .../test/ir_MWM_test.cpp | 0 .../test/ir_Magiquest_test.cpp | 0 .../test/ir_Midea_test.cpp | 0 .../test/ir_MitsubishiHeavy_test.cpp | 0 .../test/ir_Mitsubishi_test.cpp | 0 .../test/ir_Multibrackets_test.cpp | 0 .../test/ir_NEC_test.cpp | 0 .../test/ir_Neoclima_test.cpp | 0 .../test/ir_Nikai_test.cpp | 0 .../test/ir_Panasonic_test.cpp | 0 .../test/ir_Pioneer_test.cpp | 0 .../test/ir_Pronto_test.cpp | 0 .../test/ir_RC5_RC6_test.cpp | 0 .../test/ir_RCMM_test.cpp | 0 .../test/ir_Samsung_test.cpp | 0 .../test/ir_Sanyo_test.cpp | 0 .../test/ir_Sharp_test.cpp | 0 .../test/ir_Sherwood_test.cpp | 0 .../test/ir_Sony_test.cpp | 0 .../test/ir_Symphony_test.cpp | 0 .../test/ir_Tcl_test.cpp | 0 .../test/ir_Teco_test.cpp | 0 .../test/ir_Toshiba_test.cpp | 0 .../test/ir_Trotec_test.cpp | 0 .../test/ir_Vestel_test.cpp | 0 .../test/ir_Whirlpool_test.cpp | 0 .../test/ir_Whynter_test.cpp | 0 .../test/ir_Zepeal_test.cpp | 0 .../tools/Makefile | 0 .../tools/RawToGlobalCache.sh | 0 .../tools/auto_analyse_raw_data.py | 0 .../tools/auto_analyse_raw_data_test.py | 0 .../tools/gc_decode.cpp | 0 .../tools/generate_irtext_h.sh | 0 .../tools/mkkeywords | 0 .../tools/mode2_decode.cpp | 0 .../tools/raw_to_pronto_code.py | 0 .../tools/raw_to_pronto_code_test.py | 0 .../tools/scrape_supported_devices.py | 0 tasmota/CHANGELOG.md | 8 +- 1249 files changed, 275 insertions(+), 281 deletions(-) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/CPPLINT.cfg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/Doxyfile (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/LICENSE.txt (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/README.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/README_fr.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/ReleaseNotes.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/SupportedProtocols.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/README.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/README_fr.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/_config.yml (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRac_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRac_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRac_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRrecv_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRrecv_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRrecv_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRremoteESP8266_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRremoteESP8266_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRsend_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRsend_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRsend_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRtext_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRtext_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRtext_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRtimer_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRtimer_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRtimer_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRutils_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRutils_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/IRutils_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/README_8md.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/annotated.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/bc_s.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/bdwn.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRAmcorAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRAmcorAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRAmcorAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRAmcorAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRAmcorAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRArgoAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRArgoAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRArgoAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRArgoAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRArgoAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCarrierAc64-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCarrierAc64.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCarrierAc64__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCarrierAc64__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCarrierAc64__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoolixAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoolixAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoolixAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoolixAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoolixAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoronaAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoronaAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoronaAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoronaAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRCoronaAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin128-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin128.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin128__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin128__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin128__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin152-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin152.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin152__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin152__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin152__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin160-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin160.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin160__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin160__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin160__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin176-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin176.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin176__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin176__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin176__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin2-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin216-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin216.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin216__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin216__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin216__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin2__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin2__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin2__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin64-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin64.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin64__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin64__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikin64__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikinESP-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikinESP.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikinESP__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikinESP__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDaikinESP__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDelonghiAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDelonghiAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDelonghiAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDelonghiAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRDelonghiAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRElectraAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRElectraAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRElectraAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRElectraAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRElectraAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRFujitsuAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRFujitsuAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRFujitsuAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRFujitsuAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRFujitsuAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGoodweatherAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGoodweatherAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGoodweatherAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGoodweatherAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGoodweatherAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGreeAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGreeAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGreeAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGreeAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRGreeAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierACYRW02-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierACYRW02.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierACYRW02__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierACYRW02__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierACYRW02__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHaierAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc1-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc1__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc1__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc1__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc3-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344__inherit__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344__inherit__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc344__inherit__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc3__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc3__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc3__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424__inherit__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424__inherit__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc424__inherit__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRHitachiAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRKelvinatorAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRKelvinatorAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRKelvinatorAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRKelvinatorAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRKelvinatorAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRLgAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRLgAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRLgAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRLgAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRLgAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMideaAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMideaAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMideaAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMideaAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMideaAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi112-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi112.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi112__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi112__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi112__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi136-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi136.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi136__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi136__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishi136__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy152Ac-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy152Ac.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy88Ac-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy88Ac.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRNeoclimaAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRNeoclimaAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRPanasonicAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRPanasonicAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRPanasonicAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRPanasonicAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRPanasonicAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSamsungAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSamsungAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSamsungAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSamsungAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSharpAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSharpAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSharpAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSharpAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRSharpAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTcl112Ac-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTcl112Ac.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTcl112Ac__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTcl112Ac__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTcl112Ac__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTecoAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTecoAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTecoAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTecoAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTecoAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRToshibaAC-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRToshibaAC.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRToshibaAC__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRToshibaAC__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRToshibaAC__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTrotecESP-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTrotecESP.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTrotecESP__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTrotecESP__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRTrotecESP__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRVestelAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRVestelAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRVestelAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRVestelAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRVestelAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRWhirlpoolAc-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRWhirlpoolAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRac-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRac.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRac__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRac__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRac__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRrecv-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRrecv.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRrecv__coll__graph.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRrecv__coll__graph.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRrecv__coll__graph.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRsend-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRsend.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRtimer-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classIRtimer.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classTimerMs-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classTimerMs.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classdecode__results-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classdecode__results.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/classes.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/closed.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/de-CH_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/de-CH_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/de-DE_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/de-DE_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/defaults_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/defaults_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/deprecated.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/dir_49e56c817e5e54854c35e136979f97ca.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/dir_84fe998d1eb06414cc389ad334e77e63.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/doc.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/doxygen.css (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/doxygen.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/doxygen__index_8md.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/dynsections.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-AU_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-AU_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-IE_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-IE_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-UK_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-UK_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-US_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/en-US_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/es-ES_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/es-ES_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/files.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/folderclosed.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/folderopen.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/fr-FR_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/fr-FR_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_g.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_i.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_k.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_l.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_m.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_n.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_o.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_p.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_r.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_s.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_t.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_u.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_v.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_w.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_func_~.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_g.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_i.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_k.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_l.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_m.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_n.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_o.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_p.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_q.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_r.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_rela.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_s.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_t.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_u.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_v.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_i.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_l.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_m.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_n.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_o.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_p.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_q.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_r.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_s.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_t.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_u.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_v.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_w.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_vars_z.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_w.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_z.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/functions_~.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_enum.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_eval.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_func.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_g.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_i.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_j.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_k.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_l.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_m.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_n.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_p.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_r.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_s.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_t.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_type.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_u.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_v.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_vars.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_vars_i.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_vars_k.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_w.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_x.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_y.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/globals_z.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/graph_legend.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/graph_legend.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/graph_legend.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/hierarchy.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/i18n_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/i18n_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/index.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_0.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_0.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_0.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_1.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_1.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_1.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_10.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_10.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_10.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_11.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_11.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_11.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_12.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_12.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_12.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_13.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_13.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_13.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_14.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_14.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_14.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_15.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_15.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_15.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_16.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_16.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_16.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_17.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_17.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_17.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_18.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_18.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_18.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_19.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_19.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_19.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_2.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_2.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_2.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_20.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_20.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_20.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_21.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_21.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_21.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_22.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_22.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_22.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_23.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_23.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_23.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_24.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_24.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_24.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_25.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_25.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_25.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_26.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_26.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_26.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_27.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_27.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_27.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_28.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_28.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_28.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_29.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_29.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_29.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_3.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_3.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_3.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_30.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_30.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_30.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_31.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_31.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_31.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_32.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_32.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_32.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_33.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_33.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_33.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_34.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_34.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_34.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_35.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_35.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_35.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_36.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_36.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_36.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_37.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_37.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_37.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_38.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_38.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_38.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_39.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_39.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_39.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_4.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_4.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_4.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_40.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_40.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_40.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_41.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_41.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_41.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_42.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_42.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_42.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_43.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_43.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_43.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_44.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_44.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_44.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_45.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_45.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_45.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_46.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_46.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_46.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_47.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_47.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_47.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_48.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_48.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_48.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_49.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_49.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_49.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_5.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_5.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_5.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_50.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_50.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_50.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_51.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_51.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_51.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_6.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_6.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_6.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_7.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_7.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_7.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_8.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_8.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_8.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_9.map (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_9.md5 (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherit_graph_9.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/inherits.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Airwell_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Aiwa_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Amcor_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Amcor_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Amcor_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Argo_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Argo_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Argo_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Carrier_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Carrier_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Carrier_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Coolix_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Coolix_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Coolix_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Corona_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Corona_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Corona_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Daikin_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Daikin_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Daikin_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Delonghi_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Delonghi_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Delonghi_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Denon_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Dish_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Doshisha_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Electra_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Electra_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Electra_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Epson_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Fujitsu_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Fujitsu_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Fujitsu_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__GICable_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__GlobalCache_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Goodweather_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Goodweather_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Goodweather_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Gree_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Gree_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Gree_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Haier_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Haier_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Haier_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Hitachi_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Hitachi_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Hitachi_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Inax_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__JVC_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Kelvinator_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Kelvinator_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Kelvinator_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__LG_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__LG_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__LG_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Lasertag_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Lego_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Lutron_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__MWM_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Magiquest_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Magiquest_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Magiquest_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Midea_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Midea_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Midea_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__MitsubishiHeavy_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__MitsubishiHeavy_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__MitsubishiHeavy_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Mitsubishi_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Mitsubishi_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Mitsubishi_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Multibrackets_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__NEC_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__NEC_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__NEC_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Neoclima_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Neoclima_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Neoclima_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Nikai_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Panasonic_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Panasonic_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Panasonic_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Pioneer_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Pronto_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__RC5__RC6_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__RCMM_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Samsung_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Samsung_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Samsung_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Sanyo_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Sharp_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Sharp_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Sharp_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Sherwood_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Sony_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Symphony_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Tcl_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Tcl_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Tcl_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Teco_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Teco_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Teco_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Toshiba_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Toshiba_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Toshiba_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Trotec_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Trotec_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Trotec_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Vestel_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Vestel_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Vestel_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Whirlpool_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Whirlpool_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Whirlpool_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Whynter_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/ir__Zepeal_8cpp.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/it-IT_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/it-IT_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/jquery.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/md_src_locale_README.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/menu.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/menudata.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/namespaceIRAcUtils.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/namespaceirutils.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/namespacemembers.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/namespacemembers_enum.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/namespacemembers_func.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/namespaces.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/namespacestdAc.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/nav_f.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/nav_g.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/nav_h.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/open.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/pages.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_10.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_10.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_11.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_11.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_12.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_12.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_13.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_13.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_14.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_14.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_15.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_15.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_16.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_16.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_17.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_17.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_18.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_18.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_19.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_19.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_1a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_1a.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_1b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_1b.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_3.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_4.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_4.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_5.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_5.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_6.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_6.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_7.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_7.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_8.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_8.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_9.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_9.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_a.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_b.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_c.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_d.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_e.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/all_f.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_3.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_4.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/classes_4.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/close.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_3.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_4.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_4.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_5.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_5.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_6.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_6.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_7.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_7.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_8.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enums_8.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_10.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_10.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_11.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_11.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_12.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_12.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_13.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_13.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_14.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_14.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_15.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_15.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_3.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_4.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_4.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_5.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_5.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_6.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_6.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_7.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_7.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_8.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_8.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_9.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_9.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_a.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_b.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_c.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_d.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_e.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/enumvalues_f.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_3.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_4.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_4.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_5.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/files_5.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_10.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_10.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_11.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_11.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_12.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_12.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_13.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_13.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_14.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_14.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_15.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_15.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_16.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_16.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_17.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_17.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_3.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_4.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_4.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_5.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_5.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_6.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_6.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_7.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_7.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_8.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_8.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_9.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_9.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_a.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_b.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_c.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_d.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_e.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/functions_f.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/mag_sel.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/namespaces_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/namespaces_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/namespaces_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/namespaces_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/nomatches.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/pages_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/pages_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/pages_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/pages_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/pages_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/pages_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/related_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/related_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/search.css (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/search.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/search_l.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/search_m.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/search_r.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/searchdata.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/typedefs_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/typedefs_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_0.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_0.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_1.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_1.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_10.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_10.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_11.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_11.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_12.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_12.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_13.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_13.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_14.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_14.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_15.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_15.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_16.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_16.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_2.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_2.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_3.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_3.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_4.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_4.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_5.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_5.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_6.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_6.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_7.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_7.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_8.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_8.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_9.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_9.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_a.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_a.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_b.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_b.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_c.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_c.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_d.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_d.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_e.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_e.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_f.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/search/variables_f.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/splitbar.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/structirparams__t-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/structirparams__t.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/structmatch__result__t-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/structmatch__result__t.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/structstdAc_1_1state__t-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/structstdAc_1_1state__t.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/sync_off.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/sync_on.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/tab_a.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/tab_b.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/tab_h.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/tab_s.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/tabs.css (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/todo.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/unionmagiquest-members.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/unionmagiquest.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/zh-CN_8h.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen/html/zh-CN_8h_source.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/docs/doxygen_index.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/BlynkIrRemote/BlynkIrRemote.ino (97%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/BlynkIrRemote/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/CommonAcControl/CommonAcControl.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/CommonAcControl/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/ControlSamsungAC/ControlSamsungAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/ControlSamsungAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/DumbIRRepeater/DumbIRRepeater.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/DumbIRRepeater/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRGCSendDemo/IRGCSendDemo.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRGCSendDemo/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRGCTCPServer/IRGCTCPServer.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRGCTCPServer/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRMQTTServer/IRMQTTServer.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRMQTTServer/IRMQTTServer.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRMQTTServer/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRServer/IRServer.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRServer/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDemo/IRrecvDemo.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDemo/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDump/IRrecvDump.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDump/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDumpV2/IRrecvDumpV2.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDumpV2/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDumpV3/BaseOTA.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDumpV3/IRrecvDumpV3.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRrecvDumpV3/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRsendDemo/IRsendDemo.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRsendDemo/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRsendProntoDemo/IRsendProntoDemo.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/IRsendProntoDemo/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/JVCPanasonicSendDemo/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/LGACSend/LGACSend.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/LGACSend/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/SmartIRRepeater/SmartIRRepeater.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/SmartIRRepeater/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnArgoAC/TurnOnArgoAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnArgoAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnDaikinAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnFujitsuAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnGreeAC/TurnOnGreeAC.ino (97%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnGreeAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnKelvinatorAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnMitsubishiAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnMitsubishiHeavyAc/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnPanasonicAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnToshibaAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/TurnOnTrotecAC/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/README.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/Web-AC-control.ino (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/printscreen.png (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/favicon.ico (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_1_off.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_1_on.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_2_off.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_2_on.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_3_off.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_3_on.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_4_off.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/level_4_on.svg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/ui.html (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/examples/Web-AC-control/upload/ui.js (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/keywords.txt (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/library.json (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/library.properties (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/platformio.ini (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/pylintrc (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/CPPLINT.cfg (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRac.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRac.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRrecv.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRrecv.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRremoteESP8266.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRsend.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRsend.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRtext.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRtext.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRtimer.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRtimer.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRutils.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/IRutils.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/i18n.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Airwell.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Airwell.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Aiwa.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Amcor.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Amcor.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Argo.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Argo.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Carrier.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Carrier.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Coolix.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Coolix.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Corona.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Corona.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Daikin.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Daikin.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Delonghi.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Delonghi.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Denon.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Dish.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Doshisha.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Electra.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Electra.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Epson.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Fujitsu.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Fujitsu.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_GICable.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_GlobalCache.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Goodweather.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Goodweather.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Gree.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Gree.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Haier.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Haier.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Hitachi.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Hitachi.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Inax.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_JVC.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Kelvinator.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Kelvinator.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_LG.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_LG.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Lasertag.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Lego.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Lutron.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_MWM.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Magiquest.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Magiquest.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Midea.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Midea.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Mitsubishi.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Mitsubishi.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_MitsubishiHeavy.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_MitsubishiHeavy.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Multibrackets.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_NEC.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_NEC.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Neoclima.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Neoclima.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Nikai.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Panasonic.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Panasonic.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Pioneer.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Pronto.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_RC5_RC6.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_RCMM.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Samsung.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Samsung.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Sanyo.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Sanyo.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Sharp.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Sharp.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Sherwood.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Sony.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Symphony.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Tcl.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Tcl.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Teco.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Teco.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Toshiba.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Toshiba.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Trotec.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Trotec.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Vestel.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Vestel.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Whirlpool.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Whirlpool.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Whynter.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/ir_Zepeal.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/README.md (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/de-CH.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/de-DE.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/defaults.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/en-AU.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/en-IE.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/en-UK.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/en-US.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/es-ES.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/fr-FR.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/it-IT.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/src/locale/zh-CN.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/IRac_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/IRrecv_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/IRrecv_test.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/IRsend_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/IRsend_test.h (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/IRutils_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/Makefile (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Airwell_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Aiwa_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Amcor_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Argo_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Carrier_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Coolix_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Corona_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Daikin_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Delonghi_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Denon_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Dish_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Doshisha_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Electra_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Epson_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Fujitsu_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_GICable_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_GlobalCache_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Goodweather_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Gree_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Haier_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Hitachi_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Inax_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_JVC_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Kelvinator_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_LG_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Lasertag_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Lego_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Lutron_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_MWM_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Magiquest_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Midea_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_MitsubishiHeavy_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Mitsubishi_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Multibrackets_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_NEC_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Neoclima_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Nikai_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Panasonic_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Pioneer_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Pronto_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_RC5_RC6_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_RCMM_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Samsung_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Sanyo_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Sharp_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Sherwood_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Sony_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Symphony_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Tcl_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Teco_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Toshiba_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Trotec_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Vestel_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Whirlpool_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Whynter_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/test/ir_Zepeal_test.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/Makefile (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/RawToGlobalCache.sh (100%) mode change 100755 => 100644 rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/auto_analyse_raw_data.py (100%) mode change 100755 => 100644 rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/auto_analyse_raw_data_test.py (100%) mode change 100755 => 100644 rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/gc_decode.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/generate_irtext_h.sh (100%) mode change 100755 => 100644 rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/mkkeywords (100%) mode change 100755 => 100644 rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/mode2_decode.cpp (100%) rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/raw_to_pronto_code.py (100%) mode change 100755 => 100644 rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/raw_to_pronto_code_test.py (100%) mode change 100755 => 100644 rename lib/{IRremoteESP8266-2.7.8 => IRremoteESP8266-2.7.8.10}/tools/scrape_supported_devices.py (100%) mode change 100755 => 100644 diff --git a/RELEASENOTES.md b/RELEASENOTES.md index bc9abff0c..565f9fc53 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -57,7 +57,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Remove Arduino ESP8266 Core support for versions before 2.7.1 - Change to limited support of Arduino IDE as an increasing amount of features cannot be compiled with Arduino IDE -- Change IRremoteESP8266 library from v2.7.6 to v2.7.8 +- Change IRRemoteESP8266 library from v2.7.6 to v2.7.8.10, fixing Samsung and Pioneer protocols (#8938) - Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519) - Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` - Change Energy JSON ExportActive field from ``"ExportActive":[33.736,11.717,16.978]`` to ``"ExportActive":33.736,"ExportTariff":[11.717,16.978]`` diff --git a/lib/IRremoteESP8266-2.7.8/CPPLINT.cfg b/lib/IRremoteESP8266-2.7.8.10/CPPLINT.cfg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/CPPLINT.cfg rename to lib/IRremoteESP8266-2.7.8.10/CPPLINT.cfg diff --git a/lib/IRremoteESP8266-2.7.8/Doxyfile b/lib/IRremoteESP8266-2.7.8.10/Doxyfile similarity index 100% rename from lib/IRremoteESP8266-2.7.8/Doxyfile rename to lib/IRremoteESP8266-2.7.8.10/Doxyfile diff --git a/lib/IRremoteESP8266-2.7.8/LICENSE.txt b/lib/IRremoteESP8266-2.7.8.10/LICENSE.txt similarity index 100% rename from lib/IRremoteESP8266-2.7.8/LICENSE.txt rename to lib/IRremoteESP8266-2.7.8.10/LICENSE.txt diff --git a/lib/IRremoteESP8266-2.7.8/README.md b/lib/IRremoteESP8266-2.7.8.10/README.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/README.md rename to lib/IRremoteESP8266-2.7.8.10/README.md diff --git a/lib/IRremoteESP8266-2.7.8/README_fr.md b/lib/IRremoteESP8266-2.7.8.10/README_fr.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/README_fr.md rename to lib/IRremoteESP8266-2.7.8.10/README_fr.md diff --git a/lib/IRremoteESP8266-2.7.8/ReleaseNotes.md b/lib/IRremoteESP8266-2.7.8.10/ReleaseNotes.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/ReleaseNotes.md rename to lib/IRremoteESP8266-2.7.8.10/ReleaseNotes.md diff --git a/lib/IRremoteESP8266-2.7.8/SupportedProtocols.md b/lib/IRremoteESP8266-2.7.8.10/SupportedProtocols.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/SupportedProtocols.md rename to lib/IRremoteESP8266-2.7.8.10/SupportedProtocols.md diff --git a/lib/IRremoteESP8266-2.7.8/docs/README.md b/lib/IRremoteESP8266-2.7.8.10/docs/README.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/README.md rename to lib/IRremoteESP8266-2.7.8.10/docs/README.md diff --git a/lib/IRremoteESP8266-2.7.8/docs/README_fr.md b/lib/IRremoteESP8266-2.7.8.10/docs/README_fr.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/README_fr.md rename to lib/IRremoteESP8266-2.7.8.10/docs/README_fr.md diff --git a/lib/IRremoteESP8266-2.7.8/docs/_config.yml b/lib/IRremoteESP8266-2.7.8.10/docs/_config.yml similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/_config.yml rename to lib/IRremoteESP8266-2.7.8.10/docs/_config.yml diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRac_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRac_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRac_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRac_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRac_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRac_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRac_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRac_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRac_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRac_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRac_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRac_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRrecv_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRrecv_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRrecv_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRrecv_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRrecv_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRrecv_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRrecv_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRrecv_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRrecv_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRrecv_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRrecv_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRrecv_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRremoteESP8266_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRremoteESP8266_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRremoteESP8266_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRremoteESP8266_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRremoteESP8266_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRremoteESP8266_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRremoteESP8266_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRremoteESP8266_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRsend_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRsend_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRsend_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRsend_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRsend_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRsend_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRsend_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRsend_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRsend_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRsend_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRsend_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRsend_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtext_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtext_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtext_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtext_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtext_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtext_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtext_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtext_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtext_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtext_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtext_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtext_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtimer_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtimer_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtimer_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtimer_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtimer_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtimer_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtimer_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtimer_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtimer_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtimer_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRtimer_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRtimer_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRutils_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRutils_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRutils_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRutils_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRutils_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRutils_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRutils_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRutils_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRutils_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRutils_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/IRutils_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/IRutils_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/README_8md.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/README_8md.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/README_8md.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/README_8md.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/annotated.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/annotated.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/annotated.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/annotated.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/bc_s.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/bc_s.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/bc_s.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/bc_s.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/bdwn.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/bdwn.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/bdwn.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/bdwn.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRAmcorAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRAmcorAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRArgoAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRArgoAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCarrierAc64__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCarrierAc64__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoolixAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoolixAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRCoronaAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRCoronaAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin128__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin128__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin152__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin152__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin160__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin160__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin176__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin176__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin216__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin216__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin2__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin2__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikin64__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikin64__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDaikinESP__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDaikinESP__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRDelonghiAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRDelonghiAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRElectraAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRElectraAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRFujitsuAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRFujitsuAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGoodweatherAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGoodweatherAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRGreeAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRGreeAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierACYRW02__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierACYRW02__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHaierAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHaierAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc1__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc1__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__inherit__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__inherit__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__inherit__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__inherit__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__inherit__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__inherit__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__inherit__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__inherit__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__inherit__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__inherit__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc344__inherit__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc344__inherit__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc3__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc3__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__inherit__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__inherit__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__inherit__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__inherit__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__inherit__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__inherit__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__inherit__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__inherit__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__inherit__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__inherit__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc424__inherit__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc424__inherit__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRHitachiAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRHitachiAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRKelvinatorAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRKelvinatorAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRLgAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRLgAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMideaAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMideaAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi112__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi112__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishi136__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishi136__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy152Ac__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRMitsubishiHeavy88Ac__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRNeoclimaAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRPanasonicAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRPanasonicAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSamsungAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSamsungAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRSharpAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRSharpAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTcl112Ac__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTcl112Ac__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTecoAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTecoAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRToshibaAC__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRToshibaAC__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRTrotecESP__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRTrotecESP__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRVestelAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRVestelAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRWhirlpoolAc__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRac__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRac__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv__coll__graph.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv__coll__graph.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv__coll__graph.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv__coll__graph.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv__coll__graph.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv__coll__graph.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv__coll__graph.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv__coll__graph.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv__coll__graph.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv__coll__graph.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRrecv__coll__graph.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRrecv__coll__graph.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRsend-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRsend-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRsend-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRsend-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRsend.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRsend.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRsend.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRsend.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRtimer-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRtimer-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRtimer-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRtimer-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRtimer.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRtimer.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classIRtimer.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classIRtimer.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classTimerMs-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classTimerMs-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classTimerMs-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classTimerMs-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classTimerMs.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classTimerMs.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classTimerMs.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classTimerMs.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classdecode__results-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classdecode__results-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classdecode__results-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classdecode__results-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classdecode__results.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classdecode__results.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classdecode__results.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classdecode__results.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classes.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classes.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/classes.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/classes.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/closed.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/closed.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/closed.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/closed.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-CH_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-CH_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-CH_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-CH_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-CH_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-CH_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-CH_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-CH_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-DE_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-DE_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-DE_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-DE_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-DE_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-DE_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/de-DE_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/de-DE_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/defaults_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/defaults_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/defaults_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/defaults_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/defaults_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/defaults_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/defaults_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/defaults_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/deprecated.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/deprecated.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/deprecated.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/deprecated.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dir_49e56c817e5e54854c35e136979f97ca.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dir_49e56c817e5e54854c35e136979f97ca.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dir_49e56c817e5e54854c35e136979f97ca.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dir_49e56c817e5e54854c35e136979f97ca.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dir_68267d1309a1af8e8297ef4c3efbcdba.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dir_84fe998d1eb06414cc389ad334e77e63.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dir_84fe998d1eb06414cc389ad334e77e63.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dir_84fe998d1eb06414cc389ad334e77e63.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dir_84fe998d1eb06414cc389ad334e77e63.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doc.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doc.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doc.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doc.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doxygen.css b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doxygen.css similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doxygen.css rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doxygen.css diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doxygen.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doxygen.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doxygen.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doxygen.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doxygen__index_8md.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doxygen__index_8md.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/doxygen__index_8md.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/doxygen__index_8md.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dynsections.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dynsections.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/dynsections.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/dynsections.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-AU_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-AU_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-AU_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-AU_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-AU_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-AU_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-AU_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-AU_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-IE_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-IE_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-IE_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-IE_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-IE_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-IE_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-IE_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-IE_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-UK_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-UK_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-UK_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-UK_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-UK_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-UK_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-UK_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-UK_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-US_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-US_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-US_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-US_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-US_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-US_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/en-US_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/en-US_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/es-ES_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/es-ES_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/es-ES_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/es-ES_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/es-ES_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/es-ES_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/es-ES_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/es-ES_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/files.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/files.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/files.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/files.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/folderclosed.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/folderclosed.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/folderclosed.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/folderclosed.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/folderopen.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/folderopen.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/folderopen.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/folderopen.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/fr-FR_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/fr-FR_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/fr-FR_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/fr-FR_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/fr-FR_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/fr-FR_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/fr-FR_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/fr-FR_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_g.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_g.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_g.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_g.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_i.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_i.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_i.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_i.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_k.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_k.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_k.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_k.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_l.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_l.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_l.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_l.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_m.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_m.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_m.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_m.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_n.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_n.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_n.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_n.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_o.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_o.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_o.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_o.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_p.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_p.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_p.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_p.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_r.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_r.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_r.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_r.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_s.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_s.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_s.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_s.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_t.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_t.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_t.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_t.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_u.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_u.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_u.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_u.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_v.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_v.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_v.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_v.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_w.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_w.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_w.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_w.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_~.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_~.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_func_~.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_func_~.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_g.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_g.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_g.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_g.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_i.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_i.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_i.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_i.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_k.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_k.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_k.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_k.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_l.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_l.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_l.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_l.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_m.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_m.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_m.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_m.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_n.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_n.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_n.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_n.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_o.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_o.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_o.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_o.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_p.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_p.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_p.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_p.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_q.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_q.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_q.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_q.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_r.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_r.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_r.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_r.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_rela.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_rela.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_rela.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_rela.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_s.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_s.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_s.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_s.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_t.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_t.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_t.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_t.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_u.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_u.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_u.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_u.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_v.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_v.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_v.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_v.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_i.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_i.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_i.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_i.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_l.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_l.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_l.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_l.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_m.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_m.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_m.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_m.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_n.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_n.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_n.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_n.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_o.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_o.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_o.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_o.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_p.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_p.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_p.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_p.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_q.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_q.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_q.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_q.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_r.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_r.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_r.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_r.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_s.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_s.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_s.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_s.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_t.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_t.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_t.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_t.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_u.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_u.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_u.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_u.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_v.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_v.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_v.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_v.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_w.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_w.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_w.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_w.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_z.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_z.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_vars_z.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_vars_z.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_w.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_w.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_w.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_w.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_z.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_z.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_z.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_z.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_~.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_~.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/functions_~.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/functions_~.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_enum.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_enum.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_enum.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_enum.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_eval.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_eval.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_eval.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_eval.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_func.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_func.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_func.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_func.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_g.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_g.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_g.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_g.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_i.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_i.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_i.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_i.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_j.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_j.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_j.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_j.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_k.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_k.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_k.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_k.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_l.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_l.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_l.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_l.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_m.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_m.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_m.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_m.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_n.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_n.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_n.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_n.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_p.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_p.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_p.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_p.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_r.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_r.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_r.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_r.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_s.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_s.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_s.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_s.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_t.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_t.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_t.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_t.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_type.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_type.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_type.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_type.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_u.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_u.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_u.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_u.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_v.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_v.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_v.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_v.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_vars.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_vars.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_vars.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_vars.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_vars_i.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_vars_i.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_vars_i.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_vars_i.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_vars_k.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_vars_k.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_vars_k.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_vars_k.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_w.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_w.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_w.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_w.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_x.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_x.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_x.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_x.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_y.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_y.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_y.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_y.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_z.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_z.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/globals_z.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/globals_z.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/graph_legend.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/graph_legend.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/graph_legend.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/graph_legend.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/graph_legend.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/graph_legend.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/graph_legend.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/graph_legend.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/graph_legend.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/graph_legend.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/graph_legend.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/graph_legend.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/hierarchy.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/hierarchy.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/hierarchy.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/hierarchy.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/i18n_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/i18n_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/i18n_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/i18n_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/i18n_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/i18n_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/i18n_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/i18n_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/index.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/index.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/index.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/index.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_0.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_0.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_0.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_0.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_0.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_0.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_0.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_0.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_0.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_0.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_0.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_0.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_1.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_1.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_1.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_1.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_1.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_1.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_1.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_1.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_1.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_1.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_1.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_1.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_10.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_10.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_10.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_10.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_10.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_10.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_10.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_10.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_10.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_10.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_10.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_10.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_11.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_11.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_11.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_11.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_11.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_11.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_11.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_11.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_11.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_11.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_11.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_11.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_12.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_12.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_12.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_12.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_12.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_12.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_12.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_12.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_12.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_12.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_12.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_12.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_13.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_13.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_13.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_13.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_13.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_13.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_13.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_13.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_13.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_13.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_13.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_13.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_14.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_14.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_14.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_14.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_14.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_14.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_14.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_14.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_14.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_14.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_14.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_14.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_15.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_15.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_15.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_15.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_15.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_15.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_15.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_15.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_15.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_15.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_15.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_15.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_16.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_16.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_16.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_16.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_16.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_16.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_16.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_16.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_16.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_16.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_16.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_16.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_17.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_17.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_17.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_17.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_17.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_17.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_17.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_17.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_17.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_17.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_17.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_17.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_18.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_18.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_18.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_18.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_18.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_18.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_18.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_18.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_18.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_18.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_18.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_18.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_19.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_19.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_19.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_19.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_19.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_19.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_19.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_19.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_19.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_19.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_19.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_19.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_2.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_2.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_2.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_2.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_2.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_2.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_2.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_2.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_2.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_2.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_2.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_2.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_20.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_20.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_20.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_20.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_20.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_20.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_20.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_20.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_20.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_20.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_20.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_20.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_21.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_21.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_21.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_21.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_21.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_21.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_21.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_21.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_21.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_21.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_21.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_21.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_22.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_22.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_22.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_22.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_22.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_22.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_22.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_22.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_22.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_22.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_22.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_22.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_23.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_23.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_23.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_23.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_23.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_23.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_23.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_23.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_23.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_23.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_23.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_23.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_24.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_24.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_24.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_24.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_24.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_24.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_24.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_24.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_24.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_24.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_24.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_24.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_25.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_25.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_25.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_25.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_25.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_25.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_25.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_25.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_25.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_25.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_25.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_25.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_26.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_26.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_26.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_26.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_26.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_26.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_26.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_26.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_26.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_26.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_26.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_26.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_27.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_27.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_27.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_27.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_27.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_27.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_27.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_27.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_27.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_27.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_27.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_27.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_28.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_28.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_28.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_28.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_28.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_28.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_28.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_28.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_28.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_28.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_28.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_28.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_29.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_29.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_29.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_29.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_29.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_29.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_29.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_29.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_29.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_29.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_29.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_29.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_3.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_3.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_3.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_3.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_3.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_3.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_3.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_3.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_3.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_3.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_3.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_3.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_30.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_30.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_30.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_30.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_30.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_30.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_30.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_30.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_30.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_30.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_30.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_30.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_31.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_31.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_31.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_31.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_31.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_31.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_31.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_31.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_31.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_31.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_31.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_31.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_32.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_32.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_32.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_32.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_32.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_32.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_32.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_32.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_32.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_32.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_32.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_32.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_33.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_33.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_33.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_33.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_33.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_33.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_33.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_33.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_33.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_33.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_33.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_33.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_34.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_34.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_34.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_34.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_34.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_34.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_34.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_34.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_34.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_34.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_34.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_34.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_35.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_35.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_35.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_35.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_35.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_35.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_35.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_35.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_35.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_35.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_35.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_35.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_36.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_36.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_36.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_36.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_36.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_36.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_36.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_36.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_36.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_36.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_36.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_36.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_37.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_37.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_37.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_37.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_37.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_37.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_37.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_37.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_37.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_37.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_37.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_37.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_38.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_38.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_38.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_38.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_38.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_38.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_38.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_38.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_38.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_38.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_38.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_38.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_39.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_39.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_39.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_39.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_39.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_39.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_39.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_39.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_39.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_39.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_39.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_39.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_4.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_4.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_4.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_4.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_4.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_4.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_4.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_4.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_4.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_4.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_4.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_4.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_40.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_40.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_40.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_40.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_40.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_40.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_40.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_40.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_40.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_40.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_40.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_40.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_41.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_41.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_41.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_41.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_41.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_41.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_41.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_41.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_41.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_41.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_41.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_41.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_42.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_42.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_42.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_42.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_42.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_42.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_42.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_42.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_42.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_42.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_42.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_42.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_43.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_43.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_43.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_43.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_43.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_43.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_43.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_43.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_43.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_43.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_43.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_43.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_44.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_44.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_44.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_44.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_44.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_44.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_44.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_44.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_44.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_44.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_44.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_44.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_45.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_45.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_45.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_45.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_45.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_45.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_45.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_45.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_45.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_45.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_45.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_45.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_46.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_46.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_46.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_46.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_46.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_46.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_46.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_46.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_46.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_46.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_46.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_46.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_47.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_47.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_47.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_47.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_47.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_47.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_47.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_47.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_47.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_47.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_47.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_47.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_48.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_48.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_48.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_48.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_48.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_48.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_48.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_48.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_48.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_48.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_48.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_48.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_49.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_49.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_49.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_49.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_49.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_49.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_49.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_49.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_49.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_49.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_49.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_49.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_5.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_5.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_5.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_5.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_5.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_5.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_5.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_5.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_5.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_5.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_5.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_5.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_50.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_50.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_50.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_50.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_50.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_50.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_50.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_50.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_50.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_50.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_50.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_50.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_51.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_51.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_51.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_51.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_51.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_51.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_51.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_51.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_51.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_51.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_51.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_51.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_6.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_6.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_6.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_6.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_6.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_6.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_6.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_6.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_6.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_6.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_6.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_6.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_7.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_7.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_7.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_7.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_7.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_7.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_7.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_7.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_7.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_7.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_7.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_7.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_8.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_8.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_8.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_8.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_8.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_8.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_8.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_8.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_8.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_8.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_8.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_8.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_9.map b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_9.map similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_9.map rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_9.map diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_9.md5 b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_9.md5 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_9.md5 rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_9.md5 diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_9.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_9.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherit_graph_9.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherit_graph_9.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherits.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherits.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/inherits.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/inherits.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Airwell_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Airwell_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Airwell_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Airwell_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Aiwa_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Aiwa_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Aiwa_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Aiwa_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Amcor_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Amcor_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Amcor_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Amcor_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Amcor_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Amcor_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Amcor_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Amcor_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Amcor_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Amcor_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Amcor_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Amcor_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Argo_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Argo_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Argo_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Argo_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Argo_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Argo_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Argo_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Argo_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Argo_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Argo_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Argo_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Argo_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Carrier_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Carrier_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Carrier_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Carrier_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Carrier_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Carrier_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Carrier_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Carrier_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Carrier_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Carrier_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Carrier_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Carrier_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Coolix_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Coolix_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Coolix_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Coolix_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Coolix_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Coolix_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Coolix_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Coolix_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Coolix_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Coolix_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Coolix_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Coolix_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Corona_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Corona_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Corona_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Corona_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Corona_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Corona_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Corona_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Corona_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Corona_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Corona_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Corona_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Corona_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Daikin_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Daikin_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Daikin_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Daikin_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Daikin_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Daikin_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Daikin_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Daikin_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Daikin_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Daikin_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Daikin_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Daikin_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Delonghi_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Delonghi_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Delonghi_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Delonghi_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Delonghi_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Delonghi_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Delonghi_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Delonghi_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Delonghi_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Delonghi_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Delonghi_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Delonghi_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Denon_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Denon_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Denon_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Denon_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Dish_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Dish_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Dish_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Dish_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Doshisha_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Doshisha_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Doshisha_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Doshisha_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Electra_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Electra_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Electra_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Electra_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Electra_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Electra_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Electra_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Electra_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Electra_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Electra_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Electra_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Electra_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Epson_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Epson_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Epson_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Epson_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Fujitsu_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Fujitsu_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Fujitsu_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Fujitsu_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Fujitsu_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Fujitsu_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Fujitsu_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Fujitsu_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Fujitsu_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Fujitsu_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Fujitsu_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Fujitsu_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__GICable_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__GICable_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__GICable_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__GICable_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__GlobalCache_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__GlobalCache_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__GlobalCache_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__GlobalCache_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Goodweather_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Goodweather_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Goodweather_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Goodweather_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Goodweather_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Goodweather_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Goodweather_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Goodweather_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Goodweather_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Goodweather_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Goodweather_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Goodweather_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Gree_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Gree_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Gree_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Gree_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Gree_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Gree_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Gree_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Gree_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Gree_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Gree_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Gree_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Gree_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Haier_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Haier_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Haier_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Haier_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Haier_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Haier_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Haier_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Haier_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Haier_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Haier_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Haier_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Haier_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Hitachi_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Hitachi_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Hitachi_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Hitachi_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Hitachi_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Hitachi_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Hitachi_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Hitachi_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Hitachi_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Hitachi_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Hitachi_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Hitachi_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Inax_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Inax_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Inax_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Inax_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__JVC_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__JVC_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__JVC_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__JVC_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Kelvinator_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Kelvinator_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Kelvinator_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Kelvinator_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Kelvinator_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Kelvinator_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Kelvinator_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Kelvinator_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Kelvinator_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Kelvinator_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Kelvinator_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Kelvinator_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__LG_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__LG_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__LG_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__LG_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__LG_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__LG_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__LG_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__LG_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__LG_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__LG_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__LG_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__LG_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Lasertag_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Lasertag_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Lasertag_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Lasertag_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Lego_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Lego_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Lego_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Lego_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Lutron_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Lutron_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Lutron_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Lutron_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MWM_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MWM_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MWM_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MWM_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Magiquest_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Magiquest_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Magiquest_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Magiquest_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Magiquest_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Magiquest_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Magiquest_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Magiquest_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Magiquest_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Magiquest_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Magiquest_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Magiquest_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Midea_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Midea_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Midea_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Midea_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Midea_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Midea_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Midea_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Midea_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Midea_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Midea_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Midea_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Midea_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MitsubishiHeavy_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MitsubishiHeavy_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MitsubishiHeavy_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MitsubishiHeavy_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MitsubishiHeavy_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MitsubishiHeavy_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MitsubishiHeavy_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MitsubishiHeavy_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MitsubishiHeavy_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MitsubishiHeavy_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__MitsubishiHeavy_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__MitsubishiHeavy_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Mitsubishi_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Mitsubishi_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Mitsubishi_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Mitsubishi_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Mitsubishi_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Mitsubishi_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Mitsubishi_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Mitsubishi_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Mitsubishi_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Mitsubishi_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Mitsubishi_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Mitsubishi_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Multibrackets_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Multibrackets_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Multibrackets_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Multibrackets_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__NEC_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__NEC_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__NEC_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__NEC_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__NEC_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__NEC_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__NEC_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__NEC_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__NEC_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__NEC_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__NEC_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__NEC_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Neoclima_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Neoclima_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Neoclima_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Neoclima_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Neoclima_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Neoclima_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Neoclima_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Neoclima_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Neoclima_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Neoclima_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Neoclima_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Neoclima_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Nikai_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Nikai_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Nikai_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Nikai_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Panasonic_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Panasonic_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Panasonic_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Panasonic_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Panasonic_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Panasonic_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Panasonic_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Panasonic_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Panasonic_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Panasonic_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Panasonic_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Panasonic_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Pioneer_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Pioneer_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Pioneer_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Pioneer_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Pronto_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Pronto_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Pronto_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Pronto_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__RC5__RC6_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__RC5__RC6_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__RC5__RC6_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__RC5__RC6_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__RCMM_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__RCMM_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__RCMM_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__RCMM_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Samsung_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Samsung_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Samsung_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Samsung_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Samsung_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Samsung_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Samsung_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Samsung_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Samsung_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Samsung_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Samsung_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Samsung_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sanyo_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sanyo_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sanyo_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sanyo_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sharp_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sharp_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sharp_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sharp_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sharp_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sharp_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sharp_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sharp_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sharp_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sharp_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sharp_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sharp_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sherwood_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sherwood_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sherwood_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sherwood_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sony_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sony_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Sony_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Sony_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Symphony_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Symphony_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Symphony_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Symphony_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Tcl_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Tcl_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Tcl_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Tcl_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Tcl_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Tcl_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Tcl_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Tcl_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Tcl_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Tcl_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Tcl_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Tcl_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Teco_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Teco_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Teco_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Teco_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Teco_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Teco_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Teco_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Teco_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Teco_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Teco_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Teco_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Teco_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Toshiba_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Toshiba_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Toshiba_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Toshiba_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Toshiba_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Toshiba_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Toshiba_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Toshiba_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Toshiba_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Toshiba_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Toshiba_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Toshiba_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Trotec_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Trotec_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Trotec_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Trotec_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Trotec_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Trotec_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Trotec_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Trotec_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Trotec_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Trotec_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Trotec_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Trotec_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Vestel_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Vestel_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Vestel_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Vestel_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Vestel_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Vestel_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Vestel_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Vestel_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Vestel_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Vestel_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Vestel_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Vestel_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whirlpool_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whirlpool_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whirlpool_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whirlpool_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whirlpool_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whirlpool_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whirlpool_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whirlpool_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whirlpool_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whirlpool_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whirlpool_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whirlpool_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whynter_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whynter_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Whynter_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Whynter_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Zepeal_8cpp.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Zepeal_8cpp.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/ir__Zepeal_8cpp.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/ir__Zepeal_8cpp.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/it-IT_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/it-IT_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/it-IT_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/it-IT_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/it-IT_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/it-IT_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/it-IT_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/it-IT_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/jquery.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/jquery.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/jquery.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/jquery.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/md_src_locale_README.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/md_src_locale_README.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/md_src_locale_README.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/md_src_locale_README.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/menu.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/menu.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/menu.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/menu.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/menudata.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/menudata.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/menudata.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/menudata.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespaceIRAcUtils.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespaceIRAcUtils.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespaceIRAcUtils.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespaceIRAcUtils.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespaceirutils.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespaceirutils.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespaceirutils.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespaceirutils.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacemembers.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacemembers.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacemembers.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacemembers.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacemembers_enum.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacemembers_enum.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacemembers_enum.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacemembers_enum.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacemembers_func.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacemembers_func.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacemembers_func.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacemembers_func.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespaces.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespaces.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespaces.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespaces.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacestdAc.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacestdAc.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/namespacestdAc.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/namespacestdAc.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/nav_f.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/nav_f.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/nav_f.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/nav_f.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/nav_g.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/nav_g.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/nav_g.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/nav_g.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/nav_h.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/nav_h.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/nav_h.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/nav_h.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/open.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/open.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/open.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/open.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/pages.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/pages.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/pages.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/pages.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_10.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_10.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_10.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_10.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_10.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_10.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_10.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_10.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_11.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_11.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_11.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_11.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_11.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_11.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_11.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_11.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_12.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_12.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_12.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_12.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_12.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_12.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_12.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_12.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_13.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_13.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_13.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_13.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_13.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_13.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_13.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_13.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_14.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_14.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_14.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_14.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_14.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_14.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_14.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_14.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_15.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_15.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_15.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_15.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_15.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_15.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_15.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_15.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_16.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_16.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_16.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_16.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_16.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_16.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_16.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_16.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_17.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_17.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_17.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_17.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_17.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_17.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_17.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_17.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_18.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_18.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_18.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_18.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_18.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_18.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_18.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_18.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_19.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_19.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_19.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_19.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_19.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_19.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_19.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_19.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1a.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1a.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1a.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1a.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1b.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1b.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_1b.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_1b.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_3.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_3.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_3.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_3.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_4.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_4.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_4.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_4.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_4.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_4.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_4.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_4.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_5.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_5.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_5.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_5.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_5.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_5.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_5.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_5.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_6.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_6.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_6.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_6.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_6.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_6.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_6.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_6.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_7.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_7.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_7.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_7.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_7.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_7.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_7.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_7.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_8.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_8.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_8.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_8.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_8.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_8.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_8.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_8.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_9.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_9.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_9.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_9.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_9.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_9.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_9.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_9.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_a.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_a.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_a.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_a.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_b.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_b.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_b.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_b.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_c.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_c.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_c.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_c.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_d.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_d.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_d.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_d.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_e.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_e.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_e.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_e.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_f.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_f.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/all_f.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/all_f.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_3.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_3.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_3.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_3.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_4.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_4.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_4.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_4.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_4.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_4.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/classes_4.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/classes_4.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/close.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/close.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/close.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/close.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_3.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_3.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_3.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_3.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_4.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_4.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_4.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_4.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_4.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_4.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_4.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_4.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_5.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_5.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_5.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_5.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_5.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_5.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_5.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_5.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_6.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_6.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_6.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_6.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_6.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_6.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_6.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_6.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_7.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_7.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_7.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_7.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_7.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_7.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_7.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_7.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_8.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_8.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_8.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_8.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_8.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_8.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enums_8.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enums_8.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_10.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_10.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_10.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_10.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_10.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_10.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_10.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_10.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_11.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_11.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_11.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_11.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_11.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_11.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_11.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_11.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_12.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_12.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_12.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_12.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_12.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_12.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_12.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_12.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_13.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_13.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_13.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_13.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_13.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_13.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_13.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_13.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_14.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_14.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_14.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_14.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_14.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_14.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_14.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_14.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_15.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_15.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_15.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_15.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_15.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_15.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_15.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_15.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_3.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_3.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_3.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_3.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_4.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_4.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_4.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_4.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_4.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_4.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_4.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_4.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_5.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_5.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_5.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_5.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_5.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_5.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_5.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_5.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_6.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_6.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_6.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_6.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_6.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_6.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_6.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_6.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_7.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_7.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_7.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_7.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_7.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_7.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_7.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_7.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_8.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_8.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_8.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_8.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_8.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_8.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_8.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_8.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_9.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_9.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_9.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_9.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_9.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_9.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_9.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_9.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_a.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_a.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_a.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_a.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_b.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_b.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_b.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_b.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_c.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_c.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_c.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_c.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_d.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_d.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_d.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_d.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_e.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_e.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_e.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_e.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_f.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_f.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/enumvalues_f.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/enumvalues_f.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_3.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_3.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_3.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_3.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_4.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_4.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_4.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_4.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_4.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_4.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_4.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_4.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_5.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_5.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_5.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_5.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_5.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_5.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/files_5.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/files_5.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_10.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_10.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_10.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_10.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_10.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_10.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_10.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_10.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_11.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_11.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_11.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_11.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_11.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_11.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_11.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_11.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_12.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_12.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_12.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_12.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_12.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_12.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_12.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_12.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_13.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_13.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_13.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_13.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_13.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_13.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_13.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_13.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_14.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_14.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_14.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_14.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_14.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_14.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_14.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_14.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_15.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_15.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_15.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_15.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_15.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_15.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_15.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_15.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_16.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_16.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_16.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_16.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_16.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_16.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_16.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_16.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_17.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_17.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_17.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_17.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_17.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_17.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_17.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_17.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_3.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_3.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_3.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_3.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_4.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_4.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_4.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_4.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_4.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_4.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_4.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_4.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_5.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_5.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_5.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_5.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_5.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_5.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_5.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_5.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_6.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_6.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_6.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_6.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_6.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_6.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_6.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_6.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_7.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_7.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_7.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_7.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_7.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_7.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_7.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_7.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_8.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_8.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_8.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_8.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_8.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_8.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_8.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_8.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_9.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_9.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_9.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_9.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_9.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_9.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_9.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_9.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_a.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_a.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_a.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_a.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_b.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_b.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_b.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_b.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_c.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_c.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_c.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_c.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_d.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_d.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_d.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_d.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_e.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_e.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_e.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_e.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_f.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_f.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/functions_f.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/functions_f.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/mag_sel.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/mag_sel.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/mag_sel.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/mag_sel.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/namespaces_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/namespaces_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/nomatches.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/nomatches.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/nomatches.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/nomatches.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/pages_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/pages_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/related_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/related_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/related_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/related_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/related_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/related_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/related_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/related_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search.css b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search.css similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search.css rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search.css diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search_l.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search_l.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search_l.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search_l.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search_m.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search_m.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search_m.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search_m.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search_r.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search_r.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/search_r.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/search_r.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/searchdata.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/searchdata.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/searchdata.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/searchdata.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/typedefs_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/typedefs_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/typedefs_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/typedefs_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/typedefs_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/typedefs_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/typedefs_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/typedefs_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_0.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_0.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_0.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_0.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_0.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_0.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_0.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_0.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_1.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_1.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_1.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_1.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_1.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_1.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_1.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_1.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_10.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_10.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_10.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_10.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_10.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_10.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_10.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_10.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_11.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_11.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_11.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_11.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_11.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_11.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_11.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_11.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_12.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_12.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_12.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_12.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_12.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_12.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_12.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_12.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_13.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_13.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_13.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_13.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_13.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_13.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_13.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_13.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_14.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_14.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_14.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_14.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_14.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_14.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_14.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_14.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_15.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_15.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_15.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_15.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_15.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_15.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_15.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_15.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_16.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_16.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_16.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_16.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_16.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_16.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_16.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_16.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_2.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_2.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_2.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_2.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_2.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_2.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_2.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_2.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_3.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_3.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_3.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_3.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_3.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_3.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_3.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_3.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_4.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_4.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_4.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_4.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_4.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_4.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_4.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_4.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_5.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_5.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_5.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_5.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_5.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_5.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_5.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_5.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_6.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_6.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_6.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_6.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_6.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_6.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_6.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_6.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_7.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_7.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_7.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_7.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_7.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_7.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_7.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_7.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_8.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_8.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_8.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_8.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_8.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_8.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_8.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_8.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_9.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_9.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_9.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_9.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_9.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_9.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_9.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_9.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_a.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_a.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_a.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_a.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_a.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_a.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_a.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_a.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_b.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_b.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_b.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_b.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_b.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_b.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_b.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_b.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_c.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_c.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_c.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_c.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_c.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_c.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_c.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_c.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_d.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_d.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_d.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_d.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_d.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_d.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_d.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_d.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_e.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_e.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_e.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_e.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_e.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_e.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_e.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_e.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_f.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_f.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_f.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_f.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_f.js b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_f.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/search/variables_f.js rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/search/variables_f.js diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/splitbar.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/splitbar.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/splitbar.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/splitbar.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structirparams__t-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structirparams__t-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structirparams__t-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structirparams__t-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structirparams__t.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structirparams__t.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structirparams__t.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structirparams__t.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structmatch__result__t-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structmatch__result__t-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structmatch__result__t-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structmatch__result__t-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structmatch__result__t.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structmatch__result__t.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structmatch__result__t.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structmatch__result__t.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structstdAc_1_1state__t-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structstdAc_1_1state__t-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structstdAc_1_1state__t-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structstdAc_1_1state__t-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structstdAc_1_1state__t.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structstdAc_1_1state__t.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/structstdAc_1_1state__t.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/structstdAc_1_1state__t.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/sync_off.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/sync_off.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/sync_off.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/sync_off.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/sync_on.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/sync_on.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/sync_on.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/sync_on.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_a.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_a.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_a.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_a.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_b.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_b.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_b.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_b.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_h.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_h.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_h.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_h.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_s.png b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_s.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tab_s.png rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tab_s.png diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tabs.css b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tabs.css similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/tabs.css rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/tabs.css diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/todo.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/todo.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/todo.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/todo.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/unionmagiquest-members.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/unionmagiquest-members.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/unionmagiquest-members.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/unionmagiquest-members.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/unionmagiquest.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/unionmagiquest.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/unionmagiquest.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/unionmagiquest.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/zh-CN_8h.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/zh-CN_8h.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/zh-CN_8h.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/zh-CN_8h.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen/html/zh-CN_8h_source.html b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/zh-CN_8h_source.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen/html/zh-CN_8h_source.html rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen/html/zh-CN_8h_source.html diff --git a/lib/IRremoteESP8266-2.7.8/docs/doxygen_index.md b/lib/IRremoteESP8266-2.7.8.10/docs/doxygen_index.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/docs/doxygen_index.md rename to lib/IRremoteESP8266-2.7.8.10/docs/doxygen_index.md diff --git a/lib/IRremoteESP8266-2.7.8/examples/BlynkIrRemote/BlynkIrRemote.ino b/lib/IRremoteESP8266-2.7.8.10/examples/BlynkIrRemote/BlynkIrRemote.ino similarity index 97% rename from lib/IRremoteESP8266-2.7.8/examples/BlynkIrRemote/BlynkIrRemote.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/BlynkIrRemote/BlynkIrRemote.ino index 6e659bd64..7eaed8f83 100644 --- a/lib/IRremoteESP8266-2.7.8/examples/BlynkIrRemote/BlynkIrRemote.ino +++ b/lib/IRremoteESP8266-2.7.8.10/examples/BlynkIrRemote/BlynkIrRemote.ino @@ -1,196 +1,196 @@ -/************************************************************* - Emulate a physical remote via an iOS and Android App. - Copyright Gaurav Barwalia 2020 - - Download latest Blynk library here: - https://github.com/blynkkk/blynk-library/releases/latest - - Blynk is a platform with iOS and Android apps to control - Arduino, Raspberry Pi and the likes over the Internet. - You can easily build graphic interfaces for all your - projects by simply dragging and dropping widgets. - - Downloads, docs, tutorials: http://www.blynk.cc - Sketch generator: http://examples.blynk.cc - Blynk community: http://community.blynk.cc - Follow us: http://www.fb.com/blynkapp - http://twitter.com/blynk_app - - Blynk library is licensed under MIT license - This example code is in public domain. - - ************************************************************* - This example runs directly on ESP8266 chip. - - Note: This requires ESP8266 support package: - https://github.com/esp8266/Arduino - - Please be sure to select the right ESP8266 module - in the Tools -> Board menu! - - Change WiFi ssid, pass, and Blynk auth token to run :) - Feel free to apply it to any other example. It's simple! - *************************************************************/ - - /* - // After decoding received below codes - - // Power button - -18:12:33.993 -> Protocol : NEC -18:12:33.993 -> Code : 0x1FE50AF (32 Bits) -18:12:33.993 -> uint16_t rawData[71] = {9040, 4452, 606, 532, 606, 534, 630, 508, 604, 534, 604, 534, 604, 534, 630, 506, 606, 1646, 632, 1620, 606, 1646, 632, 1620, 630, 1620, 632, 1620, 630, 1620, 606, 1646, 632, 506, 632, 506, 632, 1620, 632, 506, 632, 1620, 632, 506, 632, 508, 632, 506, 632, 506, 632, 1620, 632, 506, 632, 1624, 628, 506, 632, 1620, 632, 1618, 632, 1620, 632, 1620, 632, 39016, 9040, 2216, 630}; // NEC 1FE50AF -18:12:34.027 -> uint32_t address = 0x80; -18:12:34.027 -> uint32_t command = 0xA; -18:12:34.027 -> uint64_t data = 0x1FE50AF; - -//mute button - -18:13:27.215 -> Protocol : NEC -18:13:27.215 -> Code : 0x1FE30CF (32 Bits) -18:13:27.215 -> uint16_t rawData[71] = {9094, 4398, 660, 478, 658, 480, 658, 480, 658, 480, 658, 480, 658, 480, 660, 480, 658, 1594, 658, 1594, 658, 1594, 658, 1594, 658, 1592, 658, 1594, 658, 1592, 658, 1594, 660, 480, 658, 480, 658, 480, 658, 1592, 658, 1592, 658, 480, 658, 480, 660, 478, 660, 478, 658, 1594, 658, 1592, 658, 480, 658, 480, 658, 1594, 658, 1592, 658, 1594, 658, 1594, 658, 38986, 9094, 2162, 658}; // NEC 1FE30CF -18:13:27.285 -> uint32_t address = 0x80; -18:13:27.285 -> uint32_t command = 0xC; -18:13:27.285 -> uint64_t data = 0x1FE30CF; - -//Vol. low - -18:14:44.427 -> Protocol : NEC -18:14:44.427 -> Code : 0x1FEC03F (32 Bits) -18:14:44.427 -> uint16_t rawData[71] = {9120, 4374, 658, 478, 658, 480, 658, 480, 658, 480, 658, 482, 658, 478, 658, 480, 658, 1594, 658, 1594, 658, 1592, 660, 1594, 658, 1592, 658, 1594, 658, 1594, 658, 1592, 660, 480, 658, 1594, 658, 1594, 658, 480, 658, 480, 660, 480, 658, 480, 658, 480, 658, 480, 658, 480, 658, 480, 658, 1594, 660, 1592, 658, 1594, 658, 1594, 658, 1592, 658, 1594, 658, 39002, 9094, 2162, 658}; // NEC 1FEC03F -18:14:44.497 -> uint32_t address = 0x80; -18:14:44.497 -> uint32_t command = 0x3; -18:14:44.497 -> uint64_t data = 0x1FEC03F; - -//VOl. High - -18:15:11.677 -> Protocol : NEC -18:15:11.677 -> Code : 0x1FE40BF (32 Bits) -18:15:11.677 -> uint16_t rawData[67] = {9068, 4426, 630, 506, 632, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 1622, 630, 1622, 630, 1622, 630, 1622, 656, 1594, 630, 1622, 632, 1620, 630, 1622, 630, 508, 630, 508, 630, 1622, 630, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 1622, 656, 482, 630, 1622, 630, 1622, 630, 1622, 630, 1622, 630, 1622, 632, 1620, 630}; // NEC 1FE40BF -18:15:11.747 -> uint32_t address = 0x80; -18:15:11.747 -> uint32_t command = 0x2; -18:15:11.747 -> uint64_t data = 0x1FE40BF; - -//Play/Pause - -18:15:38.529 -> Protocol : NEC -18:15:38.529 -> Code : 0x1FE32CD (32 Bits) -18:15:38.529 -> uint16_t rawData[71] = {9092, 4400, 632, 504, 658, 480, 658, 480, 632, 506, 658, 480, 658, 480, 658, 482, 632, 1620, 658, 1594, 658, 1594, 632, 1618, 658, 1594, 658, 1594, 632, 1620, 632, 1618, 634, 506, 658, 480, 658, 480, 632, 1620, 658, 1598, 656, 478, 658, 478, 658, 1594, 658, 482, 632, 1618, 632, 1618, 634, 506, 632, 506, 658, 1594, 632, 1620, 658, 480, 632, 1620, 658, 38998, 9094, 2162, 660}; // NEC 1FE32CD -18:15:38.564 -> uint32_t address = 0x80; -18:15:38.564 -> uint32_t command = 0x4C; -18:15:38.564 -> uint64_t data = 0x1FE32CD; - -//Song Back - -18:16:07.527 -> Protocol : NEC -18:16:07.527 -> Code : 0x1FEA05F (32 Bits) -18:16:07.562 -> uint16_t rawData[71] = {9590, 3902, 684, 452, 686, 456, 652, 480, 660, 480, 684, 456, 656, 480, 658, 480, 684, 1568, 658, 1594, 658, 1594, 686, 1566, 658, 1594, 684, 1568, 658, 1594, 658, 1594, 686, 454, 684, 1568, 686, 454, 658, 1594, 684, 454, 686, 454, 658, 480, 660, 480, 684, 454, 658, 482, 658, 1594, 682, 456, 658, 1596, 658, 1594, 686, 1568, 660, 1592, 684, 1568, 686, 38982, 9098, 2162, 684}; // NEC 1FEA05F -18:16:07.597 -> uint32_t address = 0x80; -18:16:07.597 -> uint32_t command = 0x5; -18:16:07.597 -> uint64_t data = 0x1FEA05F; - -//Song Forward - -18:17:20.541 -> Protocol : NEC -18:17:20.541 -> Code : 0x1FEE01F (32 Bits) -18:17:20.575 -> uint16_t rawData[71] = {9068, 4424, 632, 506, 630, 506, 632, 508, 606, 532, 632, 506, 630, 508, 630, 508, 632, 1620, 632, 1620, 632, 1620, 604, 1646, 606, 1646, 630, 1622, 604, 1646, 632, 1620, 606, 534, 630, 1622, 604, 1646, 630, 1622, 604, 534, 630, 508, 604, 534, 606, 534, 630, 508, 630, 508, 606, 534, 606, 532, 630, 1622, 604, 1646, 632, 1620, 604, 1648, 604, 1646, 604, 39040, 9040, 2216, 604}; // NEC 1FEE01F -18:17:20.610 -> uint32_t address = 0x80; -18:17:20.610 -> uint32_t command = 0x7; -18:17:20.610 -> uint64_t data = 0x1FEE01F; - - */ - -// check complete video tutorial here for program explanation https://www.youtube.com/watch?v=LqmkDKu54XY&t=17s - -/* Comment this out to disable prints and save space */ -#define BLYNK_PRINT Serial - -#if defined(ESP8266) -#include -#include -#else -#include -#endif // ESP8266 -#if defined(ESP32) -#include -#endif // ESP32 - -// IR library -#include -#include - -const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message. - -// You should get Auth Token in the Blynk App. -// Go to the Project Settings (nut icon). -char auth[] = "YourAuthToken"; - -// Your WiFi credentials. -// Set password to "" for open networks. -char ssid[] = "YourNetworkName"; -char pass[] = "YourPassword"; - - BLYNK_WRITE(V51) { // Power button - if (param.asInt() == 0) { - // Serial.println("NEC"); - irsend.sendNEC(0x1FE50AF); - } - } - - BLYNK_WRITE(V52) { // Mute button - if (param.asInt() == 0) { - // Serial.println("NEC"); - irsend.sendNEC(0x1FE30CF); - } - } - - BLYNK_WRITE(V53) { // Song Forward - if (param.asInt() == 0) { - // Serial.println("NEC"); - irsend.sendNEC(0x1FEE01F); - } - } - - BLYNK_WRITE(V54) { // Song Backward - if (param.asInt() == 0) { - // Serial.println("NEC"); - irsend.sendNEC(0x1FEA05F); - delay(10); // double tap back button to back one song - irsend.sendNEC(0x1FEA05F); - } - } - - BLYNK_WRITE(V55) { // Volume -- - if (param.asInt() == 0) { - // Serial.println("NEC"); - irsend.sendNEC(0x1FEC03F); - } - } - - BLYNK_WRITE(V56) { // Volume ++ - if (param.asInt() == 0) { - // Serial.println("NEC"); - irsend.sendNEC(0x1FE40BF); - } - } - - BLYNK_WRITE(V57) { // Play/Pause - if (param.asInt() == 0) { - // Serial.println("NEC"); - irsend.sendNEC(0x1FE32CD); - } - } - -void setup() { -#if defined(BLYNK_PRINT) - // Debug console - Serial.begin(115200); -#endif // BLYNK_PRINT - - Blynk.begin(auth, ssid, pass); -} - -void loop() { - Blynk.run(); -} +/************************************************************* + Emulate a physical remote via an iOS and Android App. + Copyright Gaurav Barwalia 2020 + + Download latest Blynk library here: + https://github.com/blynkkk/blynk-library/releases/latest + + Blynk is a platform with iOS and Android apps to control + Arduino, Raspberry Pi and the likes over the Internet. + You can easily build graphic interfaces for all your + projects by simply dragging and dropping widgets. + + Downloads, docs, tutorials: http://www.blynk.cc + Sketch generator: http://examples.blynk.cc + Blynk community: http://community.blynk.cc + Follow us: http://www.fb.com/blynkapp + http://twitter.com/blynk_app + + Blynk library is licensed under MIT license + This example code is in public domain. + + ************************************************************* + This example runs directly on ESP8266 chip. + + Note: This requires ESP8266 support package: + https://github.com/esp8266/Arduino + + Please be sure to select the right ESP8266 module + in the Tools -> Board menu! + + Change WiFi ssid, pass, and Blynk auth token to run :) + Feel free to apply it to any other example. It's simple! + *************************************************************/ + + /* + // After decoding received below codes + + // Power button + +18:12:33.993 -> Protocol : NEC +18:12:33.993 -> Code : 0x1FE50AF (32 Bits) +18:12:33.993 -> uint16_t rawData[71] = {9040, 4452, 606, 532, 606, 534, 630, 508, 604, 534, 604, 534, 604, 534, 630, 506, 606, 1646, 632, 1620, 606, 1646, 632, 1620, 630, 1620, 632, 1620, 630, 1620, 606, 1646, 632, 506, 632, 506, 632, 1620, 632, 506, 632, 1620, 632, 506, 632, 508, 632, 506, 632, 506, 632, 1620, 632, 506, 632, 1624, 628, 506, 632, 1620, 632, 1618, 632, 1620, 632, 1620, 632, 39016, 9040, 2216, 630}; // NEC 1FE50AF +18:12:34.027 -> uint32_t address = 0x80; +18:12:34.027 -> uint32_t command = 0xA; +18:12:34.027 -> uint64_t data = 0x1FE50AF; + +//mute button + +18:13:27.215 -> Protocol : NEC +18:13:27.215 -> Code : 0x1FE30CF (32 Bits) +18:13:27.215 -> uint16_t rawData[71] = {9094, 4398, 660, 478, 658, 480, 658, 480, 658, 480, 658, 480, 658, 480, 660, 480, 658, 1594, 658, 1594, 658, 1594, 658, 1594, 658, 1592, 658, 1594, 658, 1592, 658, 1594, 660, 480, 658, 480, 658, 480, 658, 1592, 658, 1592, 658, 480, 658, 480, 660, 478, 660, 478, 658, 1594, 658, 1592, 658, 480, 658, 480, 658, 1594, 658, 1592, 658, 1594, 658, 1594, 658, 38986, 9094, 2162, 658}; // NEC 1FE30CF +18:13:27.285 -> uint32_t address = 0x80; +18:13:27.285 -> uint32_t command = 0xC; +18:13:27.285 -> uint64_t data = 0x1FE30CF; + +//Vol. low + +18:14:44.427 -> Protocol : NEC +18:14:44.427 -> Code : 0x1FEC03F (32 Bits) +18:14:44.427 -> uint16_t rawData[71] = {9120, 4374, 658, 478, 658, 480, 658, 480, 658, 480, 658, 482, 658, 478, 658, 480, 658, 1594, 658, 1594, 658, 1592, 660, 1594, 658, 1592, 658, 1594, 658, 1594, 658, 1592, 660, 480, 658, 1594, 658, 1594, 658, 480, 658, 480, 660, 480, 658, 480, 658, 480, 658, 480, 658, 480, 658, 480, 658, 1594, 660, 1592, 658, 1594, 658, 1594, 658, 1592, 658, 1594, 658, 39002, 9094, 2162, 658}; // NEC 1FEC03F +18:14:44.497 -> uint32_t address = 0x80; +18:14:44.497 -> uint32_t command = 0x3; +18:14:44.497 -> uint64_t data = 0x1FEC03F; + +//VOl. High + +18:15:11.677 -> Protocol : NEC +18:15:11.677 -> Code : 0x1FE40BF (32 Bits) +18:15:11.677 -> uint16_t rawData[67] = {9068, 4426, 630, 506, 632, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 1622, 630, 1622, 630, 1622, 630, 1622, 656, 1594, 630, 1622, 632, 1620, 630, 1622, 630, 508, 630, 508, 630, 1622, 630, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 508, 630, 1622, 656, 482, 630, 1622, 630, 1622, 630, 1622, 630, 1622, 630, 1622, 632, 1620, 630}; // NEC 1FE40BF +18:15:11.747 -> uint32_t address = 0x80; +18:15:11.747 -> uint32_t command = 0x2; +18:15:11.747 -> uint64_t data = 0x1FE40BF; + +//Play/Pause + +18:15:38.529 -> Protocol : NEC +18:15:38.529 -> Code : 0x1FE32CD (32 Bits) +18:15:38.529 -> uint16_t rawData[71] = {9092, 4400, 632, 504, 658, 480, 658, 480, 632, 506, 658, 480, 658, 480, 658, 482, 632, 1620, 658, 1594, 658, 1594, 632, 1618, 658, 1594, 658, 1594, 632, 1620, 632, 1618, 634, 506, 658, 480, 658, 480, 632, 1620, 658, 1598, 656, 478, 658, 478, 658, 1594, 658, 482, 632, 1618, 632, 1618, 634, 506, 632, 506, 658, 1594, 632, 1620, 658, 480, 632, 1620, 658, 38998, 9094, 2162, 660}; // NEC 1FE32CD +18:15:38.564 -> uint32_t address = 0x80; +18:15:38.564 -> uint32_t command = 0x4C; +18:15:38.564 -> uint64_t data = 0x1FE32CD; + +//Song Back + +18:16:07.527 -> Protocol : NEC +18:16:07.527 -> Code : 0x1FEA05F (32 Bits) +18:16:07.562 -> uint16_t rawData[71] = {9590, 3902, 684, 452, 686, 456, 652, 480, 660, 480, 684, 456, 656, 480, 658, 480, 684, 1568, 658, 1594, 658, 1594, 686, 1566, 658, 1594, 684, 1568, 658, 1594, 658, 1594, 686, 454, 684, 1568, 686, 454, 658, 1594, 684, 454, 686, 454, 658, 480, 660, 480, 684, 454, 658, 482, 658, 1594, 682, 456, 658, 1596, 658, 1594, 686, 1568, 660, 1592, 684, 1568, 686, 38982, 9098, 2162, 684}; // NEC 1FEA05F +18:16:07.597 -> uint32_t address = 0x80; +18:16:07.597 -> uint32_t command = 0x5; +18:16:07.597 -> uint64_t data = 0x1FEA05F; + +//Song Forward + +18:17:20.541 -> Protocol : NEC +18:17:20.541 -> Code : 0x1FEE01F (32 Bits) +18:17:20.575 -> uint16_t rawData[71] = {9068, 4424, 632, 506, 630, 506, 632, 508, 606, 532, 632, 506, 630, 508, 630, 508, 632, 1620, 632, 1620, 632, 1620, 604, 1646, 606, 1646, 630, 1622, 604, 1646, 632, 1620, 606, 534, 630, 1622, 604, 1646, 630, 1622, 604, 534, 630, 508, 604, 534, 606, 534, 630, 508, 630, 508, 606, 534, 606, 532, 630, 1622, 604, 1646, 632, 1620, 604, 1648, 604, 1646, 604, 39040, 9040, 2216, 604}; // NEC 1FEE01F +18:17:20.610 -> uint32_t address = 0x80; +18:17:20.610 -> uint32_t command = 0x7; +18:17:20.610 -> uint64_t data = 0x1FEE01F; + + */ + +// check complete video tutorial here for program explanation https://www.youtube.com/watch?v=LqmkDKu54XY&t=17s + +/* Comment this out to disable prints and save space */ +#define BLYNK_PRINT Serial + +#if defined(ESP8266) +#include +#include +#else +#include +#endif // ESP8266 +#if defined(ESP32) +#include +#endif // ESP32 + +// IR library +#include +#include + +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message. + +// You should get Auth Token in the Blynk App. +// Go to the Project Settings (nut icon). +char auth[] = "YourAuthToken"; + +// Your WiFi credentials. +// Set password to "" for open networks. +char ssid[] = "YourNetworkName"; +char pass[] = "YourPassword"; + + BLYNK_WRITE(V51) { // Power button + if (param.asInt() == 0) { + // Serial.println("NEC"); + irsend.sendNEC(0x1FE50AF); + } + } + + BLYNK_WRITE(V52) { // Mute button + if (param.asInt() == 0) { + // Serial.println("NEC"); + irsend.sendNEC(0x1FE30CF); + } + } + + BLYNK_WRITE(V53) { // Song Forward + if (param.asInt() == 0) { + // Serial.println("NEC"); + irsend.sendNEC(0x1FEE01F); + } + } + + BLYNK_WRITE(V54) { // Song Backward + if (param.asInt() == 0) { + // Serial.println("NEC"); + irsend.sendNEC(0x1FEA05F); + delay(10); // double tap back button to back one song + irsend.sendNEC(0x1FEA05F); + } + } + + BLYNK_WRITE(V55) { // Volume -- + if (param.asInt() == 0) { + // Serial.println("NEC"); + irsend.sendNEC(0x1FEC03F); + } + } + + BLYNK_WRITE(V56) { // Volume ++ + if (param.asInt() == 0) { + // Serial.println("NEC"); + irsend.sendNEC(0x1FE40BF); + } + } + + BLYNK_WRITE(V57) { // Play/Pause + if (param.asInt() == 0) { + // Serial.println("NEC"); + irsend.sendNEC(0x1FE32CD); + } + } + +void setup() { +#if defined(BLYNK_PRINT) + // Debug console + Serial.begin(115200); +#endif // BLYNK_PRINT + + Blynk.begin(auth, ssid, pass); +} + +void loop() { + Blynk.run(); +} diff --git a/lib/IRremoteESP8266-2.7.8/examples/BlynkIrRemote/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/BlynkIrRemote/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/BlynkIrRemote/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/BlynkIrRemote/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/CommonAcControl/CommonAcControl.ino b/lib/IRremoteESP8266-2.7.8.10/examples/CommonAcControl/CommonAcControl.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/CommonAcControl/CommonAcControl.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/CommonAcControl/CommonAcControl.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/CommonAcControl/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/CommonAcControl/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/CommonAcControl/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/CommonAcControl/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/ControlSamsungAC/ControlSamsungAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/ControlSamsungAC/ControlSamsungAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/ControlSamsungAC/ControlSamsungAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/ControlSamsungAC/ControlSamsungAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/ControlSamsungAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/ControlSamsungAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/ControlSamsungAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/ControlSamsungAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/DumbIRRepeater/DumbIRRepeater.ino b/lib/IRremoteESP8266-2.7.8.10/examples/DumbIRRepeater/DumbIRRepeater.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/DumbIRRepeater/DumbIRRepeater.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/DumbIRRepeater/DumbIRRepeater.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/DumbIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/DumbIRRepeater/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/DumbIRRepeater/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/DumbIRRepeater/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRGCSendDemo/IRGCSendDemo.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRGCSendDemo/IRGCSendDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRGCSendDemo/IRGCSendDemo.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRGCSendDemo/IRGCSendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRGCSendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRGCSendDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRGCSendDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRGCSendDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRGCTCPServer/IRGCTCPServer.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRGCTCPServer/IRGCTCPServer.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRGCTCPServer/IRGCTCPServer.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRGCTCPServer/IRGCTCPServer.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRGCTCPServer/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRGCTCPServer/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRGCTCPServer/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRGCTCPServer/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRMQTTServer/IRMQTTServer.h b/lib/IRremoteESP8266-2.7.8.10/examples/IRMQTTServer/IRMQTTServer.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRMQTTServer/IRMQTTServer.h rename to lib/IRremoteESP8266-2.7.8.10/examples/IRMQTTServer/IRMQTTServer.h diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRMQTTServer/IRMQTTServer.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRMQTTServer/IRMQTTServer.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRMQTTServer/IRMQTTServer.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRMQTTServer/IRMQTTServer.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRMQTTServer/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRMQTTServer/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRMQTTServer/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRMQTTServer/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRServer/IRServer.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRServer/IRServer.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRServer/IRServer.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRServer/IRServer.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRServer/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRServer/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRServer/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRServer/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDemo/IRrecvDemo.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDemo/IRrecvDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDemo/IRrecvDemo.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDemo/IRrecvDemo.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDemo/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDump/IRrecvDump.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDump/IRrecvDump.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDump/IRrecvDump.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDump/IRrecvDump.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDump/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDump/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDump/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDump/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV2/IRrecvDumpV2.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV2/IRrecvDumpV2.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV2/IRrecvDumpV2.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV2/IRrecvDumpV2.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV2/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV2/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV2/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV2/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV3/BaseOTA.h b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV3/BaseOTA.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV3/BaseOTA.h rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV3/BaseOTA.h diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV3/IRrecvDumpV3.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV3/IRrecvDumpV3.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV3/IRrecvDumpV3.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV3/IRrecvDumpV3.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV3/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV3/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRrecvDumpV3/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRrecvDumpV3/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRsendDemo/IRsendDemo.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRsendDemo/IRsendDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRsendDemo/IRsendDemo.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRsendDemo/IRsendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRsendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRsendDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRsendDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRsendDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRsendProntoDemo/IRsendProntoDemo.ino b/lib/IRremoteESP8266-2.7.8.10/examples/IRsendProntoDemo/IRsendProntoDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRsendProntoDemo/IRsendProntoDemo.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/IRsendProntoDemo/IRsendProntoDemo.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/IRsendProntoDemo/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/IRsendProntoDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/IRsendProntoDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/IRsendProntoDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino b/lib/IRremoteESP8266-2.7.8.10/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/JVCPanasonicSendDemo/JVCPanasonicSendDemo.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/JVCPanasonicSendDemo/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/JVCPanasonicSendDemo/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/JVCPanasonicSendDemo/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/JVCPanasonicSendDemo/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/LGACSend/LGACSend.ino b/lib/IRremoteESP8266-2.7.8.10/examples/LGACSend/LGACSend.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/LGACSend/LGACSend.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/LGACSend/LGACSend.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/LGACSend/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/LGACSend/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/LGACSend/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/LGACSend/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/SmartIRRepeater/SmartIRRepeater.ino b/lib/IRremoteESP8266-2.7.8.10/examples/SmartIRRepeater/SmartIRRepeater.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/SmartIRRepeater/SmartIRRepeater.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/SmartIRRepeater/SmartIRRepeater.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/SmartIRRepeater/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/SmartIRRepeater/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/SmartIRRepeater/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/SmartIRRepeater/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnArgoAC/TurnOnArgoAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnArgoAC/TurnOnArgoAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnArgoAC/TurnOnArgoAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnArgoAC/TurnOnArgoAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnArgoAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnArgoAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnArgoAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnArgoAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnDaikinAC/TurnOnDaikinAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnDaikinAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnDaikinAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnDaikinAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnDaikinAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnFujitsuAC/TurnOnFujitsuAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnFujitsuAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnFujitsuAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnFujitsuAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnFujitsuAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnGreeAC/TurnOnGreeAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnGreeAC/TurnOnGreeAC.ino similarity index 97% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnGreeAC/TurnOnGreeAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnGreeAC/TurnOnGreeAC.ino index 64c857f3d..ecb3b8869 100644 --- a/lib/IRremoteESP8266-2.7.8/examples/TurnOnGreeAC/TurnOnGreeAC.ino +++ b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnGreeAC/TurnOnGreeAC.ino @@ -1,77 +1,77 @@ -/* Copyright 2016, 2018 David Conran -* Copyright 2020 Sadid Rafsun Tulon -* -* An IR LED circuit *MUST* be connected to the ESP8266 on a pin -* as specified by kIrLed below. -* -* TL;DR: The IR LED needs to be driven by a transistor for a good result. -* -* Suggested circuit: -* https://github.com/crankyoldgit/IRremoteESP8266/wiki#ir-sending -* -* Common mistakes & tips: -* * Don't just connect the IR LED directly to the pin, it won't -* have enough current to drive the IR LED effectively. -* * Make sure you have the IR LED polarity correct. -* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity -* * Typical digital camera/phones can be used to see if the IR LED is flashed. -* Replace the IR LED with a normal LED if you don't have a digital camera -* when debugging. -* * Avoid using the following pins unless you really know what you are doing: -* * Pin 0/D3: Can interfere with the boot/program mode & support circuits. -* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere. -* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere. -* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs -* for your first time. e.g. ESP-12 etc. -*/ -#include -#include -#include -#include - -const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). -IRGreeAC ac(kIrLed); // Set the GPIO to be used for sending messages. - -void printState() { - // Display the settings. - Serial.println("GREE A/C remote is in the following state:"); - Serial.printf(" %s\n", ac.toString().c_str()); - // Display the encoded IR sequence. - unsigned char* ir_code = ac.getRaw(); - Serial.print("IR Code: 0x"); - for (uint8_t i = 0; i < kGreeStateLength; i++) - Serial.printf("%02X", ir_code[i]); - Serial.println(); -} - -void setup() { - ac.begin(); - Serial.begin(115200); - delay(200); - - // Set up what we want to send. See ir_Gree.cpp for all the options. - // Most things default to off. - Serial.println("Default state of the remote."); - printState(); - Serial.println("Setting desired state for A/C."); - ac.on(); - ac.setFan(1); - // kGreeAuto, kGreeDry, kGreeCool, kGreeFan, kGreeHeat - ac.setMode(kGreeCool); - ac.setTemp(20); // 16-30C - ac.setSwingVertical(true, kGreeSwingAuto); - ac.setXFan(false); - ac.setLight(false); - ac.setSleep(false); - ac.setTurbo(false); -} - -void loop() { - // Now send the IR signal. -#if SEND_GREE - Serial.println("Sending IR command to A/C ..."); - ac.send(); -#endif // SEND_GREE - printState(); - delay(5000); -} +/* Copyright 2016, 2018 David Conran +* Copyright 2020 Sadid Rafsun Tulon +* +* An IR LED circuit *MUST* be connected to the ESP8266 on a pin +* as specified by kIrLed below. +* +* TL;DR: The IR LED needs to be driven by a transistor for a good result. +* +* Suggested circuit: +* https://github.com/crankyoldgit/IRremoteESP8266/wiki#ir-sending +* +* Common mistakes & tips: +* * Don't just connect the IR LED directly to the pin, it won't +* have enough current to drive the IR LED effectively. +* * Make sure you have the IR LED polarity correct. +* See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity +* * Typical digital camera/phones can be used to see if the IR LED is flashed. +* Replace the IR LED with a normal LED if you don't have a digital camera +* when debugging. +* * Avoid using the following pins unless you really know what you are doing: +* * Pin 0/D3: Can interfere with the boot/program mode & support circuits. +* * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere. +* * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere. +* * ESP-01 modules are tricky. We suggest you use a module with more GPIOs +* for your first time. e.g. ESP-12 etc. +*/ +#include +#include +#include +#include + +const uint16_t kIrLed = 4; // ESP8266 GPIO pin to use. Recommended: 4 (D2). +IRGreeAC ac(kIrLed); // Set the GPIO to be used for sending messages. + +void printState() { + // Display the settings. + Serial.println("GREE A/C remote is in the following state:"); + Serial.printf(" %s\n", ac.toString().c_str()); + // Display the encoded IR sequence. + unsigned char* ir_code = ac.getRaw(); + Serial.print("IR Code: 0x"); + for (uint8_t i = 0; i < kGreeStateLength; i++) + Serial.printf("%02X", ir_code[i]); + Serial.println(); +} + +void setup() { + ac.begin(); + Serial.begin(115200); + delay(200); + + // Set up what we want to send. See ir_Gree.cpp for all the options. + // Most things default to off. + Serial.println("Default state of the remote."); + printState(); + Serial.println("Setting desired state for A/C."); + ac.on(); + ac.setFan(1); + // kGreeAuto, kGreeDry, kGreeCool, kGreeFan, kGreeHeat + ac.setMode(kGreeCool); + ac.setTemp(20); // 16-30C + ac.setSwingVertical(true, kGreeSwingAuto); + ac.setXFan(false); + ac.setLight(false); + ac.setSleep(false); + ac.setTurbo(false); +} + +void loop() { + // Now send the IR signal. +#if SEND_GREE + Serial.println("Sending IR command to A/C ..."); + ac.send(); +#endif // SEND_GREE + printState(); + delay(5000); +} diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnGreeAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnGreeAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnGreeAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnGreeAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnKelvinatorAC/TurnOnKelvinatorAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnKelvinatorAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnKelvinatorAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnKelvinatorAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnKelvinatorAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiAC/TurnOnMitsubishiAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiHeavyAc/TurnOnMitsubishiHeavyAc.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiHeavyAc/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiHeavyAc/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnMitsubishiHeavyAc/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnMitsubishiHeavyAc/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnPanasonicAC/TurnOnPanasonicAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnPanasonicAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnPanasonicAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnPanasonicAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnPanasonicAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnToshibaAC/TurnOnToshibaAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnToshibaAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnToshibaAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnToshibaAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnTrotecAC/TurnOnTrotecAC.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/TurnOnTrotecAC/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/TurnOnTrotecAC/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/TurnOnTrotecAC/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/TurnOnTrotecAC/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/README.md b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/README.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/README.md rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/README.md diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/Web-AC-control.ino b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/Web-AC-control.ino similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/Web-AC-control.ino rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/Web-AC-control.ino diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/printscreen.png b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/printscreen.png similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/printscreen.png rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/printscreen.png diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/favicon.ico b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/favicon.ico similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/favicon.ico rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/favicon.ico diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_1_off.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_1_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_1_off.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_1_off.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_1_on.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_1_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_1_on.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_1_on.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_2_off.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_2_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_2_off.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_2_off.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_2_on.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_2_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_2_on.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_2_on.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_3_off.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_3_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_3_off.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_3_off.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_3_on.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_3_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_3_on.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_3_on.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_4_off.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_4_off.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_4_off.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_4_off.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_4_on.svg b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_4_on.svg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/level_4_on.svg rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/level_4_on.svg diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/ui.html b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/ui.html similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/ui.html rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/ui.html diff --git a/lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/ui.js b/lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/ui.js similarity index 100% rename from lib/IRremoteESP8266-2.7.8/examples/Web-AC-control/upload/ui.js rename to lib/IRremoteESP8266-2.7.8.10/examples/Web-AC-control/upload/ui.js diff --git a/lib/IRremoteESP8266-2.7.8/keywords.txt b/lib/IRremoteESP8266-2.7.8.10/keywords.txt similarity index 100% rename from lib/IRremoteESP8266-2.7.8/keywords.txt rename to lib/IRremoteESP8266-2.7.8.10/keywords.txt diff --git a/lib/IRremoteESP8266-2.7.8/library.json b/lib/IRremoteESP8266-2.7.8.10/library.json similarity index 100% rename from lib/IRremoteESP8266-2.7.8/library.json rename to lib/IRremoteESP8266-2.7.8.10/library.json diff --git a/lib/IRremoteESP8266-2.7.8/library.properties b/lib/IRremoteESP8266-2.7.8.10/library.properties similarity index 100% rename from lib/IRremoteESP8266-2.7.8/library.properties rename to lib/IRremoteESP8266-2.7.8.10/library.properties diff --git a/lib/IRremoteESP8266-2.7.8/platformio.ini b/lib/IRremoteESP8266-2.7.8.10/platformio.ini similarity index 100% rename from lib/IRremoteESP8266-2.7.8/platformio.ini rename to lib/IRremoteESP8266-2.7.8.10/platformio.ini diff --git a/lib/IRremoteESP8266-2.7.8/pylintrc b/lib/IRremoteESP8266-2.7.8.10/pylintrc similarity index 100% rename from lib/IRremoteESP8266-2.7.8/pylintrc rename to lib/IRremoteESP8266-2.7.8.10/pylintrc diff --git a/lib/IRremoteESP8266-2.7.8/src/CPPLINT.cfg b/lib/IRremoteESP8266-2.7.8.10/src/CPPLINT.cfg similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/CPPLINT.cfg rename to lib/IRremoteESP8266-2.7.8.10/src/CPPLINT.cfg diff --git a/lib/IRremoteESP8266-2.7.8/src/IRac.cpp b/lib/IRremoteESP8266-2.7.8.10/src/IRac.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRac.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/IRac.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/IRac.h b/lib/IRremoteESP8266-2.7.8.10/src/IRac.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRac.h rename to lib/IRremoteESP8266-2.7.8.10/src/IRac.h diff --git a/lib/IRremoteESP8266-2.7.8/src/IRrecv.cpp b/lib/IRremoteESP8266-2.7.8.10/src/IRrecv.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRrecv.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/IRrecv.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/IRrecv.h b/lib/IRremoteESP8266-2.7.8.10/src/IRrecv.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRrecv.h rename to lib/IRremoteESP8266-2.7.8.10/src/IRrecv.h diff --git a/lib/IRremoteESP8266-2.7.8/src/IRremoteESP8266.h b/lib/IRremoteESP8266-2.7.8.10/src/IRremoteESP8266.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRremoteESP8266.h rename to lib/IRremoteESP8266-2.7.8.10/src/IRremoteESP8266.h diff --git a/lib/IRremoteESP8266-2.7.8/src/IRsend.cpp b/lib/IRremoteESP8266-2.7.8.10/src/IRsend.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRsend.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/IRsend.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/IRsend.h b/lib/IRremoteESP8266-2.7.8.10/src/IRsend.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRsend.h rename to lib/IRremoteESP8266-2.7.8.10/src/IRsend.h diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtext.cpp b/lib/IRremoteESP8266-2.7.8.10/src/IRtext.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRtext.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/IRtext.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtext.h b/lib/IRremoteESP8266-2.7.8.10/src/IRtext.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRtext.h rename to lib/IRremoteESP8266-2.7.8.10/src/IRtext.h diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtimer.cpp b/lib/IRremoteESP8266-2.7.8.10/src/IRtimer.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRtimer.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/IRtimer.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/IRtimer.h b/lib/IRremoteESP8266-2.7.8.10/src/IRtimer.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRtimer.h rename to lib/IRremoteESP8266-2.7.8.10/src/IRtimer.h diff --git a/lib/IRremoteESP8266-2.7.8/src/IRutils.cpp b/lib/IRremoteESP8266-2.7.8.10/src/IRutils.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRutils.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/IRutils.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/IRutils.h b/lib/IRremoteESP8266-2.7.8.10/src/IRutils.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/IRutils.h rename to lib/IRremoteESP8266-2.7.8.10/src/IRutils.h diff --git a/lib/IRremoteESP8266-2.7.8/src/i18n.h b/lib/IRremoteESP8266-2.7.8.10/src/i18n.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/i18n.h rename to lib/IRremoteESP8266-2.7.8.10/src/i18n.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Airwell.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Airwell.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Airwell.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Airwell.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Airwell.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Airwell.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Airwell.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Aiwa.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Aiwa.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Aiwa.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Aiwa.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Amcor.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Amcor.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Amcor.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Amcor.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Amcor.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Amcor.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Amcor.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Amcor.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Argo.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Argo.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Argo.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Argo.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Argo.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Argo.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Argo.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Argo.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Carrier.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Carrier.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Carrier.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Carrier.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Carrier.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Carrier.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Carrier.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Carrier.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Coolix.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Coolix.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Coolix.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Coolix.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Coolix.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Coolix.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Coolix.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Coolix.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Corona.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Corona.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Corona.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Corona.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Corona.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Corona.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Corona.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Corona.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Daikin.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Daikin.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Daikin.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Daikin.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Daikin.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Daikin.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Daikin.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Daikin.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Delonghi.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Delonghi.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Delonghi.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Delonghi.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Delonghi.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Delonghi.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Delonghi.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Delonghi.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Denon.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Denon.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Denon.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Denon.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Dish.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Dish.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Dish.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Dish.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Doshisha.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Doshisha.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Doshisha.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Doshisha.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Electra.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Electra.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Electra.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Electra.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Electra.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Electra.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Electra.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Electra.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Epson.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Epson.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Epson.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Epson.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Fujitsu.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Fujitsu.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Fujitsu.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Fujitsu.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Fujitsu.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Fujitsu.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Fujitsu.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Fujitsu.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_GICable.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_GICable.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_GICable.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_GICable.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_GlobalCache.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_GlobalCache.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_GlobalCache.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_GlobalCache.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Goodweather.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Goodweather.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Goodweather.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Goodweather.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Goodweather.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Goodweather.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Goodweather.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Goodweather.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Gree.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Gree.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Gree.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Gree.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Gree.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Gree.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Gree.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Gree.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Haier.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Haier.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Haier.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Haier.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Haier.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Haier.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Haier.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Haier.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Hitachi.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Hitachi.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Hitachi.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Hitachi.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Hitachi.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Inax.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Inax.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Inax.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Inax.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_JVC.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_JVC.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_JVC.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_JVC.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Kelvinator.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Kelvinator.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Kelvinator.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Kelvinator.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Kelvinator.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Kelvinator.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Kelvinator.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Kelvinator.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_LG.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_LG.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_LG.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_LG.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_LG.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_LG.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_LG.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_LG.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Lasertag.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Lasertag.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Lasertag.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Lasertag.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Lego.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Lego.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Lego.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Lego.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Lutron.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Lutron.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Lutron.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Lutron.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_MWM.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_MWM.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_MWM.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_MWM.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Magiquest.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Magiquest.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Magiquest.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Magiquest.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Magiquest.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Magiquest.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Magiquest.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Magiquest.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Midea.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Midea.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Midea.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Midea.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Midea.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Midea.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Midea.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Midea.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Mitsubishi.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Mitsubishi.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Mitsubishi.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Mitsubishi.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Mitsubishi.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_MitsubishiHeavy.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_MitsubishiHeavy.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_MitsubishiHeavy.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_MitsubishiHeavy.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_MitsubishiHeavy.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Multibrackets.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Multibrackets.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Multibrackets.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Multibrackets.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_NEC.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_NEC.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_NEC.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_NEC.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_NEC.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_NEC.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_NEC.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_NEC.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Neoclima.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Neoclima.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Neoclima.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Neoclima.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Neoclima.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Neoclima.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Neoclima.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Neoclima.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Nikai.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Nikai.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Nikai.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Nikai.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Panasonic.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Panasonic.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Panasonic.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Panasonic.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Panasonic.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Panasonic.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Panasonic.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Panasonic.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Pioneer.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Pioneer.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Pioneer.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Pioneer.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Pronto.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Pronto.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Pronto.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Pronto.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_RC5_RC6.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_RC5_RC6.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_RC5_RC6.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_RC5_RC6.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_RCMM.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_RCMM.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_RCMM.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_RCMM.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Samsung.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Samsung.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Samsung.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Samsung.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Samsung.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Samsung.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Samsung.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Sanyo.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Sanyo.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Sanyo.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Sanyo.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Sanyo.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sharp.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Sharp.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Sharp.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Sharp.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sharp.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Sharp.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Sharp.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Sharp.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sherwood.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Sherwood.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Sherwood.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Sherwood.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Sony.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Sony.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Sony.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Sony.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Symphony.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Symphony.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Symphony.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Symphony.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Tcl.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Tcl.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Tcl.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Tcl.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Tcl.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Tcl.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Tcl.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Tcl.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Teco.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Teco.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Teco.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Teco.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Teco.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Teco.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Teco.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Teco.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Toshiba.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Toshiba.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Toshiba.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Toshiba.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Toshiba.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Trotec.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Trotec.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Trotec.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Trotec.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Trotec.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Trotec.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Trotec.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Trotec.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Vestel.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Vestel.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Vestel.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Vestel.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Vestel.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Vestel.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Vestel.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Vestel.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Whirlpool.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Whirlpool.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Whirlpool.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Whirlpool.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Whirlpool.h b/lib/IRremoteESP8266-2.7.8.10/src/ir_Whirlpool.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Whirlpool.h rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Whirlpool.h diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Whynter.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Whynter.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Whynter.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Whynter.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/ir_Zepeal.cpp b/lib/IRremoteESP8266-2.7.8.10/src/ir_Zepeal.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/ir_Zepeal.cpp rename to lib/IRremoteESP8266-2.7.8.10/src/ir_Zepeal.cpp diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/README.md b/lib/IRremoteESP8266-2.7.8.10/src/locale/README.md similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/README.md rename to lib/IRremoteESP8266-2.7.8.10/src/locale/README.md diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/de-CH.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/de-CH.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/de-CH.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/de-CH.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/de-DE.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/de-DE.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/de-DE.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/de-DE.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/defaults.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/defaults.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/defaults.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/defaults.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/en-AU.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/en-AU.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/en-AU.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/en-AU.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/en-IE.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/en-IE.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/en-IE.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/en-IE.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/en-UK.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/en-UK.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/en-UK.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/en-UK.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/en-US.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/en-US.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/en-US.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/en-US.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/es-ES.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/es-ES.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/es-ES.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/es-ES.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/fr-FR.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/fr-FR.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/fr-FR.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/fr-FR.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/it-IT.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/it-IT.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/it-IT.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/it-IT.h diff --git a/lib/IRremoteESP8266-2.7.8/src/locale/zh-CN.h b/lib/IRremoteESP8266-2.7.8.10/src/locale/zh-CN.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/src/locale/zh-CN.h rename to lib/IRremoteESP8266-2.7.8.10/src/locale/zh-CN.h diff --git a/lib/IRremoteESP8266-2.7.8/test/IRac_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/IRac_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/IRac_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/IRac_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/IRrecv_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/IRrecv_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/IRrecv_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/IRrecv_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/IRrecv_test.h b/lib/IRremoteESP8266-2.7.8.10/test/IRrecv_test.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/IRrecv_test.h rename to lib/IRremoteESP8266-2.7.8.10/test/IRrecv_test.h diff --git a/lib/IRremoteESP8266-2.7.8/test/IRsend_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/IRsend_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/IRsend_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/IRsend_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/IRsend_test.h b/lib/IRremoteESP8266-2.7.8.10/test/IRsend_test.h similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/IRsend_test.h rename to lib/IRremoteESP8266-2.7.8.10/test/IRsend_test.h diff --git a/lib/IRremoteESP8266-2.7.8/test/IRutils_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/IRutils_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/IRutils_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/IRutils_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/Makefile b/lib/IRremoteESP8266-2.7.8.10/test/Makefile similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/Makefile rename to lib/IRremoteESP8266-2.7.8.10/test/Makefile diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Airwell_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Airwell_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Airwell_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Airwell_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Aiwa_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Aiwa_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Aiwa_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Aiwa_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Amcor_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Amcor_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Amcor_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Amcor_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Argo_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Argo_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Argo_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Argo_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Carrier_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Carrier_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Carrier_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Carrier_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Coolix_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Coolix_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Coolix_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Coolix_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Corona_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Corona_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Corona_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Corona_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Daikin_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Daikin_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Daikin_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Daikin_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Delonghi_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Delonghi_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Delonghi_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Delonghi_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Denon_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Denon_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Denon_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Denon_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Dish_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Dish_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Dish_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Dish_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Doshisha_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Doshisha_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Doshisha_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Doshisha_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Electra_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Electra_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Electra_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Electra_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Epson_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Epson_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Epson_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Epson_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Fujitsu_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Fujitsu_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Fujitsu_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Fujitsu_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_GICable_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_GICable_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_GICable_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_GICable_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_GlobalCache_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_GlobalCache_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_GlobalCache_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_GlobalCache_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Goodweather_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Goodweather_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Goodweather_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Goodweather_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Gree_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Gree_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Gree_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Gree_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Haier_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Haier_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Haier_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Haier_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Hitachi_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Hitachi_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Hitachi_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Hitachi_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Inax_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Inax_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Inax_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Inax_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_JVC_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_JVC_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_JVC_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_JVC_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Kelvinator_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Kelvinator_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Kelvinator_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Kelvinator_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_LG_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_LG_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_LG_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_LG_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Lasertag_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Lasertag_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Lasertag_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Lasertag_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Lego_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Lego_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Lego_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Lego_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Lutron_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Lutron_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Lutron_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Lutron_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_MWM_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_MWM_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_MWM_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_MWM_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Magiquest_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Magiquest_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Magiquest_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Magiquest_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Midea_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Midea_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Midea_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Midea_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_MitsubishiHeavy_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_MitsubishiHeavy_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_MitsubishiHeavy_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_MitsubishiHeavy_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Mitsubishi_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Mitsubishi_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Mitsubishi_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Mitsubishi_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Multibrackets_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Multibrackets_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Multibrackets_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Multibrackets_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_NEC_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_NEC_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_NEC_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_NEC_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Neoclima_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Neoclima_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Neoclima_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Neoclima_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Nikai_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Nikai_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Nikai_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Nikai_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Panasonic_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Panasonic_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Panasonic_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Panasonic_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Pioneer_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Pioneer_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Pioneer_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Pioneer_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Pronto_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Pronto_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Pronto_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Pronto_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_RC5_RC6_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_RC5_RC6_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_RC5_RC6_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_RC5_RC6_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_RCMM_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_RCMM_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_RCMM_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_RCMM_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Samsung_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Samsung_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Samsung_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Samsung_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Sanyo_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Sanyo_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Sanyo_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Sanyo_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Sharp_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Sharp_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Sharp_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Sharp_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Sherwood_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Sherwood_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Sherwood_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Sherwood_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Sony_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Sony_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Sony_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Sony_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Symphony_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Symphony_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Symphony_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Symphony_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Tcl_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Tcl_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Tcl_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Tcl_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Teco_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Teco_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Teco_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Teco_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Toshiba_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Toshiba_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Toshiba_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Toshiba_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Trotec_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Trotec_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Trotec_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Trotec_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Vestel_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Vestel_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Vestel_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Vestel_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Whirlpool_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Whirlpool_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Whirlpool_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Whirlpool_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Whynter_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Whynter_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Whynter_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Whynter_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/test/ir_Zepeal_test.cpp b/lib/IRremoteESP8266-2.7.8.10/test/ir_Zepeal_test.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/test/ir_Zepeal_test.cpp rename to lib/IRremoteESP8266-2.7.8.10/test/ir_Zepeal_test.cpp diff --git a/lib/IRremoteESP8266-2.7.8/tools/Makefile b/lib/IRremoteESP8266-2.7.8.10/tools/Makefile similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/Makefile rename to lib/IRremoteESP8266-2.7.8.10/tools/Makefile diff --git a/lib/IRremoteESP8266-2.7.8/tools/RawToGlobalCache.sh b/lib/IRremoteESP8266-2.7.8.10/tools/RawToGlobalCache.sh old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/RawToGlobalCache.sh rename to lib/IRremoteESP8266-2.7.8.10/tools/RawToGlobalCache.sh diff --git a/lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data.py b/lib/IRremoteESP8266-2.7.8.10/tools/auto_analyse_raw_data.py old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data.py rename to lib/IRremoteESP8266-2.7.8.10/tools/auto_analyse_raw_data.py diff --git a/lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data_test.py b/lib/IRremoteESP8266-2.7.8.10/tools/auto_analyse_raw_data_test.py old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/auto_analyse_raw_data_test.py rename to lib/IRremoteESP8266-2.7.8.10/tools/auto_analyse_raw_data_test.py diff --git a/lib/IRremoteESP8266-2.7.8/tools/gc_decode.cpp b/lib/IRremoteESP8266-2.7.8.10/tools/gc_decode.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/gc_decode.cpp rename to lib/IRremoteESP8266-2.7.8.10/tools/gc_decode.cpp diff --git a/lib/IRremoteESP8266-2.7.8/tools/generate_irtext_h.sh b/lib/IRremoteESP8266-2.7.8.10/tools/generate_irtext_h.sh old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/generate_irtext_h.sh rename to lib/IRremoteESP8266-2.7.8.10/tools/generate_irtext_h.sh diff --git a/lib/IRremoteESP8266-2.7.8/tools/mkkeywords b/lib/IRremoteESP8266-2.7.8.10/tools/mkkeywords old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/mkkeywords rename to lib/IRremoteESP8266-2.7.8.10/tools/mkkeywords diff --git a/lib/IRremoteESP8266-2.7.8/tools/mode2_decode.cpp b/lib/IRremoteESP8266-2.7.8.10/tools/mode2_decode.cpp similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/mode2_decode.cpp rename to lib/IRremoteESP8266-2.7.8.10/tools/mode2_decode.cpp diff --git a/lib/IRremoteESP8266-2.7.8/tools/raw_to_pronto_code.py b/lib/IRremoteESP8266-2.7.8.10/tools/raw_to_pronto_code.py old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/raw_to_pronto_code.py rename to lib/IRremoteESP8266-2.7.8.10/tools/raw_to_pronto_code.py diff --git a/lib/IRremoteESP8266-2.7.8/tools/raw_to_pronto_code_test.py b/lib/IRremoteESP8266-2.7.8.10/tools/raw_to_pronto_code_test.py old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/raw_to_pronto_code_test.py rename to lib/IRremoteESP8266-2.7.8.10/tools/raw_to_pronto_code_test.py diff --git a/lib/IRremoteESP8266-2.7.8/tools/scrape_supported_devices.py b/lib/IRremoteESP8266-2.7.8.10/tools/scrape_supported_devices.py old mode 100755 new mode 100644 similarity index 100% rename from lib/IRremoteESP8266-2.7.8/tools/scrape_supported_devices.py rename to lib/IRremoteESP8266-2.7.8.10/tools/scrape_supported_devices.py diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 0f13cfe48..d61be6e00 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -3,6 +3,7 @@ ### 8.3.1.7 20200716 - Remove Arduino ESP8266 Core support for versions before 2.7.1 +- Change IRRemoteESP8266 library to v2.7.8.10, fixing Samsung and Pioneer protocols (#8938) - Change to limited support of Arduino IDE as an increasing amount of features cannot be compiled with Arduino IDE - Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message - Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` @@ -13,7 +14,6 @@ - Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 - Add command (``S``)``SerialSend6`` \ (#8937) - Add support for Sonoff Zigbee Bridge as module 75 (#8583) -- Change IRRemoteESP8266 IR lib to pre-2.7.9, fixing Samsung and Pioneer protocols (#8938) ### 8.3.1.6 20200617 @@ -79,8 +79,6 @@ - Add support for VEML6075 UVA/UVB/UVINDEX Sensor by device111 (#8432) - Add support for VEML7700 Ambient light intensity Sensor by device111 (#8432) -## Released - ### 8.3.1 20200518 - Release Fred @@ -97,8 +95,6 @@ - Change Quick Power Cycle detection from 4 to 7 power interrupts (#4066) - Fix default state of ``SetOption73 0`` for button decoupling and send multi-press and hold MQTT messages -## Released - ### 8.3.0 20200514 - Release Fred @@ -183,8 +179,6 @@ - Add support for unreachable (unplugged) Zigbee devices in Philips Hue emulation and Alexa - Add support for 64x48 SSD1306 OLED (#6740) -## Released - ### 8.2.0 20200321 - Release Elliot From e6cf1ef5764708b5681f11b353be46daaed74292 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Wed, 29 Jul 2020 15:17:15 +0200 Subject: [PATCH 67/91] changed some comments... and redundant entry --- platformio.ini | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/platformio.ini b/platformio.ini index b0b047144..f48ab0039 100644 --- a/platformio.ini +++ b/platformio.ini @@ -83,7 +83,7 @@ extra_scripts = pio/strip-floats.py pio/override_copy.py [esp_defaults] -; *** Fix espressif8266@1.7.0 induced undesired all warnings +; *** remove undesired all warnings build_unflags = -Wall build_flags = -D_IR_ENABLE_DEFAULT_=false -DDECODE_HASH=true -DDECODE_NEC=true -DSEND_NEC=true @@ -107,11 +107,8 @@ build_flags = ${esp_defaults.build_flags} ; lwIP 2 - Higher Bandwidth no Features -DPIO_FRAMEWORK_ARDUINO_LWIP2_HIGHER_BANDWIDTH_LOW_FLASH ; VTABLES in Flash - -DVTABLES_IN_FLASH - ; No exception code in firmware - -fno-exceptions - -lstdc++ - ; the following removes the 4-bytes alignment for PSTR() + -DVTABLES_IN_FLASH + ; remove the 4-bytes alignment for PSTR() -DPSTR_ALIGN=1 ; restrict to minimal mime-types -DMIMETYPE_MINIMAL @@ -123,7 +120,7 @@ build_flags = -DUSE_IR_REMOTE_FULL [core] -; *** Esp8266 Tasmota modified Arduino core based on core 2.7.2 +; *** Esp8266 Tasmota modified Arduino core based on core 2.7.3 platform = espressif8266@2.5.1 platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.2/esp8266-2.7.3.2.zip build_unflags = ${esp_defaults.build_unflags} From 70c7f38a1f4d7cb4fbea05f1483770c4348da5f4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 29 Jul 2020 16:58:07 +0200 Subject: [PATCH 68/91] Release 8.4.0 --- FIRMWARE.md | 2 +- README.md | 2 +- RELEASENOTES.md | 55 +-------------------------------------- tasmota/CHANGELOG.md | 7 ++++- tasmota/tasmota_version.h | 2 +- 5 files changed, 10 insertions(+), 58 deletions(-) diff --git a/FIRMWARE.md b/FIRMWARE.md index d66bd1ba1..9f05223e8 100644 --- a/FIRMWARE.md +++ b/FIRMWARE.md @@ -18,7 +18,7 @@ See [CHANGELOG.md](https://github.com/arendst/Tasmota/blob/development/tasmota/C ## Development -[![Dev Version](https://img.shields.io/badge/development%20version-v8.3.x.x-blue.svg)](https://github.com/arendst/Tasmota) +[![Dev Version](https://img.shields.io/badge/development%20version-v8.4.x.x-blue.svg)](https://github.com/arendst/Tasmota) [![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://thehackbox.org/tasmota/) [![Tasmota CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+CI%22) [![Tasmota ESP32 CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20ESP32%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+ESP32+CI%22) diff --git a/README.md b/README.md index 97413616e..0bdf2a9e9 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ In addition to the [release webpage](https://github.com/arendst/Tasmota/releases ## Development -[![Dev Version](https://img.shields.io/badge/development%20version-v8.3.x.x-blue.svg)](https://github.com/arendst/Tasmota) +[![Dev Version](https://img.shields.io/badge/development%20version-v8.4.x.x-blue.svg)](https://github.com/arendst/Tasmota) [![Download Dev](https://img.shields.io/badge/download-development-yellow.svg)](http://thehackbox.org/tasmota/) [![Tasmota CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+CI%22) [![Tasmota ESP32 CI](https://github.com/arendst/Tasmota/workflows/Tasmota%20ESP32%20CI/badge.svg)](https://github.com/arendst/Tasmota/actions?query=workflow%3A%22Tasmota+ESP32+CI%22) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 565f9fc53..ae3820c55 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -53,57 +53,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog -### Version 8.3.1.7 - -- Remove Arduino ESP8266 Core support for versions before 2.7.1 -- Change to limited support of Arduino IDE as an increasing amount of features cannot be compiled with Arduino IDE -- Change IRRemoteESP8266 library from v2.7.6 to v2.7.8.10, fixing Samsung and Pioneer protocols (#8938) -- Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519) -- Change Energy JSON Total field from ``"Total":[33.736,11.717,16.978]`` to ``"Total":33.736,"TotalTariff":[11.717,16.978]`` -- Change Energy JSON ExportActive field from ``"ExportActive":[33.736,11.717,16.978]`` to ``"ExportActive":33.736,"ExportTariff":[11.717,16.978]`` -- Change ESP32 USER GPIO template representation decreasing template message size -- Change define USE_TASMOTA_SLAVE into USE_TASMOTA_CLIENT -- Change commands ``SlaveSend`` and ``SlaveReset`` into ``ClientSend`` and ``ClientReset`` -- Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message -- Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` -- Change Zigbee randomizing of parameters at first run or after Reset -- Fix escape of non-JSON received serial data (#8329) -- Fix exception or watchdog on rule re-entry (#8757) -- Add command ``Rule0`` to change global rule parameters -- Add command ``Time 4`` to display timestamp using milliseconds (#8537) -- Add command ``SetOption94 0/1`` to select MAX31855 or MAX6675 thermocouple support (#8616) -- Add command ``SetOption97 0/1`` to switch between Tuya serial speeds 9600 bps (0) or 115200 bps (1) -- Add command ``SetOption98 0/1`` to provide rotary rule triggers (1) instead of controlling light (0) -- Add command ``SetOption99 0/1`` to enable zero cross detection on PWM dimmer -- Add command ``SetOption100 0/1`` to remove Zigbee ``ZbReceived`` value from ``{"ZbReceived":{xxx:yyy}}`` JSON message -- Add command ``SetOption101 0/1`` to add the Zigbee source endpoint as suffix to attributes, ex `Power3` instead of `Power` if sent from endpoint 3 -- Add command ``DzSend ,`` to send values or state to Domoticz -- Add command ``Module2`` to configure fallback module on fast reboot (#8464) -- Add command (``S``)``SerialSend6`` \ (#8937) -- Add commands ``LedPwmOn 0..255``, ``LedPwmOff 0..255`` and ``LedPwmMode1 0/1`` to control led brightness by George (#8491) -- Add ESP32 ethernet commands ``EthType 0/1``, ``EthAddress 0..31`` and ``EthClockMode 0..3`` -- Add more functionality to command ``Switchmode`` 11 and 12 (#8450) -- Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet -- Add support for unique MQTTClient (and inherited fallback topic) by full Mac address using ``mqttclient DVES_%12X`` (#8300) -- Add wildcard pattern ``?`` for JSON matching in rules -- Add Three Phase Export Active Energy to SDM630 driver -- Add Zigbee options to ``ZbSend`` to write and report attributes -- Add Zigbee auto-responder for common attributes -- Add ``CpuFrequency`` to ``status 2`` -- Add ``FlashFrequency`` to ``status 4`` -- Add compile time interlock parameters (#8759) -- Add compile time user template (#8766) -- Add support for VEML6075 UVA/UVB/UVINDEX Sensor by device111 (#8432) -- Add support for VEML7700 Ambient light intensity Sensor by device111 (#8432) -- Add support for up to two BH1750 sensors controlled by commands ``BH1750Resolution`` and ``BH1750MTime`` (#8139) -- Add support for up to eight MCP9808 temperature sensors by device111 (#8594) -- Add support for BL0940 energy monitor as used in Blitzwolf BW-SHP10 (#8175) -- Add support for Telegram bot (#8619) -- Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638) -- Add support for Energy sensor (Denky) for French Smart Metering meter provided by global Energy Providers, need a adaptater. See dedicated full [blog](http://hallard.me/category/tinfo/) about French teleinformation stuff -- Add support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON -- Add support for single wire LMT01 temperature Sensor by justifiably (#8713) -- Add support for rotary encoder as light dimmer and optional color temperature if button1 still pressed (#8670) -- Add support for switches/relays using an AC detection circuitry e.g. MOES MS-104B or BlitzWolf SS5 (#8606) -- Add support for Schneider Electric iEM3000 series Modbus energy meter by Marius Bezuidenhout -- Add support for Sonoff Zigbee Bridge as module 75 (#8583) +### Version 8.4.0.1 diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index d61be6e00..f42ee4ca1 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -1,9 +1,14 @@ ## Unreleased (development) +### 8.4.0.1 20200730 + +### 8.4.0 20200730 + +- Release George + ### 8.3.1.7 20200716 - Remove Arduino ESP8266 Core support for versions before 2.7.1 -- Change IRRemoteESP8266 library to v2.7.8.10, fixing Samsung and Pioneer protocols (#8938) - Change to limited support of Arduino IDE as an increasing amount of features cannot be compiled with Arduino IDE - Change all timer references from ``Arm`` to ``Enable`` in GUI, ``Timer`` command and JSON message - Change Domoticz commands prefix from ``Domoticz`` to ``Dz`` diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index 23105273e..308601067 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,7 +20,7 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x08030107; +const uint32_t VERSION = 0x08040001; // Lowest compatible version const uint32_t VERSION_COMPATIBLE = 0x07010006; From 3b7305f20c0cd86b43ea48a6cb19553ccfc46694 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 30 Jul 2020 13:41:51 +0200 Subject: [PATCH 69/91] Add changes from https://github.com/esp8266/Arduino/commit/a6798691 to be compatible with Arduino master. --- tasmota/core_esp8266_wiring_pwm.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tasmota/core_esp8266_wiring_pwm.cpp b/tasmota/core_esp8266_wiring_pwm.cpp index d81928a5d..d879a0001 100644 --- a/tasmota/core_esp8266_wiring_pwm.cpp +++ b/tasmota/core_esp8266_wiring_pwm.cpp @@ -29,15 +29,21 @@ extern "C" { static uint32_t analogMap = 0; -static int32_t analogScale = PWMRANGE; +static int32_t analogScale = 255; // Match upstream default, breaking change from 2.x.x static uint16_t analogFreq = 1000; extern void __analogWriteRange(uint32_t range) { - if (range > 0) { + if ((range >= 15) && (range <= 65535)) { analogScale = range; } } +extern void __analogWriteResolution(int res) { + if ((res >= 4) && (res <= 16)) { + analogScale = (1 << res) - 1; + } +} + extern void __analogWriteFreq(uint32_t freq) { if (freq < 40) { analogFreq = 40; @@ -61,6 +67,10 @@ extern void __analogWrite(uint8_t pin, int val) { val = analogScale; } + // Per the Arduino docs at https://www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/ + // val: the duty cycle: between 0 (always off) and 255 (always on). + // So if val = 0 we have digitalWrite(LOW), if we have val==range we have digitalWrite(HIGH) + if (analogMap & 1UL << pin) { analogMap &= ~(1 << pin); } @@ -79,6 +89,7 @@ extern void __analogWrite(uint8_t pin, int val) { extern void analogWrite(uint8_t pin, int val) __attribute__((weak, alias("__analogWrite"))); extern void analogWriteFreq(uint32_t freq) __attribute__((weak, alias("__analogWriteFreq"))); extern void analogWriteRange(uint32_t range) __attribute__((weak, alias("__analogWriteRange"))); +extern void analogWriteResolution(int res) __attribute__((weak, alias("__analogWriteResolution"))); }; From 0c25c4c97c0090199c3c4a4d1fc961533255df6a Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 30 Jul 2020 14:53:07 +0200 Subject: [PATCH 70/91] Use latest Platformio 2.6.1... for the buildchain. Tasmota core 2.7.3.2 is on top and still used! --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index f48ab0039..4b7101d4d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -121,7 +121,7 @@ build_flags = -DUSE_IR_REMOTE_FULL [core] ; *** Esp8266 Tasmota modified Arduino core based on core 2.7.3 -platform = espressif8266@2.5.1 +platform = espressif8266@2.6.1 platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.2/esp8266-2.7.3.2.zip build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} From c87acfd08cd88292b92b137cedc4e52c27098d81 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Thu, 30 Jul 2020 14:55:31 +0200 Subject: [PATCH 71/91] use platformio 2.6.1 for the buildchain. Tasmota core 2.7.3.2 is on top and still used! --- platformio_override_sample.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 5ea714612..8d6ac6341 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -88,7 +88,7 @@ extra_scripts = ${scripts_defaults.extra_scripts} [tasmota_stage] ; *** Esp8266 core for Arduino version Tasmota stage -platform = espressif8266@2.5.1 +platform = espressif8266@2.6.1 platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.2/esp8266-2.7.3.2.zip build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} From cd6de24f14186ee07daa7a308e42dc2984d719f0 Mon Sep 17 00:00:00 2001 From: Norbert Richter Date: Thu, 30 Jul 2020 18:10:29 +0200 Subject: [PATCH 72/91] Fix ShutterStopToggleDir init --- tasmota/xdrv_27_shutter.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/tasmota/xdrv_27_shutter.ino b/tasmota/xdrv_27_shutter.ino index 15d5143f1..8bf783680 100644 --- a/tasmota/xdrv_27_shutter.ino +++ b/tasmota/xdrv_27_shutter.ino @@ -238,6 +238,7 @@ void ShutterInit(void) //Shutter.real_position[i] = Settings.shutter_position[i] <= 5 ? Settings.shuttercoeff[2][i] * Settings.shutter_position[i] : Settings.shuttercoeff[1][i] * Settings.shutter_position[i] + Settings.shuttercoeff[0,i]; Shutter.start_position[i] = Shutter.target_position[i] = Shutter.real_position[i]; Shutter.motordelay[i] = Settings.shutter_motordelay[i]; + Shutter.lastdirection[i] = (50 < Settings.shutter_position[i]) ? 1 : -1; char shutter_open_chr[10]; dtostrfd((float)Shutter.open_time[i] / 10 , 1, shutter_open_chr); From 6aee706f01a352fb7d20edb299183c43aa561ee4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 31 Jul 2020 11:35:26 +0200 Subject: [PATCH 73/91] Fix ESP32 Zigbee compilation --- tasmota/xdrv_01_webserver.ino | 4 ++++ tasmota/xdrv_23_zigbee_A_impl.ino | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 1f878ae6b..016240b35 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -2711,7 +2711,11 @@ void HandleUploadLoop(void) } else { #if defined(USE_ZIGBEE) && defined(USE_ZIGBEE_EZSP) +#ifdef ESP8266 if ((SONOFF_ZB_BRIDGE == my_module_type) && (upload.buf[0] == 0xEB)) { // Check if this is a Zigbee bridge FW file +#else // ESP32 + if (PinUsed(GPIO_ZIGBEE_RX) && PinUsed(GPIO_ZIGBEE_TX) && (upload.buf[0] == 0xEB)) { // Check if this is a Zigbee bridge FW file +#endif // ESP8266 or ESP32 Update.end(); // End esp8266 update session Web.upload_file_type = UPL_EFR32; diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index f48258031..12dc7c0ea 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -62,8 +62,12 @@ void ZigbeeInit(void) AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_ZIGBEE "Randomizing Zigbee parameters, please check with 'ZbConfig'")); uint64_t mac64 = 0; // stuff mac address into 64 bits WiFi.macAddress((uint8_t*) &mac64); - uint32_t esp_id = ESP.getChipId(); - uint32_t flash_id = ESP.getFlashChipId(); + uint32_t esp_id = ESP_getChipId(); +#ifdef ESP8266 + uint32_t flash_id = ESP.getFlashChipIdd(); +#else // ESP32 + uint32_t flash_id = 0; +#endif // ESP8266 or ESP32 uint16_t pan_id = (mac64 & 0x3FFF); if (0x0000 == pan_id) { pan_id = 0x0001; } // avoid extreme values From feb5ffc3ddfb819a5a64ed2cde35658bb1e2c3e3 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 31 Jul 2020 11:37:12 +0200 Subject: [PATCH 74/91] Oops broke esp8266 compile. Fixed --- tasmota/xdrv_23_zigbee_A_impl.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 12dc7c0ea..076ed7d4a 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -64,7 +64,7 @@ void ZigbeeInit(void) WiFi.macAddress((uint8_t*) &mac64); uint32_t esp_id = ESP_getChipId(); #ifdef ESP8266 - uint32_t flash_id = ESP.getFlashChipIdd(); + uint32_t flash_id = ESP.getFlashChipId(); #else // ESP32 uint32_t flash_id = 0; #endif // ESP8266 or ESP32 From a5857ac03fcb182fb68bcea81c273219483d7346 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 31 Jul 2020 11:53:12 +0200 Subject: [PATCH 75/91] Add masterlog_level to control master log level control --- tasmota/support.ino | 3 ++- tasmota/tasmota.ino | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tasmota/support.ino b/tasmota/support.ino index 2e36793b0..169bf2005 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1784,8 +1784,9 @@ void Syslog(void) void AddLog(uint32_t loglevel) { - char mxtime[10]; // "13:45:21 " + if ((masterlog_level > 0) && (loglevel < masterlog_level)) { return; } + char mxtime[10]; // "13:45:21 " snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d "), RtcTime.hour, RtcTime.minute, RtcTime.second); if (loglevel <= seriallog_level) { diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 43e019e33..0fca0cddc 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -144,6 +144,7 @@ uint8_t light_type = 0; // Light types uint8_t serial_in_byte; // Received byte uint8_t ota_retry_counter = OTA_ATTEMPTS; // OTA retry counter uint8_t devices_present = 0; // Max number of devices supported +uint8_t masterlog_level = 0; // Master log level used to override set log level uint8_t seriallog_level; // Current copy of Settings.seriallog_level uint8_t syslog_level; // Current copy of Settings.syslog_level uint8_t my_module_type; // Current copy of Settings.module or user template type From 317d4977d1fed72cb1f356d63fde9e8cec1e30be Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Fri, 31 Jul 2020 16:56:42 +0200 Subject: [PATCH 76/91] Fix masterlog_level to control master log level control --- tasmota/support.ino | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tasmota/support.ino b/tasmota/support.ino index 169bf2005..92ab14a99 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -1784,16 +1784,17 @@ void Syslog(void) void AddLog(uint32_t loglevel) { - if ((masterlog_level > 0) && (loglevel < masterlog_level)) { return; } - char mxtime[10]; // "13:45:21 " snprintf_P(mxtime, sizeof(mxtime), PSTR("%02d" D_HOUR_MINUTE_SEPARATOR "%02d" D_MINUTE_SECOND_SEPARATOR "%02d "), RtcTime.hour, RtcTime.minute, RtcTime.second); - if (loglevel <= seriallog_level) { + if ((loglevel <= seriallog_level) && + (masterlog_level <= seriallog_level)) { Serial.printf("%s%s\r\n", mxtime, log_data); } #ifdef USE_WEBSERVER - if (Settings.webserver && (loglevel <= Settings.weblog_level)) { + if (Settings.webserver && + (loglevel <= Settings.weblog_level) && + (masterlog_level <= Settings.weblog_level)) { // Delimited, zero-terminated buffer of log lines. // Each entry has this format: [index][log data]['\1'] web_log_index &= 0xFF; @@ -1814,10 +1815,12 @@ void AddLog(uint32_t loglevel) #endif // USE_WEBSERVER if (Settings.flag.mqtt_enabled && // SetOption3 - Enable MQTT !global_state.mqtt_down && - (loglevel <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); } + (loglevel <= Settings.mqttlog_level) && + (masterlog_level <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); } if (!global_state.network_down && - (loglevel <= syslog_level)) { Syslog(); } + (loglevel <= syslog_level) && + (masterlog_level <= syslog_level)) { Syslog(); } prepped_loglevel = 0; } From f1bea6b3634f9e3b11f853a60924361d457ebb32 Mon Sep 17 00:00:00 2001 From: Stephan Hadinger Date: Sat, 1 Aug 2020 18:52:04 +0200 Subject: [PATCH 77/91] Add Zigbee better support for IKEA Motion Sensor --- tasmota/CHANGELOG.md | 2 ++ tasmota/xdrv_23_zigbee_0_constants.ino | 2 ++ tasmota/xdrv_23_zigbee_5_converters.ino | 2 ++ tasmota/xdrv_23_zigbee_6_commands.ino | 22 ++++++++++++++++++++-- tasmota/xdrv_23_zigbee_7_statemachine.ino | 2 ++ tasmota/xdrv_23_zigbee_A_impl.ino | 2 ++ 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index f42ee4ca1..237d131b3 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -2,6 +2,8 @@ ### 8.4.0.1 20200730 +- Add Zigbee better support for IKEA Motion Sensor + ### 8.4.0 20200730 - Release George diff --git a/tasmota/xdrv_23_zigbee_0_constants.ino b/tasmota/xdrv_23_zigbee_0_constants.ino index 62b3652af..5ebd66087 100644 --- a/tasmota/xdrv_23_zigbee_0_constants.ino +++ b/tasmota/xdrv_23_zigbee_0_constants.ino @@ -26,6 +26,8 @@ #error "You must select one of: #define USE_ZIGBEE_ZNP or #define USE_ZIGBEE_EZSP" #endif +// #define USE_ZIGBEE_NO_READ_ATTRIBUTES // disable automatic READ ATTRIBUTES generated by Z2T - for debugging only + #define OCCUPANCY "Occupancy" // global define for Aqara #define ZIGBEE_EZSP_RESET_LED 4 // Led number to drive the EZSP Reset pin diff --git a/tasmota/xdrv_23_zigbee_5_converters.ino b/tasmota/xdrv_23_zigbee_5_converters.ino index 454e9b5cf..aa9d7513f 100644 --- a/tasmota/xdrv_23_zigbee_5_converters.ino +++ b/tasmota/xdrv_23_zigbee_5_converters.ino @@ -1158,7 +1158,9 @@ void ZCLFrame::parseResponse(void) { // Parse non-normalized attributes void ZCLFrame::parseClusterSpecificCommand(JsonObject& json, uint8_t offset) { convertClusterSpecific(json, _cluster_id, _cmd_id, _frame_control.b.direction, _srcaddr, _srcendpoint, _payload); +#ifndef USE_ZIGBEE_NO_READ_ATTRIBUTES // read attributes unless disabled sendHueUpdate(_srcaddr, _groupaddr, _cluster_id, _cmd_id, _frame_control.b.direction); +#endif } // ====================================================================== diff --git a/tasmota/xdrv_23_zigbee_6_commands.ino b/tasmota/xdrv_23_zigbee_6_commands.ino index c2ea81765..39da3049b 100644 --- a/tasmota/xdrv_23_zigbee_6_commands.ino +++ b/tasmota/xdrv_23_zigbee_6_commands.ino @@ -56,8 +56,8 @@ ZF(ColorTempStep) ZF(ColorTempStepUp) ZF(ColorTempStepDown) ZF(ArrowClick) ZF(ArrowHold) ZF(ArrowRelease) ZF(ZoneStatusChange) ZF(xxxx00) ZF(xxxx) ZF(01xxxx) ZF(03xxxx) ZF(00) ZF(01) ZF() ZF(xxxxyy) ZF(00190200) ZF(01190200) ZF(xxyyyy) ZF(xx) -ZF(xx000A00) ZF(xx0A00) ZF(xxyy0A00) ZF(xxxxyyyy0A00) ZF(xxxx0A00) ZF(xx0A) -ZF(xx190A00) ZF(xx19) ZF(xx190A) ZF(xxxxyyyy) ZF(xxxxyyzz) ZF(xxyyzzzz) ZF(xxyyyyzz) +ZF(xx000A00) ZF(xx0A00) ZF(xxyy0A00) ZF(xxxxyyyy0A00) ZF(xxxx0A00) ZF(xx0A) ZF(xxyy) +ZF(xx190A00) ZF(xx19) ZF(xx190A) ZF(xxxxyyyy) ZF(xxxxyyzz) ZF(xxyyzzzz) ZF(xxyyyyzz) ZF(xxyyyyzzzz) ZF(01xxxx000000000000) ZF(03xxxx000000000000) ZF(00xxxx000000000000) ZF(xxyyyy000000000000) ZF(00xx0A00) ZF(01xx0A00) ZF(03xx0A00) ZF(01xxxx0A0000000000) ZF(03xxxx0A0000000000) ZF(xxyyyy0A0000000000) @@ -84,6 +84,9 @@ const Z_CommandConverter Z_Commands[] PROGMEM = { { Z(RecallScene), 0x0005, 0x05, 0x01, Z(xxxxyy) }, { Z(GetSceneMembership),0x0005, 0x06, 0x01, Z(xxxx) }, // Light & Shutter commands + { Z(Power), 0x0006, 0x40, 0x81, Z(xxyy) }, // Power Off With Effect + { Z(Power), 0x0006, 0x41, 0x81, Z() }, // Power On With Recall Global Scene + { Z(Power), 0x0006, 0x42, 0x81, Z(xxyyyyzzzz) }, // Power On with Timed Off { Z(Power), 0x0006, 0xFF, 0x01, Z() }, // 0=Off, 1=On, 2=Toggle { Z(Dimmer), 0x0008, 0x04, 0x01, Z(xx0A00) }, // Move to Level with On/Off, xx=0..254 (255 is invalid) { Z(DimmerUp), 0x0008, 0x06, 0x01, Z(00190200) }, // Step up by 10%, 0.2 secs @@ -464,6 +467,21 @@ void convertClusterSpecific(JsonObject& json, uint16_t cluster, uint8_t cmd, boo json[F("GroupId")] = xyz.z; String scene_payload = json[attrid_str]; json[F("ScenePayload")] = scene_payload.substring(8); // remove first 8 characters + } else if ((cluster == 0x0006) && (cmd == 0x40)) { + // Power Off With Effect + json[command_name] = 0; // always "Power":0 + json[command_name2 + F("Effect")] = xyz.x; + json[command_name2 + F("EffectVariant")] = xyz.y; + } else if ((cluster == 0x0006) && (cmd == 0x41)) { + // Power On With Recall Global Scene + json[command_name] = 1; // always "Power":1 + json[command_name2 + F("RecallGlobalScene")] = true; + } else if ((cluster == 0x0006) && (cmd == 0x42)) { + // Power On With Timed Off Command + json[command_name] = 1; // always "Power":1 + json[command_name2 + F("OnlyWhenOn")] = xyz.x; + json[command_name2 + F("OnTime")] = xyz.y / 10.0f; + json[command_name2 + F("OffWait")] = xyz.z / 10.0f; } } else { // general case bool extended_command = false; // do we send command with endpoint suffix diff --git a/tasmota/xdrv_23_zigbee_7_statemachine.ino b/tasmota/xdrv_23_zigbee_7_statemachine.ino index 784a5ebf3..ce741c027 100644 --- a/tasmota/xdrv_23_zigbee_7_statemachine.ino +++ b/tasmota/xdrv_23_zigbee_7_statemachine.ino @@ -904,7 +904,9 @@ static const Zigbee_Instruction zb_prog[] PROGMEM = { ZI_LOG(LOG_LEVEL_INFO, kZigbeeStarted) ZI_CALL(&Z_State_Ready, 1) // Now accept incoming messages ZI_CALL(&Z_Load_Devices, 0) +#ifndef USE_ZIGBEE_NO_READ_ATTRIBUTES ZI_CALL(&Z_Query_Bulbs, 0) +#endif ZI_LABEL(ZIGBEE_LABEL_MAIN_LOOP) ZI_WAIT_FOREVER() diff --git a/tasmota/xdrv_23_zigbee_A_impl.ino b/tasmota/xdrv_23_zigbee_A_impl.ino index 076ed7d4a..13b7bb749 100644 --- a/tasmota/xdrv_23_zigbee_A_impl.ino +++ b/tasmota/xdrv_23_zigbee_A_impl.ino @@ -179,7 +179,9 @@ void zigbeeZCLSendStr(uint16_t shortaddr, uint16_t groupaddr, uint8_t endpoint, ZigbeeZCLSend_Raw(shortaddr, groupaddr, cluster, endpoint, cmd, clusterSpecific, manuf, buf.getBuffer(), buf.len(), true, zigbee_devices.getNextSeqNumber(shortaddr)); // now set the timer, if any, to read back the state later if (clusterSpecific) { +#ifndef USE_ZIGBEE_NO_READ_ATTRIBUTES // read back attribute value unless it is disabled zigbeeSetCommandTimer(shortaddr, groupaddr, cluster, endpoint); +#endif } } From 6323e777a0bdcaff754e6f2c01723f1cdddd2027 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Sun, 2 Aug 2020 07:35:25 +0200 Subject: [PATCH 78/91] scripter display dump --- tasmota/support_jpeg.ino | 43 +++++++++++++++ tasmota/xdrv_10_scripter.ino | 104 ++++++++++++++++++++++++++++++----- 2 files changed, 134 insertions(+), 13 deletions(-) diff --git a/tasmota/support_jpeg.ino b/tasmota/support_jpeg.ino index 7e811cd76..e9d0b2813 100644 --- a/tasmota/support_jpeg.ino +++ b/tasmota/support_jpeg.ino @@ -153,5 +153,48 @@ char get_jpeg_size(unsigned char* data, unsigned int data_size, unsigned short * }else{ return false; } //Not a valid SOI header } + #endif // JPEG_PICTS #endif //ESP32 + +#ifdef USE_DISPLAY_DUMP +#define bytesPerPixel 3 +#define fileHeaderSize 14 +#define infoHeaderSize 40 + +void createBitmapFileHeader(uint32_t height, uint32_t width, uint8_t *fileHeader) { + int paddingSize = (4 - (width*bytesPerPixel) % 4) % 4; + + int fileSize = fileHeaderSize + infoHeaderSize + (bytesPerPixel*width+paddingSize) * height; + memset(fileHeader,0,fileHeaderSize); + fileHeader[ 0] = (unsigned char)('B'); + fileHeader[ 1] = (unsigned char)('M'); + fileHeader[ 2] = (unsigned char)(fileSize ); + fileHeader[ 3] = (unsigned char)(fileSize>> 8); + fileHeader[ 4] = (unsigned char)(fileSize>>16); + fileHeader[ 5] = (unsigned char)(fileSize>>24); + fileHeader[10] = (unsigned char)(fileHeaderSize + infoHeaderSize); + +} + +void createBitmapInfoHeader(uint32_t height, uint32_t width, uint8_t *infoHeader ) { + memset(infoHeader,0,infoHeaderSize); + + infoHeader[ 0] = (unsigned char)(infoHeaderSize); + infoHeader[ 4] = (unsigned char)(width ); + infoHeader[ 5] = (unsigned char)(width>> 8); + infoHeader[ 6] = (unsigned char)(width>>16); + infoHeader[ 7] = (unsigned char)(width>>24); + infoHeader[ 8] = (unsigned char)(height ); + infoHeader[ 9] = (unsigned char)(height>> 8); + infoHeader[10] = (unsigned char)(height>>16); + infoHeader[11] = (unsigned char)(height>>24); + infoHeader[12] = (unsigned char)(1); + infoHeader[14] = (unsigned char)(bytesPerPixel*8); + infoHeader[24] = (unsigned char)0x13; // 72 dpi + infoHeader[25] = (unsigned char)0x0b; + infoHeader[28] = (unsigned char)0x13; + infoHeader[29] = (unsigned char)0x0b; + +} +#endif // USE_DISPLAY_DUMP diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 19f24e1aa..5e7fad736 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -388,9 +388,9 @@ WiFiUDP Script_PortUdp; #ifndef USE_DEVICE_GROUPS char * IPAddressToString(const IPAddress& ip_address) { - static char buffer[16]; - sprintf_P(buffer, PSTR("%u.%u.%u.%u"), ip_address[0], ip_address[1], ip_address[2], ip_address[3]); - return buffer; + static char ipbuffer[16]; + sprintf_P(ipbuffer, PSTR("%u.%u.%u.%u"), ip_address[0], ip_address[1], ip_address[2], ip_address[3]); + return ipbuffer; } #endif #endif @@ -5291,6 +5291,23 @@ bool ScriptCommand(void) { execute_script(XdrvMailbox.data); } } + if ('?' == XdrvMailbox.data[0]) { + char *lp=XdrvMailbox.data; + lp++; + while (*lp==' ') lp++; + float fvar; + char str[SCRIPT_MAXSSIZE]; + glob_script_mem.glob_error=0; + GetNumericResult(lp,OPER_EQU,&fvar,0); + if (glob_script_mem.glob_error==1) { + // was string, not number + GetStringResult(lp,OPER_EQU,str,0); + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"script\":{\"%s\":\"%s\"}}"),lp,str); + } else { + dtostrfd(fvar,6,str); + snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"script\":{\"%s\":%s}}"),lp,str); + } + } return serviced; } snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"Free\":%d}"),command, GetStateText(bitRead(Settings.rule_enabled,0)),glob_script_mem.script_size-strlen(glob_script_mem.script_ram)); @@ -5606,32 +5623,54 @@ const char HTTP_SCRIPT_MIMES[] PROGMEM = "Content-type: %s\r\n\r\n"; void ScriptGetSDCard(void) { + if (!HttpCheckPriviledgedAccess()) { return; } String stmp = Webserver->uri(); - char *cp=strstr(stmp.c_str(),"/sdc/"); + char *cp=strstr_P(stmp.c_str(),PSTR("/sdc/")); // if (cp) Serial.printf(">>>%s\n",cp); if (cp) { #ifdef ESP32 - cp+=4 + cp+=4; #else cp+=5; #endif - if (fsp->exists(cp)) { + if (strstr_P(cp,PSTR("scrdmp.bmp"))) { SendFile(cp); return; + } else { + if (fsp->exists(cp)) { + SendFile(cp); + return; + } } } HandleNotFound(); } +extern uint8_t *buffer; + void SendFile(char *fname) { char buff[512]; const char *mime; + uint8_t sflg=0; char *jpg=strstr(fname,".jpg"); if (jpg) { mime="image/jpeg"; } + +#ifdef USE_DISPLAY_DUMP + char *sbmp=strstr_P(fname,PSTR("scrdmp.bmp")); + if (sbmp) { + mime="image/bmp"; + sflg=1; + } +#endif // USE_DISPLAY_DUMP + + char *bmp=strstr(fname,".bmp"); + if (bmp) { + mime="image/bmp"; + } char *html=strstr(fname,".html"); if (html) { mime="text/html"; @@ -5643,18 +5682,57 @@ char buff[512]; WSContentSend_P(HTTP_SCRIPT_MIMES,fname,mime); - - File file=fsp->open(fname,FILE_READ); - uint32_t siz = file.size(); - uint32_t len=sizeof(buff); - while (siz > 0) { + if (sflg) { +#ifdef USE_DISPLAY_DUMP + // screen copy + #define fileHeaderSize 14 + #define infoHeaderSize 40 + if (buffer) { + uint8_t *bp=buffer; + uint8_t *lbuf=(uint8_t*)calloc(Settings.display_width+2,3); + uint8_t *lbp; + uint8_t fileHeader[fileHeaderSize]; + createBitmapFileHeader(Settings.display_height , Settings.display_width , fileHeader); + Webserver->client().write((uint8_t *)fileHeader, fileHeaderSize); + uint8_t infoHeader[infoHeaderSize]; + createBitmapInfoHeader(Settings.display_height, Settings.display_width, infoHeader ); + Webserver->client().write((uint8_t *)infoHeader, infoHeaderSize); + for (uint32_t lins=0; lins>1; + } + bp++; + } + Webserver->client().write((const char*)lbuf, Settings.display_width*3); + } + if (lbuf) free(lbuf); + Webserver->client().stop(); + } +#endif // USE_DISPLAY_DUMP + } else { + File file=fsp->open(fname,FILE_READ); + uint32_t siz = file.size(); + uint32_t len=sizeof(buff); + while (siz > 0) { if (len>siz) len=siz; file.read((uint8_t *)buff,len ); Webserver->client().write((const char*)buff, len); siz -= len; + } + file.close(); } - file.close(); - Webserver->client().stop(); } #endif // USE_SCRIPT_FATFS From 6185941b18313a8763a88efe3c889e8152be53f4 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 2 Aug 2020 11:42:28 +0200 Subject: [PATCH 79/91] Fix display redundant power toggle Fix display redundant power toggle if backlight is configured as PWM --- tasmota/xdrv_13_display.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index d1fc01832..c7e4fb251 100644 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -1268,7 +1268,9 @@ void DisplayInitDriver(void) // AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model); if (Settings.display_model) { - devices_present++; + if (!light_type) { + devices_present++; // If no PWM channel for backlight then use "normal" power control + } disp_device = devices_present; #ifndef USE_DISPLAY_MODES1TO5 From e1b825ed75dd7e488fa816a0f68391b29b08b4b8 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Sun, 2 Aug 2020 12:40:15 +0200 Subject: [PATCH 80/91] Fix ESP32 PWM resolution calculation --- .../src/esp8266toEsp32.h | 64 ++++++++++--------- tasmota/support_tasmota.ino | 8 +-- tasmota/xdrv_04_light.ino | 5 ++ tasmota/xlgt_03_sm16716.ino | 5 ++ 4 files changed, 48 insertions(+), 34 deletions(-) diff --git a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index 90e2460b3..b9876ac15 100644 --- a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -28,16 +28,23 @@ #include +/*********************************************************************************************\ + * ESP32 analogWrite support +\*********************************************************************************************/ -// webcam uses channel 0, so we offset standard PWM -#define PWM_CHANNEL_OFFSET 2 -// Analog +#define PWM_SUPPORTED_CHANNELS 8 +#define PWM_CHANNEL_OFFSET 2 // Webcam uses channel 0, so we offset standard PWM -uint8_t pwm_channel[8]={99,99,99,99,99,99,99,99}; +uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS] = { 99, 99, 99, 99, 99, 99, 99, 99 }; -inline uint32_t pin2chan(uint32_t pin) { - for (uint32_t cnt=0;cnt<8;cnt++) { - if ((pwm_channel[cnt]<99) && (pwm_channel[cnt]==pin)) { +inline void analogWriteFreq(uint32_t freq) { +} +inline void analogWriteRange(uint32_t range) { +} + +inline uint32_t _analog_pin2chan(uint32_t pin) { + for (uint32_t cnt = 0; cnt < PWM_SUPPORTED_CHANNELS; cnt++) { + if ((_pwm_channel[cnt] < 99) && (_pwm_channel[cnt] == pin)) { return cnt; } } @@ -46,43 +53,40 @@ inline uint32_t pin2chan(uint32_t pin) { inline void analogWrite(uint8_t pin, int val) { - uint32_t channel=pin2chan(pin); - ledcWrite(channel+PWM_CHANNEL_OFFSET,val); - //Serial.printf("write %d - %d\n",channel,val); -} - -inline void analogWriteFreq(uint32_t freq) -{ -} -inline void analogWriteRange(uint32_t range) -{ + uint32_t channel = _analog_pin2chan(pin); + ledcWrite(channel + PWM_CHANNEL_OFFSET, val); +// Serial.printf("write %d - %d\n",channel,val); } inline void analogAttach(uint32_t pin, uint32_t channel) { - pwm_channel[channel&7]=pin; - ledcAttachPin(pin,channel+PWM_CHANNEL_OFFSET); - //Serial.printf("attach %d - %d\n",channel,pin); + _pwm_channel[channel &7] = pin; + ledcAttachPin(pin, channel + PWM_CHANNEL_OFFSET); +// Serial.printf("attach %d - %d\n",channel,pin); } -inline uint32_t pow2(uint32_t x) { -uint32_t power = 1,bits=0; +inline uint32_t _analog_pow2(uint32_t x) { + uint32_t power = 1; + uint32_t bits = 0; while (power < x) { - power*=2; + power *= 2; bits++; } - return bits-1; + return bits; } + // input range is in full range, ledc needs bits -inline void analogWriteFreqRange(uint32_t channel,uint32_t freq, uint32_t irange) { - uint32_t range=pow2(irange); - for (uint32_t cnt=0;cnt<8;cnt++) { - if (pwm_channel[cnt]<99) { - ledcSetup(cnt+PWM_CHANNEL_OFFSET,freq,range); +inline void analogWriteFreqRange(uint32_t channel, uint32_t freq, uint32_t irange) { + uint32_t range = _analog_pow2(irange); + for (uint32_t cnt = 0; cnt < PWM_SUPPORTED_CHANNELS; cnt++) { + if (_pwm_channel[cnt] < 99) { + ledcSetup(cnt + PWM_CHANNEL_OFFSET, freq, range); } } - //Serial.printf("freq - range %d - %d\n",freq,range); +// Serial.printf("freq - range %d - %d\n",freq,range); } +/*********************************************************************************************/ + #define INPUT_PULLDOWN_16 INPUT_PULLUP typedef double real64_t; diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 9007d0157..6b0dd6f4e 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1686,12 +1686,12 @@ void GpioInit(void) for (uint32_t i = 0; i < MAX_PWMS; i++) { // Basic PWM control only if (PinUsed(GPIO_PWM1, i)) { +#ifdef ESP8266 pinMode(Pin(GPIO_PWM1, i), OUTPUT); -#ifdef ESP32 - analogAttach(Pin(GPIO_PWM1, i),i); - analogWriteFreqRange(i,Settings.pwm_frequency,Settings.pwm_range); +#else // ESP32 + analogAttach(Pin(GPIO_PWM1, i), i); + analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); #endif - if (light_type) { // force PWM GPIOs to low or high mode, see #7165 analogWrite(Pin(GPIO_PWM1, i), bitRead(pwm_inverted, i) ? Settings.pwm_range : 0); diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index 18881d119..97a09a806 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1351,7 +1351,12 @@ void LightInit(void) for (uint32_t i = 0; i < light_type; i++) { Settings.pwm_value[i] = 0; // Disable direct PWM control if (PinUsed(GPIO_PWM1, i)) { +#ifdef ESP8266 pinMode(Pin(GPIO_PWM1, i), OUTPUT); +#else // ESP32 + analogAttach(Pin(GPIO_PWM1, i), i); + analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); +#endif } } if (PinUsed(GPIO_ARIRFRCV)) { diff --git a/tasmota/xlgt_03_sm16716.ino b/tasmota/xlgt_03_sm16716.ino index 314122a8b..81e38996f 100644 --- a/tasmota/xlgt_03_sm16716.ino +++ b/tasmota/xlgt_03_sm16716.ino @@ -148,7 +148,12 @@ void Sm16716ModuleSelected(void) for (uint32_t i = 0; i < Light.subtype; i++) { Settings.pwm_value[i] = 0; // Disable direct PWM control if (PinUsed(GPIO_PWM1, i)) { +#ifdef ESP8266 pinMode(Pin(GPIO_PWM1, i), OUTPUT); +#else // ESP32 + analogAttach(Pin(GPIO_PWM1, i), i); + analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); +#endif } } */ From ccdfff33dd59bb650ff7f63140df74f8f236f471 Mon Sep 17 00:00:00 2001 From: Staars Date: Sun, 2 Aug 2020 15:07:18 +0200 Subject: [PATCH 81/91] add support for MHO-C303 --- tasmota/xsns_62_MI_ESP32.ino | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tasmota/xsns_62_MI_ESP32.ino b/tasmota/xsns_62_MI_ESP32.ino index 612474172..0204b0462 100644 --- a/tasmota/xsns_62_MI_ESP32.ino +++ b/tasmota/xsns_62_MI_ESP32.ino @@ -20,6 +20,8 @@ -------------------------------------------------------------------------------------------- Version yyyymmdd Action Description -------------------------------------------------------------------------------------------- + 0.9.1.2 20200802 changed - add MHO-C303 + ------- 0.9.1.1 20200715 changed - add MHO-C401, refactoring ------- 0.9.1.0 20200712 changed - add lights and yeerc, add pure passive mode with decryption, @@ -250,10 +252,11 @@ const char kMI32_Commands[] PROGMEM = "Period|Time|Page|Battery|Unit #define MJYD2S 8 #define YEERC 9 #define MHOC401 10 +#define MHOC303 11 -#define MI_TYPES 10 //count this manually +#define MI32_TYPES 11 //count this manually -const uint16_t kMI32DeviceID[MI_TYPES]={ 0x0098, // Flora +const uint16_t kMI32DeviceID[MI32_TYPES]={ 0x0098, // Flora 0x01aa, // MJ_HT_V1 0x045b, // LYWSD02 0x055b, // LYWSD03 @@ -262,7 +265,8 @@ const uint16_t kMI32DeviceID[MI_TYPES]={ 0x0098, // Flora 0x03dd, // NLIGHT 0x07f6, // MJYD2S 0x0153, // yee-rc - 0x0387 // MHO-C401 + 0x0387, // MHO-C401 + 0x06d3 // MHO-C303 }; const char kMI32DeviceType1[] PROGMEM = "Flora"; @@ -275,7 +279,8 @@ const char kMI32DeviceType7[] PROGMEM = "NLIGHT"; const char kMI32DeviceType8[] PROGMEM = "MJYD2S"; const char kMI32DeviceType9[] PROGMEM = "YEERC"; const char kMI32DeviceType10[] PROGMEM ="MHOC401"; -const char * kMI32DeviceType[] PROGMEM = {kMI32DeviceType1,kMI32DeviceType2,kMI32DeviceType3,kMI32DeviceType4,kMI32DeviceType5,kMI32DeviceType6,kMI32DeviceType7,kMI32DeviceType8,kMI32DeviceType9,kMI32DeviceType10}; +const char kMI32DeviceType11[] PROGMEM ="MHOC303"; +const char * kMI32DeviceType[] PROGMEM = {kMI32DeviceType1,kMI32DeviceType2,kMI32DeviceType3,kMI32DeviceType4,kMI32DeviceType5,kMI32DeviceType6,kMI32DeviceType7,kMI32DeviceType8,kMI32DeviceType9,kMI32DeviceType10,kMI32DeviceType11}; /*********************************************************************************************\ * enumerations @@ -530,7 +535,7 @@ uint32_t MIBLEgetSensorSlot(uint8_t (&_MAC)[6], uint16_t _type, uint8_t counter) DEBUG_SENSOR_LOG(PSTR("%s: will test ID-type: %x"),D_CMND_MI32, _type); bool _success = false; - for (uint32_t i=0;i1000){ @@ -925,7 +929,7 @@ void MI32StartUnitTask(){ } void MI32UnitTask(void *pvParameters){ - if (MIBLEsensors[MI32.state.sensor].type != LYWSD02) { + if (MIBLEsensors[MI32.state.sensor].type != LYWSD02 && MIBLEsensors[MI32.state.sensor].type != MHOC303) { MI32.mode.shallSetUnit = 0; vTaskDelete( NULL ); } @@ -1497,7 +1501,7 @@ bool MI32Cmd(void) { case CMND_MI32_TIME: if (XdrvMailbox.data_len > 0) { if(MIBLEsensors.size()>XdrvMailbox.payload){ - if(MIBLEsensors[XdrvMailbox.payload].type == LYWSD02){ + if(MIBLEsensors[XdrvMailbox.payload].type == LYWSD02 || MIBLEsensors[XdrvMailbox.payload].type == MHOC303){ AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s: will set Time"),D_CMND_MI32); MI32.state.sensor = XdrvMailbox.payload; MI32.mode.canScan = 0; @@ -1512,7 +1516,7 @@ bool MI32Cmd(void) { case CMND_MI32_UNIT: if (XdrvMailbox.data_len > 0) { if(MIBLEsensors.size()>XdrvMailbox.payload){ - if(MIBLEsensors[XdrvMailbox.payload].type == LYWSD02){ + if(MIBLEsensors[XdrvMailbox.payload].type == LYWSD02 || MIBLEsensors[XdrvMailbox.payload].type == MHOC303){ AddLog_P2(LOG_LEVEL_DEBUG,PSTR("%s: will set Unit"),D_CMND_MI32); MI32.state.sensor = XdrvMailbox.payload; MI32.mode.canScan = 0; From 8e48d3f14770d991ed7e894b1a48c47e47744e32 Mon Sep 17 00:00:00 2001 From: Reese Date: Sun, 2 Aug 2020 16:28:00 -0500 Subject: [PATCH 82/91] Add latest portisch firmware. Includes support for zemismart roller shades --- tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220 | 484 ++++++++++++++++++++ 1 file changed, 484 insertions(+) create mode 100644 tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220 diff --git a/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220 b/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220 new file mode 100644 index 000000000..7840f347d --- /dev/null +++ b/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220 @@ -0,0 +1,484 @@ +:020000040000FA +:100000000210D8A2029290A2029280AD40AC3F7F33 +:100010000A7E0012002E12001DA202B322E59120DA +:10002000E2FB220210487597A5222202141B8E4182 +:100030008F428C438D4412163112188EE54424BF32 +:100040009000E8F0E54334FF9000E7F09000E3E52E +:1000500041F0A3E542F043910422220211671219F4 +:100060002253D87853DAFE1218F3E4900087F02276 +:10007000D2DE2202146E1217C0C290C296C280E471 +:10008000FBFD7F101218DA12053174A4F0D2AF1202 +:10009000170AD2969000ECE004F070069000EBE0B6 +:1000A00004F09000EBE0B427E9A3E0B410E4C296BA +:1000B0001200263003091216B18E228F2380067596 +:1000C0002201752300E5237004E522640170469047 +:1000D00000DEE0700612170B0202959000EBE4754B +:1000E000F001120807FED3E5F09410EE94274002C9 +:1000F000D296D39000ECE094309000EBE0947550F1 +:1001000003020295E4F0A3F09000DEF0900099F075 +:10011000C29602029512170A9000DEE014602A14BB +:1001200070030202591470030202171470030202D2 +:100130003024046003020295E52364AA60030202EE +:10014000959000DE04F0020295E523900099F0906E +:1001500000DE7402F0E52312092F0201A0017FA145 +:10016000018BA501A9A601BDA701C6A801DDA901B2 +:10017000CCB001D5B1019DC00295FF0000020C1268 +:10018000051EE490008AF07FA1806512054E900064 +:10019000EA7408F0E4F52575240902029512054E6B +:1001A000E4F52575240202029590008A7401F07F1F +:1001B000A61215A690007974A6F0020295120531D8 +:1001C00074A4F00202959000EA7408F09000DE74C6 +:1001D00003F00202957FB112056202029512051E1C +:1001E00090008AE09000E9F090008A7401F07FA905 +:1001F0001205627D307C757F017E00121797020226 +:100200009512056B900079EFF0E48005E490009979 +:10021000F09000DEF0807EE4F525E523F524E5246A +:10022000D39400402C12005E9000DE7404F08065D0 +:1002300074032525F582E43400F583E523F00525D4 +:10024000E525B52402800AE525C39470404775244E +:10025000709000DE7402F0803CE5236455703690A7 +:1002600000DEF0C203900099E02460601B24FC6073 +:100270001224FE600E14600B24F760101460042436 +:100280001070127FA0121875D2038009900004E04C +:10029000049000EAF0900099E012092F02BEA10339 +:1002A00033A40377A50333A60447A802BEA9047CA0 +:1002B000B004E5B1041EC00442FF000000B090008D +:1002C00086E030E73F7DC87C0012053F900099E052 +:1002D0002457600E2408701F12056B7FA31215ECC3 +:1002E00080159000E9E090008AF0900079E0FF121C +:1002F00015A67FAB12057CE4900086F043DA01D2AC +:10030000030200B01218EB50207DE87C0312053F79 +:10031000900099E02457600C240860030200B07F2D +:10032000A20204D77FAA0204D71205744003020078 +:10033000B0802E900086E030E71F900099E0245AAC +:10034000600F240260030204F17FA41215EC020482 +:10035000F17FA612057C0204F1120574400302002D +:10036000B01216E7C006C0071216F69200D007D0EA +:10037000061209810200B09000DEE060030200B0C6 +:100380001217127003020411240560030200B01258 +:100390000558900005E0FFA3E090008BCFF0A3EF9D +:1003A000F0900007E0FFA3E090008DCFF0A3EFF006 +:1003B000900003E0FFA3E090008FCFF0A3EFF07B6D +:1003C000017A00798B9019FAE493FC740193FD9003 +:1003D00019FCE493F52E1217028E2FF5309019FFB9 +:1003E000E493F5311217028E32F533901A02E4933A +:1003F000F5341217028E35F536901A05E493F53769 +:10040000A3E493F538753900753A09120EBC020061 +:10041000B09000EAE07063C2807FA00204D7900031 +:10042000DEE060030200B0900003E0FCA3E0FD7F8B +:10043000017E00121797D29612001DC2967FA0026D +:1004400004D77F030204D79000DEE060030200B00F +:100450001217126019240560030200B012055890AB +:100460000003E0FF7C007D041213570200B09000EF +:10047000EAE07006C2807FA0805D80619000DEE0CF +:1004800060030200B01217126043240560030200EB +:10049000B09000EAE014F012005E7E007F05C00616 +:1004A000C007900003E0FB25E0FFE433FE74052F56 +:1004B000F58274003EAD82FCEB25E0FFE52424FECE +:1004C000C39FFBD007D006120FA70200B09000EA2E +:1004D000E0700AC2807FA01218680200B0E49000A9 +:1004E00087F00200B0900086E030E7107FB1121173 +:1004F000ECE4900086F043DA010200B07E007FED6C +:1005000012151040030200B01216E7C006C0071211 +:1005100016F69200D007D006120D160200B07D32FA +:100520007C007F017E00121797D29612001DC296A2 +:1005300022E490008AF07FA41215A6900079227F11 +:10054000017E00121797D29612001DC29622120049 +:100550005E9000DE7404F0229000EAE014F01200D5 +:100560005E221215A6900079EFF022900079E0FF4C +:100570001215A6227E007FED12151022900086E053 +:10058000547FFD12155B228F29E4F536EF25E02517 +:10059000E02468F8E6701EEF25E025E02469F8768F +:1005A000087E007F707D007B017A00790312095577 +:1005B000E490007AF0AB2CAA2DA92EC001120B6793 +:1005C0002466F9E7540F120CA3120B86D001121403 +:1005D000C1503D120B672466F9E7540FFF120CA3BC +:1005E000120C90300101B34031EF700A900077E5B2 +:1005F0002AF0A3E52BF0120B67120CAF2401FFEFDA +:10060000FEEC54F04EFEEDFF120B67120C9A800ABE +:10061000120B672466F874F056F6AB2CAA2DA92E9F +:10062000C001120B67120CBB120BD1120CC7120BBC +:1006300086D0011214C15052120B67120CBB120B60 +:10064000D1FF120CC75408FE120C92300101B340C6 +:1006500043EF700A900088E52AF0A3E52BF0120B17 +:1006600067120BC22401FFE433FEEFC4F8540FC835 +:1006700068FFEEC454F048FEED540FFDEC4EFEED65 +:100680004FFF120B67120C9A800A120B672467F84F +:10069000740F56F6120B67120CAFFB700F120BCAD9 +:1006A000700A120B4D2469F8E4F6C322120B67247A +:1006B00068F8E53514667003753601C3E531953683 +:1006C0006B7020D290120B672466F874F056F674A3 +:1006D0000F0856120B662468F806120B672469F897 +:1006E00016804C120B67120BC2FFC3E53495366FB0 +:1006F000703DD290120B672466F8EC54F0FEED5476 +:100700000FA60608120B662468F806120B67246908 +:10071000F816120B67120BD8E0FF120B672469F86A +:10072000E6FE7401A806088002C333D8FC4FF0121D +:100730000B672469F8E67017120B67120BD8120CBE +:100740004CFF12182DEFF0120B672469F87608128F +:100750000B672468F8E6C3953540311218E350055D +:10076000E4900085F0120C4960181218F37D207C8B +:10077000037F017E0012176E120CD3A3E529F0440B +:1007800080F0120B4D2469F8E4F6D322C322BB019A +:100790000689828A83F0225002F722BBFE01F322EF +:1007A000EF8DF0A4A8F0CF8CF0A428CE8DF0A42E6D +:1007B000FE22BC000BBE0029EF8DF084FFADF022BD +:1007C000E4CCF875F008EF2FFFEE33FEEC33FCEECF +:1007D0009DEC984005FCEE9DFE0FD5F0E9E4CEFDC2 +:1007E00022EDF8F5F0EE8420D21CFEADF075F00895 +:1007F000EF2FFFED33FD4007985006D5F0F222C3EE +:1008000098FD0FD5F0EA22C5F0F8A3E028F0C5F076 +:10081000F8E582158270021583E038F022BB0110E2 +:10082000E58229F582E5833AF583E0F5F0A3E0223D +:100830005009E92582F886F008E622BBFE0AE92580 +:1008400082F8E2F5F008E222E5832AF583E993F5E0 +:10085000F0A3E9932275F008758200EF2FFFEE33C5 +:10086000FECD33CDCC33CCC58233C5829BED9AEC23 +:1008700099E58298400CF582EE9BFEED9AFDEC998D +:10088000FC0FD5F0D6E4CEFBE4CDFAE4CCF9A88297 +:1008900022B800C1B90059BA002DEC8BF084CFCE3C +:1008A000CDFCE5F0CBF97818EF2FFFEE33FEED33FA +:1008B000FDEC33FCEB33FB10D703994004EB99FBC1 +:1008C0000FD8E5E4F9FA227818EF2FFFEE33FEEDAA +:1008D00033FDEC33FCC933C910D7059BE99A4007B7 +:1008E000EC9BFCE99AF90FD8E0E4C9FAE4CCFB22CE +:1008F00075F010EF2FFFEE33FEED33FDCC33CCC897 +:1009000033C810D7079BEC9AE899400AED9BFDECA1 +:100910009AFCE899F80FD5F0DAE4CDFBE4CCFAE4E0 +:10092000C8F922A42582F582E5F03583F58322D02B +:1009300083D082F8E4937012740193700DA3A39393 +:10094000F8740193F5828883E4737402936860EF0E +:10095000A3A3A380DFEF4E6012EF60010EEDBB0199 +:100960000B89828A83F0A3DFFCDEFA2289F050072C +:10097000F709DFFCA9F022BBFEFCF309DFFCA9F0BC +:10098000228E268F27E4F528C3E5279464E5269474 +:10099000005017E4F528E528120B922469F8E4F6D4 +:1009A0000528E528B40EEFC2902290008AE014706A +:1009B00003020A6F046003020B4C7866E6C4540F0E +:1009C000F97065D3E5279494E52694115003020B42 +:1009D0004C300003020B4CE9120C32E6540FFC08B9 +:1009E000E6FDEC4E18F6ED08F618120C29EC540F43 +:1009F0004E18F6ED08F6900001E526F0A3E527F085 +:100A0000AE26FF7C007D1F1207B290008BEEF0A394 +:100A1000EFF07C007D031207A0A3EEF0A3EFF0A39C +:100A2000E526F0A3E527F0227866E6C4540F6402B9 +:100A30006003020B4C120CEB752C01752D00752E0A +:100A40008B901B9F93FE7401938E2FF530901BA10A +:100A5000E493F531A3120BBB8E32F533901BA4E463 +:100A600093F534901BA8E493F535E4FF020587E481 +:100A7000F528120BA8120D0CFFE528120C54F9EF03 +:100A8000C399506EE528120C16F5828C832FF582DF +:100A9000E43583F583E493FF120C90300001B350EA +:100AA00003020B40E528C454F02499F582E4341B7A +:100AB000120C20F5828C83EF540775F00212092383 +:100AC000120C22FDAF27AE261214CBE528501925B3 +:100AD000E025E02466F8120C29EC540F4EFEEDFFE1 +:100AE000120BA8120C9A8058120B922469F8E4F6A3 +:100AF000804E120BA8120D0C697045120CEBE52804 +:100B0000120BAFAA06752CFF8A2DF52EE528120CC4 +:100B1000F6120BB98E2FF530E528120C63F531E58E +:100B200028120D01120BB98E32F533E528120C7222 +:100B3000F534E528120C81F535AF28120587400CF5 +:100B40000528E528C3940E5003020A7222C290E5DC +:100B50002925E025E02466F8E4F608F6E52925E0F5 +:100B600025E02468F8E4F6E52925E025E022F58370 +:100B7000E493FF5408FE131313541F24FF9202AB97 +:100B800029AA2AA92BEF540775F002A4F58285F053 +:100B9000832225E025E02466F8E4F608F6E528251A +:100BA000E025E02468F8E4F6E52825E025E022C405 +:100BB00054F02499F582E4341BF583E493FE740128 +:100BC00093222466F8E6FC08E6FDECC4F854F0C86D +:100BD000EDC4540F48540F222468F8E6141313137D +:100BE000541F2403F582E43400F58322E529252BE4 +:100BF000F582E43528F583E022A200E433C43333E0 +:100C00003354804526FFE527900074CFF0A3EFF022 +:100C1000E490007BF022C454F0249CF582E4341B61 +:100C2000F583E493FC74019322E6FC08E6FDECC432 +:100C3000540F2401FFEFC454F0FE22E52E25E024DA +:100C40008BF582E43400F58322900085E0FF90006C +:100C50007AE06F22C454F0249EF582E4341BF583BD +:100C6000E49322C454F024A1F582E4341BF583E418 +:100C70009322C454F024A4F582E4341BF583E49356 +:100C800022C454F024A8F582E4341BF583E49322B3 +:100C90005408131313541F24FF222466F8A60608D1 +:100CA000A607222530F582E4352FF583E49322242C +:100CB00066F8E6FC08E6FDEC540F222466F9E7C46A +:100CC000F854F0C809E7222533F582E43532F5837C +:100CD000E4932290007AE0900085F053DAFE22251A +:100CE000E0247DF582E43400F58322A200920185A0 +:100CF000262A85272B22C454F0249FF582E4341B36 +:100D000022C454F024A2F582E4341B222466F8E6BF +:100D1000FEEEC4540F228E268F27C3E5279464E588 +:100D20002694005003020EAA900087E024FE60255E +:100D3000147003020DB724036003020EAFC290AF1C +:100D400027AE2612185A4003020EAF120BF990007C +:100D5000877402F022120EB0503090007BE09404B1 +:100D60004021D290E4900000F0900073F0C2049013 +:100D7000007CF090007AF0900003F09000877403FC +:100D8000F08025E4900087F0801E900074E0547F8E +:100D9000FEA3E0FFD3E5279FE5269E4005120BF951 +:100DA000800690007BE004F090007BE0C394E0506C +:100DB00003020EAF020EAA90007CE004F090007BCC +:100DC000E0FFA3E0D39F4003020E587B007A007936 +:100DD00028AF27AE261212DF4022900000E0FF125B +:100DE0000C3DE526F0A3E527F08F28900000E004F5 +:100DF000F0E0D394074005E4900087F030041DA292 +:100E000000E433C43333335480FFE528C454F04F37 +:100E1000FF900073E0120BE2EFF08039900073E076 +:100E2000FF120BE2E0FEA200E43333333354F84503 +:100E300028FDEE4DF074032F120BE4120C4CFF1240 +:100E4000182DEFF0900073E004F0E0D394704005AB +:100E5000E4900087F0B20422120EB0504D1218E355 +:100E60005005E4900085F0120C49603A1218F37DA9 +:100E7000207C037F017E0012176E120CD3900003BA +:100E8000E0FD900074E05480FF900000E0C454F056 +:100E90004FFFED4F900003F0900074E0547FF0900E +:100EA0000086E04480F0C2908000E4900087F02249 +:100EB000A2009201AF27AE26121744228B298A2A5C +:100EC000892B8C2C8D2DE4F53D753E80F53BE53B63 +:100ED000C3952E5010E52D253BF582E4352C120FDD +:100EE0006C053B80E9E4F53BE53BC395385057E59D +:100EF0003A253DF582E43539F583E0553E7019F524 +:100F00003CE53CC39531502DE530253CF582E43578 +:100F10002F120F6C053C80E9E4F53CE53CC39534A9 +:100F20005013E533253CF582E43532120B6E120F77 +:100F30009B053C80E6E53EC313F53E7005053D7517 +:100F40003E80053B80A2E4F53BE53BC3953750135B +:100F5000E536253BF582E43535120B6E120F9B0505 +:100F60003B80E6C2909000877405F022F583E493FD +:100F7000FF5408FE131313541F24FF9202AB29AA37 +:100F80002AA92BEF540775F002A4F58285F083128D +:100F9000081DF54085F03F1200032212081DF540A0 +:100FA00085F03F120003228E268F278C288D298BF7 +:100FB0002AD200C201852982852883E05488D394EF +:100FC000004003D38001C39201E4F52BE52BC395C8 +:100FD0002A505930010D120BECC413131354012481 +:100FE000FF8002A2009202852782852683C083C0EB +:100FF00082120BECFFC45407D082D083121035301C +:10100000010C120BECFF131313541F138002A200E8 +:101010009202852782852683C083C082120BEC54FE +:1010200007D082D083121035052B80A0C29090008B +:10103000877405F02275F002120923E0F53FA3E062 +:10104000F540120003920022C0E0C0F0C083C082CD +:10105000C0D075D000C000C001C002C003C004C031 +:1010600005C006C007E5985403F545F45298E545D8 +:1010700030E01712192B9000DD121739EFF09000B5 +:10108000DDE004F0E0B44002E4F0E54530E12E900C +:1010900000E0E0D39400401A9000DCE02446F8E63B +:1010A000FF1219289000DCE004F09000E0E014F05A +:1010B0008002D2059000DCE0B42002E4F0D007D03A +:1010C00006D005D004D003D002D001D000D0D0D0BB +:1010D00082D083D0F0D0E03212005A787FE4F6D884 +:1010E000FD75819D021122020076E493A3F8E4933A +:1010F000A34003F68001F208DFF48029E493A3F80B +:101100005407240CC8C333C4540F4420C88340047C +:10111000F456800146F6DFE4800B0102040810203B +:101120004080901266E47E019360BCA3FF543F3080 +:10113000E509541FFEE493A360010ECF54C025E0DF +:1011400060A840B8E493A3FAE493A3F8E493A3C897 +:10115000C582C8CAC583CAF0A3C8C582C8CAC58328 +:10116000CADFE9DEE780BEC0E0C0F0C083C082C055 +:10117000D075D000C000C001C002C003C004C005CB +:10118000C006C007E5D85487F521F452D8E5F730FA +:10119000E508E5F730E60312193253F7DFE52130B1 +:1011A000E708E5D930E003121931E52130E008E520 +:1011B000DA30E003121675E52130E108E5DB30E0B6 +:1011C00003121933E52130E208E5DC30E00312199F +:1011D00034D007D006D005D004D003D002D001D03F +:1011E00000D0D0D082D083D0F0D0E032AE07E4F58A +:1011F0002612180A900000E004FF12181112125F64 +:10120000900000E0FFE526C39F501412172BE05416 +:101210007FFF12181112172B121725052680E19057 +:101220000074E0547FFF12181190007412172512F9 +:10123000125FE4F526900073E0FFE526C39F501788 +:10124000740325261217190526E526541F70E61289 +:10125000192512191E80DE7F551218110219251248 +:10126000192512191E224200E500004200E100008B +:101270004200E700004200E30000C1834100860015 +:101280004100870041008A004100790042000100CE +:101290000042008800004200770000C10441007352 +:1012A000004100850041007A004100000048007DB7 +:1012B0000000000000000000410076004100DD0059 +:1012C0004100DF004100DB004100DC004100E000A4 +:1012D0004100DA00C1054100DE0041009900008EA6 +:1012E000298F2A8B2B8A2C892DE4F52E900000E083 +:1012F000FFE52EC39F505EE52AAE297803CEC313C7 +:10130000CE13D8F9FDAC06E52AAE297802CEC31378 +:10131000CE13D8F92DFFEE3CAB07FA120C3BE0FEE2 +:10132000A3E0FFC39BEE9A50028004AE02AF03AA73 +:1013300006AB07120C3BE0FCA3E0FDAF2AAE29127E +:1013400017E7500DAB2BAA2CA92DE52E12078ED333 +:1013500022052E8097C3228F268C278D28EF120B13 +:10136000AFAA06F97BFFEF120C16FDEF120C54F535 +:101370002EEF120CF6120BB98E2FF530EF120C6314 +:10138000F531EF120D01120BB98E32F533EF120C5D +:1013900072F534EFC454F024A5F582E4341B120B2B +:1013A000B98E35F536EFC454F024A7F582E4341B2A +:1013B000F583E493F537EF120C81F53885273985ED +:1013C000283A020EBC900076E0FDC4540F2401FBC5 +:1013D000E433FAED540FF96B7001EA603DE97010E7 +:1013E000E0C4540F2401FDE433FCED64044C602A96 +:1013F000900076E0C4540FFD540F120CDFEEF0A302 +:10140000EFF0ED04C454F049900076F0E0FFC454CE +:101410000FC394044004EF540FF022C0E0C083C017 +:1014200082C0D075D000C004C005C006C00753C834 +:101430007F9000E5E0FEA3E0FF4E700353C8FB90F1 +:1014400000E112166A50099000E5E4F0A3F0800D67 +:10145000C39000E6E09DF09000E5E09CF0D007D05E +:1014600006D005D004D0D0D082D083D0E032C0E006 +:10147000C083C082C0D075D000C004C005C006C003 +:101480000753917F9000E7E0FEA3E0FF4E70035307 +:1014900091FB9000E312166A50099000E7E4F0A374 +:1014A000F0800DC39000E8E09DF09000E7E09CF034 +:1014B000D007D006D005D004D0D0D082D083D0E0E1 +:1014C0003212081DFDACF0AF2BAE2A8F828E83AF97 +:1014D00005AE041218A6AB07AA06D3EB94F4EA945F +:1014E0000140067E017FF48004AE02AF03AA06AB82 +:1014F00007C3EB9464EA940050067E007F64800486 +:10150000AE02AF03AA06AB07AF82AE831217E72283 +:10151000AD07AC06ABDA900076E0FEC4540FFFEEE8 +:10152000540FFEB50702C32253DAFE900076E0FAAC +:10153000EE120CDFE0FFA3E08D828C83CFF0A3EFEF +:10154000F0EA54F0FF900076E0044FF0540FC3949B +:10155000044004E054F0F08BDAD322AE05AD07E48A +:10156000FCFB7FAA121811AF05121811EEC454F03B +:10157000244AF582E4341DF583E493FFECC39F50C5 +:101580000774082CFC0B80F4EB04FF12180CE4FC2D +:10159000ECC39B500974032C1217190C80F27F5571 +:1015A0001218110219258F26900079E0F5277E0088 +:1015B0007F387D007B007A0079661209557F0B1217 +:1015C000192E43DA011200707D0A7C007F017E0033 +:1015D00012179712001DE4900087F0900086F0909B +:1015E0000099E526F0900079F0AF2722AE07E4FDE0 +:1015F000F52612180A900001E0FF12181190000160 +:10160000121725900077E0FF12181190007712173B +:1016100025900088E0FF1218119000881217257499 +:10162000032D1217190DBD03F67F5512181102195B +:1016300025AB07AA06E4F9F87F407E427D0FFC1235 +:101640000891A804A905AA06AB077F207ED77D755F +:101650007C01120891C3E49FFFE49EFE22AB07AA1F +:1016600006E4F9F87FE87E03FD22E0FCA3E0FDC379 +:10167000EF9DEE9C22AFFBAEFC7C007D0A1207A022 +:10168000AD07AC06AFD953D9BFE4F5FAF5F98FD958 +:10169000C3EC948050157F002093027F01EFC43388 +:1016A000333354804CFEEDFF0213C5E4900076F016 +:1016B000229000DDE0FF9000DBE0B507057E017FB2 +:1016C00000229000DB121739E0FD7C009000DBE087 +:1016D00004F0E0B44002E4F09000DAE0FEEE4204F0 +:1016E000E4F0AE04AF05229000EDE0FCA3E0FDECD9 +:1016F000547FFEAF0522EC5480C41313135401240D +:10170000FF22A3E493FE74019322E49000EBF0A384 +:10171000F022900087E024FB22F582E43400F58378 +:10172000E0FF021811A3E0FF021811E52625E024CE +:101730008BF582E43400F58322E0249AF582E434C8 +:1017400000F58322AD07AC06900074E0FAA3E0FB3D +:10175000EA5480C413131354017005300102C322EC +:10176000AF05AE04EA547FFCAD031214CB228E37D2 +:101770008F388C398D3A12165D12163E12188290EF +:1017800000E5E539F0A3E53AF09000E1E537F0A394 +:10179000E538F043C804228E288F298C2A8D2B121D +:1017A000165D12163E12188E9000E7E52AF0A3E5AA +:1017B0002BF09000E3E528F0A3E529F04391042203 +:1017C00012002A1218FA1219011218B2121916125E +:1017D00018441218D01218BC1218C612189A1219EE +:1017E0000812191A02190FC3ED9BF582EC9AF583C2 +:1017F000C3E5829FE5839E500FED2BFDEC3AFCC3C1 +:10180000EF9DEE9C50028001C3227FAA121811AFF7 +:1018100006C2059000DFE0B42002E4F09000DFE0B3 +:101820002446F8A607E004F0A3E004F0227E1DE4BD +:10183000FDEF30E70625E06EFF8004EF25E0FF0DA9 +:10184000BD08EE22AF885388AF758CA0758DCBEFA5 +:101850005440FEEF54104E428822C3EF942CEE9475 +:10186000014003D38001C322121875D2039000797E +:10187000E0FF0215A6AE0712180A7F5512181102D2 +:101880001925AD07AC06ECF5CBAF058FCA22AD0725 +:10189000AC06ECF593AF058F9222C2DE75D90575C3 +:1018A000F9FF75960122EF7802CEC313CE13D8F953 +:1018B000FF2275E34075E10175E20122E5915404D0 +:1018C0005391FB429122758E547589224388502290 +:1018D000E5C8540453C8FB42C82253984FEB4F4D00 +:1018E000F59822E5C8C320E201D322E591C320E2A6 +:1018F00001D32253C8FB53C87F2275A41175D4CFDE +:101900002275A54175D5772253F77F75DA30227598 +:10191000E69075A8B022E4F5A9224398102230057C +:10192000FD22C2DE22D299228F9922AF99228F8C7A +:101930002222222222015E041A2A620802080109D8 +:1019400000017202E412C005DC20D00A030801097C +:101950000004017C044C0BB823280A030801090089 +:1019600001F403E805DC733C030A0108010190045B +:10197000B00BB81C520A030801090001C2038428F5 +:101980006E02080009010800D201A41D88020800A7 +:1019900009010800C8017C1B260208000901080192 +:1019A0005E028A32C8020800090108015E02BC3DDD +:1019B00022020800090108028A1E82071C0F8C08F7 +:1019C0000108020803016802D012C005DC0A0308FE +:1019D000010900024E05DC01AE348A0A0308010940 +:1019E00000012C0A00008C047E27F6080108030879 +:1019F00002080208030804193503193B02193D02C5 +:101A0000193F0200000018194105194B02194D0237 +:101A1000194F0219510128195204195A02195C026E +:101A2000195E0200000018196004196801196902A2 +:101A3000196B0200000047196D041975021977022D +:101A400019790200000018197B0319810219830219 +:101A500019850200000018198703198D02198F02D9 +:101A60001991020000000C199303199902199B02A5 +:101A7000199D020000000C199F0319A50219A70265 +:101A800019A9020000000C19AB0319B10219B30225 +:101A900019B5020000001219B70419BF0219C102DA +:101AA00019C3020000002819C50419CD0219CF027C +:101AB00019D1020000002819D30419DB0219DD0234 +:101AC00019DF020000001819E10519EB0219ED04F5 +:101AD00019F10419F50220015E041A2A62080208AD +:101AE000010900017202E412C005DC20D00A0308DB +:101AF00001090004017C044C0BB823280A030801E7 +:101B0000090001F403E805DC733C030A0108010144 +:101B10009004B00BB81C520A030801090001C2036B +:101B200084286E02080009010800D201A41D880261 +:101B3000080009010800C8017C1B260208000901F1 +:101B400008015E028A32C8020800090108015E022B +:101B5000BC3D22020800090108028A1E82071C0FF0 +:101B60008C080108020803016802D012C005DC0AD3 +:101B70000308010900024E05DC01AE348A0A03089D +:101B8000010900012C0A00008C047E27F6080108D8 +:101B90000308020802080308041AD7031ADD021A10 +:101BA000DF021AE102000000181AE3051AED021A1A +:101BB000EF021AF1021AF301281AF4041AFC021AAD +:101BC000FE021B0002000000181B02041B0A011B7E +:101BD0000B021B0D02000000471B0F041B17021B0A +:101BE00019021B1B02000000181B1D031B23021BF4 +:101BF00025021B2702000000181B29031B2F021BB4 +:101C000031021B33020000000C1B35031B3B021B7F +:101C10003D021B3F020000000C1B41031B47021B3F +:101C200049021B4B020000000C1B4D031B53021BFF +:101C300055021B5702000000121B59041B61021BB6 +:101C400063021B6502000000281B67041B6F021B58 +:101C500071021B7302000000281B75041B7D021B10 +:101C60007F021B8102000000181B83051B8D021BD5 +:101C70008F041B93041B970220015E041A2A62083A +:101C80000208010900017202E412C005DC20D00A3A +:101C9000030801090004017C044C0BB823280A0343 +:101CA0000801090001F403E805DC733C030A01089C +:101CB00001019004B00BB81C520A0308010900018D +:101CC000C20384286E02080009010800D201A41D85 +:101CD0008802080009010800C8017C1B26020800D0 +:101CE000090108015E028A32C802080009010801E0 +:101CF0005E02BC3D22020800090108028A1E82071A +:101D00001C0F8C080108020803016802D012C005EC +:101D1000DC0A0308010900024E05DC01AE348A0A20 +:101D20000308010900012C0A00008C047E27F60834 +:101D300001080308020802080308041C79031C7F39 +:101D4000021C81021C8302000000181C85051C8FE8 +:101D5000021C91021C93021C9501281C96041C9ED7 +:101D6000021CA0021CA202000000181CA4041CAC4F +:101D7000011CAD021CAF02000000471CB1041CB9DD +:101D8000021CBB021CBD02000000181CBF031CC5C6 +:101D9000021CC7021CC902000000181CCB031CD186 +:101DA000021CD3021CD5020000000C1CD7031CDD52 +:101DB000021CDF021CE1020000000C1CE3031CE912 +:101DC000021CEB021CED020000000C1CEF031CF5D2 +:101DD000021CF7021CF902000000121CFB041D0388 +:101DE000021D05021D0702000000281D09041D1127 +:101DF000021D13021D1502000000281D17041D1FDF +:101E0000021D21021D2302000000181D25051D2FA3 +:0B1E1000021D31041D35041D390220A5 +:00000001FF From aed641616b3a1b74f71a54950b876133933f0116 Mon Sep 17 00:00:00 2001 From: Adrian Scillato <39969427+ascillato2@users.noreply.github.com> Date: Sun, 2 Aug 2020 20:11:32 -0300 Subject: [PATCH 83/91] Rename RF-Bridge-EFM8BB1-20190220 to RF-Bridge-EFM8BB1-20190220.hex --- ...{RF-Bridge-EFM8BB1-20190220 => RF-Bridge-EFM8BB1-20190220.hex} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tools/fw_efm8bb1/{RF-Bridge-EFM8BB1-20190220 => RF-Bridge-EFM8BB1-20190220.hex} (100%) diff --git a/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220 b/tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220.hex similarity index 100% rename from tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220 rename to tools/fw_efm8bb1/RF-Bridge-EFM8BB1-20190220.hex From 2b90ee3baff14027c574fd718a5a3fa747b1ff91 Mon Sep 17 00:00:00 2001 From: Jason2866 <24528715+Jason2866@users.noreply.github.com> Date: Mon, 3 Aug 2020 10:21:18 +0200 Subject: [PATCH 84/91] Use Tasmota core 2.7.4.1 for Tasmota stage. - Since Platformio released the GCC10.1 build chain, use the platformio provided for Core Stage. --- platformio_override_sample.ini | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/platformio_override_sample.ini b/platformio_override_sample.ini index 8d6ac6341..9e750911f 100644 --- a/platformio_override_sample.ini +++ b/platformio_override_sample.ini @@ -89,7 +89,7 @@ extra_scripts = ${scripts_defaults.extra_scripts} [tasmota_stage] ; *** Esp8266 core for Arduino version Tasmota stage platform = espressif8266@2.6.1 -platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.3.2/esp8266-2.7.3.2.zip +platform_packages = framework-arduinoespressif8266 @ https://github.com/tasmota/Arduino/releases/download/2.7.4.1/esp8266-2.7.4.1.zip build_unflags = ${esp_defaults.build_unflags} build_flags = ${esp82xx_defaults.build_flags} @@ -124,8 +124,10 @@ build_flags = ${esp82xx_defaults.build_flags} [core_stage] ; *** Esp8266 core version. Tasmota stage or Arduino stage version. Built with GCC 10.1 toolchain -platform = https://github.com/Jason2866/platform-espressif8266/releases/download/2.9.0/platform-espressif8266-2.9.0.tar.gz -platform_packages = ;framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git +platform = espressif8266@2.6.1 +platform_packages = framework-arduinoespressif8266 @ https://github.com/Jason2866/platform-espressif8266/releases/download/2.9.0/framework-arduinoespressif8266-3.20900.0.tar.gz + ;framework-arduinoespressif8266 @ https://github.com/esp8266/Arduino.git + toolchain-xtensa @ ~2.100100.0 build_unflags = ${esp_defaults.build_unflags} -Wswitch-unreachable build_flags = ${esp82xx_defaults.build_flags} @@ -205,4 +207,3 @@ lib_extra_dirs = lib_ignore = cc1101 - From 1d990ad0919a9214b85566ed954df95eac577c2f Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 3 Aug 2020 11:52:25 +0200 Subject: [PATCH 85/91] Fix ESP32 PWM range --- RELEASENOTES.md | 3 + .../src/esp8266toEsp32.h | 80 ++++++++++--------- tasmota/CHANGELOG.md | 1 + tasmota/support_command.ino | 26 +++--- tasmota/support_tasmota.ino | 9 +-- tasmota/xdrv_04_light.ino | 1 - tasmota/xlgt_03_sm16716.ino | 1 - 7 files changed, 65 insertions(+), 56 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index ae3820c55..5a0d46ab4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -54,3 +54,6 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog ### Version 8.4.0.1 + +- Fix ESP32 PWM range +- Add Zigbee better support for IKEA Motion Sensor diff --git a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h index b9876ac15..a301189a6 100644 --- a/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h +++ b/libesp32/ESP32-to-ESP8266-compat/src/esp8266toEsp32.h @@ -29,28 +29,63 @@ #include /*********************************************************************************************\ - * ESP32 analogWrite support + * ESP32 analogWrite emulation support \*********************************************************************************************/ #define PWM_SUPPORTED_CHANNELS 8 #define PWM_CHANNEL_OFFSET 2 // Webcam uses channel 0, so we offset standard PWM uint8_t _pwm_channel[PWM_SUPPORTED_CHANNELS] = { 99, 99, 99, 99, 99, 99, 99, 99 }; - -inline void analogWriteFreq(uint32_t freq) { -} -inline void analogWriteRange(uint32_t range) { -} +uint32_t _pwm_frequency = 977; // Default 977Hz +uint8_t _pwm_bit_num = 10; // Default 1023 inline uint32_t _analog_pin2chan(uint32_t pin) { - for (uint32_t cnt = 0; cnt < PWM_SUPPORTED_CHANNELS; cnt++) { - if ((_pwm_channel[cnt] < 99) && (_pwm_channel[cnt] == pin)) { - return cnt; + for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) { + if ((_pwm_channel[channel] < 99) && (_pwm_channel[channel] == pin)) { + return channel; } } return 0; } +inline void _analogWriteFreqRange(void) { + for (uint32_t channel = 0; channel < PWM_SUPPORTED_CHANNELS; channel++) { + if (_pwm_channel[channel] < 99) { +// uint32_t duty = ledcRead(channel + PWM_CHANNEL_OFFSET); + ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num); +// ledcWrite(channel + PWM_CHANNEL_OFFSET, duty); + } + } +// Serial.printf("freq - range %d - %d\n",freq,range); +} + +// input range is in full range, ledc needs bits +inline uint32_t _analogGetResolution(uint32_t x) { + uint32_t bits = 0; + while (x) { + bits++; + x >>= 1; + } + return bits; +} + +inline void analogWriteRange(uint32_t range) { + _pwm_bit_num = _analogGetResolution(range); + _analogWriteFreqRange(); +} + +inline void analogWriteFreq(uint32_t freq) { + _pwm_frequency = freq; + _analogWriteFreqRange(); +} + +inline void analogAttach(uint32_t pin, uint32_t channel) { + _pwm_channel[channel &7] = pin; + ledcAttachPin(pin, channel + PWM_CHANNEL_OFFSET); + ledcSetup(channel + PWM_CHANNEL_OFFSET, _pwm_frequency, _pwm_bit_num); +// Serial.printf("attach %d - %d\n", channel, pin); +} + inline void analogWrite(uint8_t pin, int val) { uint32_t channel = _analog_pin2chan(pin); @@ -58,33 +93,6 @@ inline void analogWrite(uint8_t pin, int val) // Serial.printf("write %d - %d\n",channel,val); } -inline void analogAttach(uint32_t pin, uint32_t channel) { - _pwm_channel[channel &7] = pin; - ledcAttachPin(pin, channel + PWM_CHANNEL_OFFSET); -// Serial.printf("attach %d - %d\n",channel,pin); -} - -inline uint32_t _analog_pow2(uint32_t x) { - uint32_t power = 1; - uint32_t bits = 0; - while (power < x) { - power *= 2; - bits++; - } - return bits; -} - -// input range is in full range, ledc needs bits -inline void analogWriteFreqRange(uint32_t channel, uint32_t freq, uint32_t irange) { - uint32_t range = _analog_pow2(irange); - for (uint32_t cnt = 0; cnt < PWM_SUPPORTED_CHANNELS; cnt++) { - if (_pwm_channel[cnt] < 99) { - ledcSetup(cnt + PWM_CHANNEL_OFFSET, freq, range); - } - } -// Serial.printf("freq - range %d - %d\n",freq,range); -} - /*********************************************************************************************/ #define INPUT_PULLDOWN_16 INPUT_PULLUP diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 237d131b3..7ceb6f7c1 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -2,6 +2,7 @@ ### 8.4.0.1 20200730 +- Fix ESP32 PWM range - Add Zigbee better support for IKEA Motion Sensor ### 8.4.0 20200730 diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index 0affcb83e..49f554b18 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -1236,29 +1236,31 @@ void CmndPwmfrequency(void) { if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload >= PWM_MIN) && (XdrvMailbox.payload <= PWM_MAX))) { Settings.pwm_frequency = (1 == XdrvMailbox.payload) ? PWM_FREQ : XdrvMailbox.payload; -#ifdef ESP8266 analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) -#else - analogWriteFreqRange(0,Settings.pwm_frequency,Settings.pwm_range); -#endif } ResponseCmndNumber(Settings.pwm_frequency); } -void CmndPwmrange(void) -{ +void CmndPwmrange(void) { + // Support only 8 (=255), 9 (=511) and 10 (=1023) bits resolution if ((1 == XdrvMailbox.payload) || ((XdrvMailbox.payload > 254) && (XdrvMailbox.payload < 1024))) { - Settings.pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : XdrvMailbox.payload; + uint32_t pwm_range = XdrvMailbox.payload; + uint32_t pwm_resolution = 0; + while (pwm_range) { + pwm_resolution++; + pwm_range >>= 1; + } + pwm_range = (1 << pwm_resolution) - 1; + uint32_t old_pwm_range = Settings.pwm_range; + Settings.pwm_range = (1 == XdrvMailbox.payload) ? PWM_RANGE : pwm_range; for (uint32_t i = 0; i < MAX_PWMS; i++) { if (Settings.pwm_value[i] > Settings.pwm_range) { Settings.pwm_value[i] = Settings.pwm_range; } } -#ifdef ESP8266 - analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) -#else - analogWriteFreqRange(0,Settings.pwm_frequency,Settings.pwm_range); -#endif + if (Settings.pwm_range != old_pwm_range) { // On ESP32 this prevents loss of duty state + analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) + } } ResponseCmndNumber(Settings.pwm_range); } diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 6b0dd6f4e..db4ce592f 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -1564,12 +1564,12 @@ void GpioInit(void) // AddLogBufferSize(LOG_LEVEL_DEBUG, (uint8_t*)gpio_pin, ARRAY_SIZE(gpio_pin), sizeof(gpio_pin[0])); -#ifdef ESP8266 - if ((2 == Pin(GPIO_TXD)) || (H801 == my_module_type)) { Serial.set_tx(2); } - analogWriteRange(Settings.pwm_range); // Default is 1023 (Arduino.h) analogWriteFreq(Settings.pwm_frequency); // Default is 1000 (core_esp8266_wiring_pwm.c) +#ifdef ESP8266 + if ((2 == Pin(GPIO_TXD)) || (H801 == my_module_type)) { Serial.set_tx(2); } + #ifdef USE_SPI spi_flg = (((PinUsed(GPIO_SPI_CS) && (Pin(GPIO_SPI_CS) > 14)) || (Pin(GPIO_SPI_CS) < 12)) || ((PinUsed(GPIO_SPI_DC) && (Pin(GPIO_SPI_DC) > 14)) || (Pin(GPIO_SPI_DC) < 12))); if (spi_flg) { @@ -1584,8 +1584,6 @@ void GpioInit(void) soft_spi_flg = (PinUsed(GPIO_SSPI_CS) && PinUsed(GPIO_SSPI_SCLK) && (PinUsed(GPIO_SSPI_MOSI) || PinUsed(GPIO_SSPI_MISO))); #endif // USE_SPI #else // ESP32 - analogWriteFreqRange(0, Settings.pwm_frequency, Settings.pwm_range); - #ifdef USE_SPI if (PinUsed(GPIO_SPI_CS) || PinUsed(GPIO_SPI_DC)) { if ((15 == Pin(GPIO_SPI_CS)) && (!GetPin(12) && !GetPin(13) && !GetPin(14))) { // HSPI @@ -1690,7 +1688,6 @@ void GpioInit(void) pinMode(Pin(GPIO_PWM1, i), OUTPUT); #else // ESP32 analogAttach(Pin(GPIO_PWM1, i), i); - analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); #endif if (light_type) { // force PWM GPIOs to low or high mode, see #7165 diff --git a/tasmota/xdrv_04_light.ino b/tasmota/xdrv_04_light.ino index 97a09a806..908ec026e 100644 --- a/tasmota/xdrv_04_light.ino +++ b/tasmota/xdrv_04_light.ino @@ -1355,7 +1355,6 @@ void LightInit(void) pinMode(Pin(GPIO_PWM1, i), OUTPUT); #else // ESP32 analogAttach(Pin(GPIO_PWM1, i), i); - analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); #endif } } diff --git a/tasmota/xlgt_03_sm16716.ino b/tasmota/xlgt_03_sm16716.ino index 81e38996f..0c6866ada 100644 --- a/tasmota/xlgt_03_sm16716.ino +++ b/tasmota/xlgt_03_sm16716.ino @@ -152,7 +152,6 @@ void Sm16716ModuleSelected(void) pinMode(Pin(GPIO_PWM1, i), OUTPUT); #else // ESP32 analogAttach(Pin(GPIO_PWM1, i), i); - analogWriteFreqRange(i, Settings.pwm_frequency, Settings.pwm_range); #endif } } From b966a5a9336295df92c480daf99448f65257625f Mon Sep 17 00:00:00 2001 From: stefanbode Date: Mon, 3 Aug 2020 18:02:27 +0200 Subject: [PATCH 86/91] Exposed OUT Pin as Relays --- tasmota/xsns_29_mcp230xx.ino | 73 +++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/tasmota/xsns_29_mcp230xx.ino b/tasmota/xsns_29_mcp230xx.ino index c2e160476..70255df12 100644 --- a/tasmota/xsns_29_mcp230xx.ino +++ b/tasmota/xsns_29_mcp230xx.ino @@ -45,6 +45,8 @@ uint8_t MCP230xx_GPIO = 0x09; uint8_t mcp230xx_type = 0; uint8_t mcp230xx_pincount = 0; +uint8_t mcp230xx_oldoutpincount = 0; +uint8_t mcp230xx_outpinmapping[16]; uint8_t mcp230xx_int_en = 0; uint8_t mcp230xx_int_prio_counter = 0; uint8_t mcp230xx_int_counter_en = 0; @@ -192,9 +194,16 @@ void MCP230xx_ApplySettings(void) I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO+mcp230xx_port, reg_portpins); #endif // USE_MCP230xx_OUTPUT } + devices_present -= mcp230xx_oldoutpincount; + mcp230xx_oldoutpincount = 0; for (uint32_t idx=0;idx= 5) { + mcp230xx_outpinmapping[mcp230xx_oldoutpincount] = idx; + mcp230xx_oldoutpincount++; + } int_millis[idx]=millis(); } + devices_present += mcp230xx_oldoutpincount; mcp230xx_int_en = int_en; MCP230xx_CheckForIntCounter(); // update register on whether or not we should be counting interrupts MCP230xx_CheckForIntRetainer(); // update register on whether or not we should be retaining interrupt events for teleperiod @@ -330,7 +339,7 @@ void MCP230xx_Show(bool json) if (json) { uint8_t gpio = MCP230xx_readGPIO(0); ResponseAppend_P(PSTR(",\"MCP230XX\":{\"D0\":%i,\"D1\":%i,\"D2\":%i,\"D3\":%i,\"D4\":%i,\"D5\":%i,\"D6\":%i,\"D7\":%i"), - (gpio>>0)&1, (gpio>>1)&1, (gpio>>2)&1, (gpio>>3)&1, (gpio>>4)&1, (gpio>>5)&1, (gpio>>6)&1, (gpio>>7)&1); + (gpio>>0)&1,(gpio>>1)&1,(gpio>>2)&1,(gpio>>3)&1,(gpio>>4)&1,(gpio>>5)&1,(gpio>>6)&1,(gpio>>7)&1); uint8_t gpiob = 0; if (2 == mcp230xx_type) { gpiob = MCP230xx_readGPIO(1); @@ -338,25 +347,24 @@ void MCP230xx_Show(bool json) (gpiob>>0)&1, (gpiob>>1)&1, (gpiob>>2)&1, (gpiob>>3)&1, (gpiob>>4)&1, (gpiob>>5)&1, (gpiob>>6)&1, (gpiob>>7)&1); } -#ifdef USE_MCP230xx_OUTPUT - uint8_t outputcount = 0; - for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { - if (Settings.mcp230xx_config[pinx].pinmode >= 5) { outputcount++; } - } - if (outputcount) { - uint16_t gpiototal = ((uint16_t)gpiob << 8) | gpio; - ResponseAppend_P(PSTR(",\"MCP230_OUT\":{")); - char stt[7]; - for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { - if (Settings.mcp230xx_config[pinx].pinmode >= 5) { - sprintf(stt, ConvertNumTxt(((gpiototal>>pinx)&1), Settings.mcp230xx_config[pinx].pinmode)); - ResponseAppend_P(PSTR("\"OUT_D%i\":\"%s\","), pinx, stt); - } - } - ResponseAppend_P(PSTR("\"END\":1}")); - } -#endif // USE_MCP230xx_OUTPUT - +#ifdef USE_MCP230xx_OUTPUT + uint8_t outputcount = 0; + for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { + if (Settings.mcp230xx_config[pinx].pinmode >= 5) { outputcount++; } + } + if (outputcount) { + uint16_t gpiototal = ((uint16_t)gpiob << 8) | gpio; + ResponseAppend_P(PSTR(",\"MCP230_OUT\":{")); + char stt[7]; + for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { + if (Settings.mcp230xx_config[pinx].pinmode >= 5) { + sprintf(stt, ConvertNumTxt(((gpiototal>>pinx)&1), Settings.mcp230xx_config[pinx].pinmode)); + ResponseAppend_P(PSTR("\"OUT_D%i\":\"%s\","), pinx, stt); + } + } + ResponseAppend_P(PSTR("\"END\":1}")); + } +#endif // USE_MCP230xx_OUTPUT ResponseJsonEnd(); } } @@ -794,6 +802,26 @@ void MCP230xx_Interrupt_Retain_Report(void) { MqttPublishTeleSensor(); } +void MCP230xx_SwitchRelay() { + + //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MCP: devices_present %d"), devices_present); + for (uint32_t i = devices_present - mcp230xx_oldoutpincount; i < devices_present; i++) { + uint8_t pin = mcp230xx_outpinmapping[i - (devices_present - mcp230xx_oldoutpincount)]; + uint8_t pincmd = Settings.mcp230xx_config[pin].pinmode - 5; + uint8_t relay_state = bitRead(XdrvMailbox.index, i); + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MCP: relay %d pin_no %d state %d"), i,pin, relay_state); + switch (relay_state) { + case 1: + MCP230xx_SetOutPin(pin,abs(pincmd-1)); + break; + case 0: + MCP230xx_SetOutPin(pin,pincmd); + break; + } + } +} + + /*********************************************************************************************\ Interface \*********************************************************************************************/ @@ -804,7 +832,7 @@ bool Xsns29(uint8_t function) bool result = false; - if (FUNC_INIT == function) { + if (FUNC_PRE_INIT == function) { MCP230xx_Detect(); } else if (mcp230xx_type) { @@ -836,6 +864,9 @@ bool Xsns29(uint8_t function) */ } break; + case FUNC_SET_POWER: + MCP230xx_SwitchRelay(); + break; case FUNC_JSON_APPEND: MCP230xx_Show(1); break; From d16cdb108c29af970b4774ec99168d8f0c5a6032 Mon Sep 17 00:00:00 2001 From: stefanbode Date: Mon, 3 Aug 2020 18:08:49 +0200 Subject: [PATCH 87/91] Added required hooks --- tasmota/support_tasmota.ino | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index db4ce592f..1c790fd57 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -207,6 +207,7 @@ void SetDevicePower(power_t rpower, uint32_t source) XdrvMailbox.index = rpower; XdrvCall(FUNC_SET_POWER); // Signal power state + XsnsCall(FUNC_SET_POWER); // Signal power state XdrvMailbox.index = rpower; XdrvMailbox.payload = source; @@ -1746,4 +1747,5 @@ void GpioInit(void) SetLedLink(Settings.ledstate &8); XdrvCall(FUNC_PRE_INIT); + XsnsCall(FUNC_PRE_INIT); } From a3445e5b5f9cb05680a45bebace14707eef8791c Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Mon, 3 Aug 2020 18:21:34 +0200 Subject: [PATCH 88/91] Add ESP32 ADC framework --- tasmota/settings.h | 2 + tasmota/support_button.ino | 30 +- tasmota/support_features.ino | 2 +- tasmota/support_tasmota.ino | 4 +- tasmota/tasmota.h | 1 + tasmota/tasmota_template_ESP32.h | 46 +-- tasmota/xdrv_01_webserver.ino | 2 +- tasmota/xdrv_07_domoticz.ino | 4 +- tasmota/xsns_02_analog.ino | 4 +- tasmota/xsns_02_analog_esp32.ino | 502 +++++++++++++++++++++++++++++++ 10 files changed, 561 insertions(+), 36 deletions(-) create mode 100644 tasmota/xsns_02_analog_esp32.ino diff --git a/tasmota/settings.h b/tasmota/settings.h index 913309393..880e8af80 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -691,8 +691,10 @@ typedef union { } StateBitfield; // See issue https://github.com/esp8266/Arduino/issues/2913 +#ifdef ESP8266 #ifdef USE_ADC_VCC ADC_MODE(ADC_VCC); // Set ADC input for Power Supply Voltage usage #endif +#endif #endif // _SETTINGS_H_ diff --git a/tasmota/support_button.ino b/tasmota/support_button.ino index e6e6e27ea..be8a4dabb 100644 --- a/tasmota/support_button.ino +++ b/tasmota/support_button.ino @@ -90,12 +90,14 @@ void ButtonInit(void) Button.present++; pinMode(Pin(GPIO_KEY1, i), bitRead(Button.no_pullup_mask, i) ? INPUT : ((16 == Pin(GPIO_KEY1, i)) ? INPUT_PULLDOWN_16 : INPUT_PULLUP)); } +#ifdef ESP8266 #ifndef USE_ADC_VCC else if ((99 == Button.adc) && ((ADC0_BUTTON == my_adc0) || (ADC0_BUTTON_INV == my_adc0))) { Button.present++; Button.adc = i; } #endif // USE_ADC_VCC +#endif // ESP8266 } } @@ -162,7 +164,18 @@ void ButtonHandler(void) button = (digitalRead(Pin(GPIO_KEY1, button_index)) != bitRead(Button.inverted_mask, button_index)); } } -#else +#ifndef USE_ADC_VCC + if (Button.adc == button_index) { + button_present = 1; + if (ADC0_BUTTON_INV == my_adc0) { + button = (AdcRead(1) < 128); + } + else if (ADC0_BUTTON == my_adc0) { + button = (AdcRead(1) > 128); + } + } +#endif // USE_ADC_VCC +#else // ESP32 if (PinUsed(GPIO_KEY1, button_index)) { button_present = 1; if (bitRead(Button.touch_mask, button_index)) { // Touch @@ -188,18 +201,7 @@ void ButtonHandler(void) button = (digitalRead(Pin(GPIO_KEY1, button_index)) != bitRead(Button.inverted_mask, button_index)); } } -#endif // ESP8266 -#ifndef USE_ADC_VCC - if (Button.adc == button_index) { - button_present = 1; - if (ADC0_BUTTON_INV == my_adc0) { - button = (AdcRead(1) < 128); - } - else if (ADC0_BUTTON == my_adc0) { - button = (AdcRead(1) > 128); - } - } -#endif // USE_ADC_VCC +#endif // ESP8266 or ESP32 if (button_present) { XdrvMailbox.index = button_index; XdrvMailbox.payload = button; @@ -333,7 +335,7 @@ void ButtonHandler(void) } } else { // 6 press start wificonfig 2 - if (!Settings.flag.button_restrict) { + if (!Settings.flag.button_restrict) { // SetOption1 - Control button multipress snprintf_P(scmnd, sizeof(scmnd), PSTR(D_CMND_WIFICONFIG " 2")); ExecuteCommand(scmnd, SRC_BUTTON); } diff --git a/tasmota/support_features.ino b/tasmota/support_features.ino index 0561eac6b..8b1bb3d96 100644 --- a/tasmota/support_features.ino +++ b/tasmota/support_features.ino @@ -230,7 +230,7 @@ void GetFeatures(void) #ifdef USE_COUNTER feature_sns1 |= 0x00000001; // xsns_01_counter.ino #endif -#ifdef USE_ADC_VCC +#if defined(USE_ADC_VCC) || defined(USE_ADC) feature_sns1 |= 0x00000002; // xsns_02_analog.ino #endif #ifdef USE_ENERGY_SENSOR diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index db4ce592f..bfe190069 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -651,10 +651,12 @@ void MqttShowState(void) ResponseAppendTime(); ResponseAppend_P(PSTR(",\"" D_JSON_UPTIME "\":\"%s\",\"UptimeSec\":%u"), GetUptime().c_str(), UpTime()); +#ifdef ESP8266 #ifdef USE_ADC_VCC dtostrfd((double)ESP.getVcc()/1000, 3, stemp1); ResponseAppend_P(PSTR(",\"" D_JSON_VCC "\":%s"), stemp1); -#endif +#endif // USE_ADC_VCC +#endif // ESP8266 ResponseAppend_P(PSTR(",\"" D_JSON_HEAPSIZE "\":%d,\"SleepMode\":\"%s\",\"Sleep\":%u,\"LoadAvg\":%u,\"MqttCount\":%u"), ESP_getFreeHeap()/1024, GetTextIndexed(stemp1, sizeof(stemp1), Settings.flag3.sleep_normal, kSleepMode), // SetOption60 - Enable normal sleep instead of dynamic sleep diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 21a7b5b00..29c8875c7 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -85,6 +85,7 @@ const uint8_t MAX_DEV_GROUP_NAMES = 4; // Max number of Device Group names const uint8_t MAX_HUE_DEVICES = 15; // Max number of Philips Hue device per emulation const uint8_t MAX_ROTARIES = 2; // Max number of Rotary Encoders +const uint8_t MAX_ADCS = 18; // Max number of ESP32 ADC pins const char MQTT_TOKEN_PREFIX[] PROGMEM = "%prefix%"; // To be substituted by mqtt_prefix[x] const char MQTT_TOKEN_TOPIC[] PROGMEM = "%topic%"; // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index ddd13d87b..923a278c6 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -36,7 +36,6 @@ // Not ported (yet) #undef USE_DISCOVERY -#undef USE_ADC_VCC // Needs to be ported #undef USE_DEEPSLEEP #undef USE_MY92X1 #undef USE_TUYA_MCU @@ -115,12 +114,12 @@ enum UserSelectablePins { GPIO_HRXL_RX, // Data from MaxBotix HRXL sonar range sensor GPIO_ELECTRIQ_MOODL_TX, // ElectriQ iQ-wifiMOODL Serial TX GPIO_AS3935, - ADC0_INPUT, // Analog input - ADC0_TEMP, // Analog Thermistor - ADC0_LIGHT, // Analog Light sensor - ADC0_BUTTON, ADC0_BUTTON_INV, // Analog Button - ADC0_RANGE, // Analog Range - ADC0_CT_POWER, // ANalog Current + GPIO_ADC_INPUT, // Analog input + GPIO_ADC_TEMP, // Analog Thermistor + GPIO_ADC_LIGHT, // Analog Light sensor + GPIO_ADC_BUTTON, GPIO_ADC_BUTTON_INV, // Analog Button + GPIO_ADC_RANGE, // Analog Range + GPIO_ADC_CT_POWER, // ANalog Current GPIO_WEBCAM_PWDN, GPIO_WEBCAM_RESET, GPIO_WEBCAM_XCLK, // Webcam GPIO_WEBCAM_SIOD, GPIO_WEBCAM_SIOC, // Webcam I2C GPIO_WEBCAM_DATA, @@ -557,17 +556,15 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_TELEINFO_RX), AGPIO(GPIO_TELEINFO_ENABLE), #endif -/* -#ifndef USE_ADC_VCC - AGPIO(ADC0_INPUT), // Analog input - AGPIO(ADC0_TEMP), // Thermistor - AGPIO(ADC0_LIGHT), // Light sensor - AGPIO(ADC0_BUTTON), // Button - AGPIO(ADC0_BUTTON_INV), - AGPIO(ADC0_RANGE), // Range - AGPIO(ADC0_CT_POWER), // Current +#ifdef USE_ADC + AGPIO(GPIO_ADC_INPUT) + MAX_ADCS, // Analog inputs + AGPIO(GPIO_ADC_TEMP) + MAX_ADCS, // Thermistor + AGPIO(GPIO_ADC_LIGHT) + MAX_ADCS, // Light sensor + AGPIO(GPIO_ADC_BUTTON) + MAX_ADCS, // Button + AGPIO(GPIO_ADC_BUTTON_INV) + MAX_ADCS, + AGPIO(GPIO_ADC_RANGE) + MAX_ADCS, // Range + AGPIO(GPIO_ADC_CT_POWER) + MAX_ADCS, // Current #endif -*/ #ifdef USE_WEBCAM AGPIO(GPIO_WEBCAM_PWDN), AGPIO(GPIO_WEBCAM_RESET), @@ -591,6 +588,21 @@ const uint16_t kGpioNiceList[] PROGMEM = { //******************************************************************************************** +// User selectable ADC functionality +enum UserSelectableAdc { + ADC_NONE, // Not used + ADC_INPUT, // Analog input + ADC_TEMP, // Thermistor + ADC_LIGHT, // Light sensor + ADC_BUTTON, // Button + ADC_BUTTON_INV, + ADC_RANGE, // Range + ADC_CT_POWER, // Current + +// ADC_SWITCH, // Switch +// ADC_SWITCH_INV, + ADC_END }; + #define MAX_GPIO_PIN 40 // Number of supported GPIO #define MIN_FLASH_PINS 4 // Number of flash chip pins unusable for configuration (GPIO6, 7, 8 and 11) #define MAX_USER_PINS 36 // MAX_GPIO_PIN - MIN_FLASH_PINS diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 016240b35..65ea3497d 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -1921,7 +1921,7 @@ void HandleModuleConfiguration(void) } WSContentSend_P(PSTR("\";sk(%d," STR(ADC0_PIN) ");"), Settings.my_adc0); #endif // USE_ADC_VCC -#endif // ESP8266 - ESP32 +#endif // ESP8266 WSContentSend_P(PSTR("}wl(sl);")); diff --git a/tasmota/xdrv_07_domoticz.ino b/tasmota/xdrv_07_domoticz.ino index 4f26a2c8a..2ea842491 100644 --- a/tasmota/xdrv_07_domoticz.ino +++ b/tasmota/xdrv_07_domoticz.ino @@ -66,6 +66,7 @@ int DomoticzBatteryQuality(void) { int quality = 100; // Voltage range from 2,6V > 0% to 3,6V > 100% +#ifdef ESP8266 #ifdef USE_ADC_VCC uint16_t voltage = ESP.getVcc(); if (voltage <= 2600) { @@ -75,7 +76,8 @@ int DomoticzBatteryQuality(void) { } else { quality = (voltage - 2600) / 10; } -#endif +#endif // USE_ADC_VCC +#endif // ESP8266 return quality; } diff --git a/tasmota/xsns_02_analog.ino b/tasmota/xsns_02_analog.ino index 235a91bdd..963406b3f 100644 --- a/tasmota/xsns_02_analog.ino +++ b/tasmota/xsns_02_analog.ino @@ -17,6 +17,7 @@ along with this program. If not, see . */ +#ifdef ESP8266 #ifndef USE_ADC_VCC /*********************************************************************************************\ * ADC support @@ -455,4 +456,5 @@ bool Xsns02(uint8_t function) return result; } -#endif // USE_ADC_VCC \ No newline at end of file +#endif // USE_ADC_VCC +#endif // ESP8266 diff --git a/tasmota/xsns_02_analog_esp32.ino b/tasmota/xsns_02_analog_esp32.ino new file mode 100644 index 000000000..0339f8345 --- /dev/null +++ b/tasmota/xsns_02_analog_esp32.ino @@ -0,0 +1,502 @@ +/* + xsns_02_analog_esp32.ino - ESP32 ADC support for Tasmota + + Copyright (C) 2020 Theo Arends + + 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. + + 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. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ESP32 +#ifdef USE_ADC +/*********************************************************************************************\ + * ADC support +\*********************************************************************************************/ + +#define XSNS_02 2 + +#define TO_CELSIUS(x) ((x) - 273.15) +#define TO_KELVIN(x) ((x) + 273.15) + +// Parameters for equation +#define ANALOG_V33 3.3 // ESP8266 Analog voltage +#define ANALOG_T0 TO_KELVIN(25.0) // 25 degrees Celcius in Kelvin (= 298.15) + +// Shelly 2.5 NTC Thermistor +// 3V3 --- ANALOG_NTC_BRIDGE_RESISTANCE ---v--- NTC --- Gnd +// | +// ADC0 +#define ANALOG_NTC_BRIDGE_RESISTANCE 32000 // NTC Voltage bridge resistor +#define ANALOG_NTC_RESISTANCE 10000 // NTC Resistance +#define ANALOG_NTC_B_COEFFICIENT 3350 // NTC Beta Coefficient + +// LDR parameters +// 3V3 --- LDR ---v--- ANALOG_LDR_BRIDGE_RESISTANCE --- Gnd +// | +// ADC0 +#define ANALOG_LDR_BRIDGE_RESISTANCE 10000 // LDR Voltage bridge resistor +#define ANALOG_LDR_LUX_CALC_SCALAR 12518931 // Experimental +#define ANALOG_LDR_LUX_CALC_EXPONENT -1.4050 // Experimental + +// CT Based Apparrent Power Measurement Parameters +// 3V3 --- R1 ----v--- R1 --- Gnd +// | +// CT+ CT- +// | +// ADC0 +// Default settings for a 20A/1V Current Transformer. +// Analog peak to peak range is measured and converted to RMS current using ANALOG_CT_MULTIPLIER +#define ANALOG_CT_FLAGS 0 // (uint32_t) reserved for possible future use +#define ANALOG_CT_MULTIPLIER 2146 // (uint32_t) Multiplier*100000 to convert raw ADC peak to peak range 0..1023 to RMS current in Amps. Value of 100000 corresponds to 1 +#define ANALOG_CT_VOLTAGE 2300 // (int) Convert current in Amps to apparrent power in Watts using voltage in Volts*10. Value of 2200 corresponds to 220V + +#define CT_FLAG_ENERGY_RESET (1 << 0) // Reset energy total + +uint8_t adc_present = 0; + +struct { + float temperature = 0; + float current = 0; + float energy = 0; + uint32_t previous_millis = 0; + uint16_t last_value = 0; + uint8_t type = 0; + uint8_t pin = 0; +} Adc[MAX_ADCS]; + +void AdcInitParams(void) { + my_adc0 = Adc[0].type; + + if ((Settings.adc_param_type != my_adc0) || (Settings.adc_param1 > 1000000)) { + if (ADC_TEMP == my_adc0) { + // Default Shelly 2.5 and 1PM parameters + Settings.adc_param_type = ADC_TEMP; + Settings.adc_param1 = ANALOG_NTC_BRIDGE_RESISTANCE; + Settings.adc_param2 = ANALOG_NTC_RESISTANCE; + Settings.adc_param3 = ANALOG_NTC_B_COEFFICIENT * 10000; + } + else if (ADC_LIGHT == my_adc0) { + Settings.adc_param_type = ADC_LIGHT; + Settings.adc_param1 = ANALOG_LDR_BRIDGE_RESISTANCE; + Settings.adc_param2 = ANALOG_LDR_LUX_CALC_SCALAR; + Settings.adc_param3 = ANALOG_LDR_LUX_CALC_EXPONENT * 10000; + } + else if (ADC_RANGE == my_adc0) { + Settings.adc_param_type = ADC_RANGE; + Settings.adc_param1 = 0; + Settings.adc_param2 = 1023; + Settings.adc_param3 = 0; + Settings.adc_param4 = 100; + } + else if (ADC_CT_POWER == my_adc0) { + Settings.adc_param_type = ADC_CT_POWER; + Settings.adc_param1 = ANALOG_CT_FLAGS; //(uint32_t) 0 + Settings.adc_param2 = ANALOG_CT_MULTIPLIER; //(uint32_t) 100000 + Settings.adc_param3 = ANALOG_CT_VOLTAGE; //(int) 10 + } + } +} + +void AdcInit(void) { + adc_present = 0; + for (uint32_t i = 0; i < MAX_ADCS; i++) { + if (PinUsed(GPIO_ADC_INPUT, i)) { + Adc[adc_present].pin = Pin(GPIO_ADC_INPUT, i); + if (adcAttachPin(Adc[adc_present].pin)) { + Adc[adc_present].type = ADC_INPUT; +// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default + adc_present++; + } + } + if (PinUsed(GPIO_ADC_TEMP, i)) { + Adc[adc_present].pin = Pin(GPIO_ADC_TEMP, i); + if (adcAttachPin(Adc[adc_present].pin)) { + Adc[adc_present].type = ADC_TEMP; +// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default + adc_present++; + } + } + if (PinUsed(GPIO_ADC_LIGHT, i)) { + Adc[adc_present].pin = Pin(GPIO_ADC_LIGHT, i); + if (adcAttachPin(Adc[adc_present].pin)) { + Adc[adc_present].type = ADC_LIGHT; +// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default + adc_present++; + } + } + if (PinUsed(GPIO_ADC_BUTTON, i)) { + Adc[adc_present].pin = Pin(GPIO_ADC_BUTTON, i); + if (adcAttachPin(Adc[adc_present].pin)) { + Adc[adc_present].type = ADC_BUTTON; +// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default + adc_present++; + } + } + if (PinUsed(ADC_BUTTON_INV, i)) { + Adc[adc_present].pin = Pin(ADC_BUTTON_INV, i); + if (adcAttachPin(Adc[adc_present].pin)) { + Adc[adc_present].type = ADC_BUTTON_INV; +// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default + adc_present++; + } + } + if (PinUsed(GPIO_ADC_RANGE, i)) { + Adc[adc_present].pin = Pin(GPIO_ADC_RANGE, i); + if (adcAttachPin(Adc[adc_present].pin)) { + Adc[adc_present].type = ADC_RANGE; +// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default + adc_present++; + } + } + if (PinUsed(GPIO_ADC_CT_POWER, i)) { + Adc[adc_present].pin = Pin(GPIO_ADC_CT_POWER, i); + if (adcAttachPin(Adc[adc_present].pin)) { + Adc[adc_present].type = ADC_CT_POWER; +// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default + adc_present++; + } + } + } + if (adc_present) { + analogSetClockDiv(1); // Default 1 + analogSetWidth(12); // Default 12 bits (0 - 4095) + analogSetAttenuation(ADC_11db); // Default 11db + } + AdcInitParams(); +} + +uint16_t AdcRead(uint8_t pin, uint8_t factor) { + // factor 1 = 2 samples + // factor 2 = 4 samples + // factor 3 = 8 samples + // factor 4 = 16 samples + // factor 5 = 32 samples + uint8_t samples = 1 << factor; + uint16_t analog = 0; + for (uint32_t i = 0; i < samples; i++) { + analog += analogRead(pin); + delay(1); + } + analog >>= factor; + return analog; +} + +#ifdef USE_RULES +void AdcEvery250ms(void) { + for (uint32_t idx = 0; idx < adc_present; idx++) { + if (ADC_INPUT == Adc[idx].type) { + uint16_t new_value = AdcRead(Adc[idx].pin, 5); + if ((new_value < Adc[idx].last_value -10) || (new_value > Adc[idx].last_value +10)) { + Adc[idx].last_value = new_value; + uint16_t value = Adc[idx].last_value / 10; + Response_P(PSTR("{\"ANALOG\":{\"A%ddiv10\":%d}}"), idx, (value > 99) ? 100 : value); + XdrvRulesProcess(); + } + } + } +} +#endif // USE_RULES + +uint16_t AdcGetLux(uint8_t pin) { + int adc = AdcRead(pin, 2); + // Source: https://www.allaboutcircuits.com/projects/design-a-luxmeter-using-a-light-dependent-resistor/ + double resistorVoltage = ((double)adc / 1023) * ANALOG_V33; + double ldrVoltage = ANALOG_V33 - resistorVoltage; + double ldrResistance = ldrVoltage / resistorVoltage * (double)Settings.adc_param1; + double ldrLux = (double)Settings.adc_param2 * FastPrecisePow(ldrResistance, (double)Settings.adc_param3 / 10000); + + return (uint16_t)ldrLux; +} + +uint16_t AdcGetRange(uint8_t pin) { + // formula for calibration: value, fromLow, fromHigh, toLow, toHigh + // Example: 514, 632, 236, 0, 100 + // int( (( - ) / ( - ) ) * ( - ) ) + ) + int adc = AdcRead(pin, 2); + double adcrange = ( ((double)Settings.adc_param2 - (double)adc) / ( ((double)Settings.adc_param2 - (double)Settings.adc_param1)) * ((double)Settings.adc_param3 - (double)Settings.adc_param4) + (double)Settings.adc_param4 ); + return (uint16_t)adcrange; +} + +void AdcGetCurrentPower(uint8_t idx, uint8_t factor) { + // factor 1 = 2 samples + // factor 2 = 4 samples + // factor 3 = 8 samples + // factor 4 = 16 samples + // factor 5 = 32 samples + uint8_t samples = 1 << factor; + uint16_t analog = 0; + uint16_t analog_min = 1023; + uint16_t analog_max = 0; + + if (0 == Settings.adc_param1) { + for (uint32_t i = 0; i < samples; i++) { + analog = analogRead(Adc[idx].pin); + if (analog < analog_min) { + analog_min = analog; + } + if (analog > analog_max) { + analog_max = analog; + } + delay(1); + } + Adc[idx].current = (float)(analog_max-analog_min) * ((float)(Settings.adc_param2) / 100000); + } + else { + analog = AdcRead(Adc[idx].pin, 5); + if (analog > Settings.adc_param1) { + Adc[idx].current = ((float)(analog) - (float)Settings.adc_param1) * ((float)(Settings.adc_param2) / 100000); + } + else { + Adc[idx].current = 0; + } + } + + float power = Adc[idx].current * (float)(Settings.adc_param3) / 10; + uint32_t current_millis = millis(); + Adc[idx].energy = Adc[idx].energy + ((power * (current_millis - Adc[idx].previous_millis)) / 3600000000); + Adc[idx].previous_millis = current_millis; +} + +void AdcEverySecond(void) { + for (uint32_t idx = 0; idx < adc_present; idx++) { + if (ADC_TEMP == Adc[idx].type) { + int adc = AdcRead(Adc[idx].pin, 2); + // Steinhart-Hart equation for thermistor as temperature sensor + double Rt = (adc * Settings.adc_param1) / (1024.0 * ANALOG_V33 - (double)adc); + double BC = (double)Settings.adc_param3 / 10000; + double T = BC / (BC / ANALOG_T0 + TaylorLog(Rt / (double)Settings.adc_param2)); + Adc[idx].temperature = ConvertTemp(TO_CELSIUS(T)); + } + else if (ADC_CT_POWER == Adc[idx].type) { + AdcGetCurrentPower(idx, 5); + } + } +} + +void AdcShow(bool json) { + bool domo_flag[ADC_END] = { false }; + char adc_name[10]; // ANALOG12 + for (uint32_t idx = 0; idx < adc_present; idx++) { + snprintf_P(adc_name, sizeof(adc_name), PSTR("ANALOG%d"), idx); + + switch (Adc[idx].type) { + case ADC_INPUT: { + uint16_t analog = AdcRead(Adc[idx].pin, 5); + + if (json) { + ResponseAppend_P(PSTR(",\"%s\":{\"A0\":%d}"), adc_name, analog); +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_ANALOG, "", idx, analog); +#endif // USE_WEBSERVER + } + break; + } + case ADC_TEMP: { + char temperature[33]; + dtostrfd(Adc[idx].temperature, Settings.flag2.temperature_resolution, temperature); + + if (json) { + ResponseAppend_P(JSON_SNS_TEMP, adc_name, temperature); + if ((0 == tele_period) && (!domo_flag[ADC_TEMP])) { +#ifdef USE_DOMOTICZ + DomoticzSensor(DZ_TEMP, temperature); + domo_flag[ADC_TEMP] = true; +#endif // USE_DOMOTICZ +#ifdef USE_KNX + KnxSensor(KNX_TEMPERATURE, Adc[idx].temperature); +#endif // USE_KNX + } +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_TEMP, adc_name, temperature, TempUnit()); +#endif // USE_WEBSERVER + } + break; + } + case ADC_LIGHT: { + uint16_t adc_light = AdcGetLux(Adc[idx].pin); + + if (json) { + ResponseAppend_P(JSON_SNS_ILLUMINANCE, adc_name, adc_light); +#ifdef USE_DOMOTICZ + if ((0 == tele_period) && (!domo_flag[ADC_LIGHT])) { + DomoticzSensor(DZ_ILLUMINANCE, adc_light); + domo_flag[ADC_LIGHT] = true; + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_ILLUMINANCE, adc_name, adc_light); +#endif // USE_WEBSERVER + } + break; + } + case ADC_RANGE: { + uint16_t adc_range = AdcGetRange(Adc[idx].pin); + + if (json) { + ResponseAppend_P(JSON_SNS_RANGE, adc_name, adc_range); +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_RANGE, adc_name, adc_range); +#endif // USE_WEBSERVER + } + break; + } + case ADC_CT_POWER: { + AdcGetCurrentPower(idx, 5); + + float voltage = (float)(Settings.adc_param3) / 10; + char voltage_chr[FLOATSZ]; + dtostrfd(voltage, Settings.flag2.voltage_resolution, voltage_chr); + char current_chr[FLOATSZ]; + dtostrfd(Adc[idx].current, Settings.flag2.current_resolution, current_chr); + char power_chr[FLOATSZ]; + dtostrfd(voltage * Adc[idx].current, Settings.flag2.wattage_resolution, power_chr); + char energy_chr[FLOATSZ]; + dtostrfd(Adc[idx].energy, Settings.flag2.energy_resolution, energy_chr); + + if (json) { + ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ENERGY "\":%s,\"" D_JSON_POWERUSAGE "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), + adc_name, energy_chr, power_chr, voltage_chr, current_chr); +#ifdef USE_DOMOTICZ + if ((0 == tele_period) && (!domo_flag[ADC_CT_POWER])) { + DomoticzSensor(DZ_POWER_ENERGY, power_chr); + DomoticzSensor(DZ_VOLTAGE, voltage_chr); + DomoticzSensor(DZ_CURRENT, current_chr); + domo_flag[ADC_CT_POWER] = true; + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + WSContentSend_PD(HTTP_SNS_VOLTAGE, voltage_chr); + WSContentSend_PD(HTTP_SNS_CURRENT, current_chr); + WSContentSend_PD(HTTP_SNS_POWER, power_chr); + WSContentSend_PD(HTTP_SNS_ENERGY_TOTAL, energy_chr); +#endif // USE_WEBSERVER + } + break; + } + } + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +const char kAdcCommands[] PROGMEM = "|" // No prefix + D_CMND_ADCPARAM; + +void (* const AdcCommand[])(void) PROGMEM = { + &CmndAdcParam }; + +void CmndAdcParam(void) { + if (XdrvMailbox.data_len) { + if ((ADC_TEMP == XdrvMailbox.payload) || + (ADC_LIGHT == XdrvMailbox.payload) || + (ADC_RANGE == XdrvMailbox.payload) || + (ADC_CT_POWER == XdrvMailbox.payload)) { + if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry + char sub_string[XdrvMailbox.data_len +1]; + // AdcParam 2, 32000, 10000, 3350 + // AdcParam 3, 10000, 12518931, -1.405 + // AdcParam 6, 0, 1023, 0, 100 + Settings.adc_param_type = XdrvMailbox.payload; + Settings.adc_param1 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); + Settings.adc_param2 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 3), nullptr, 10); + if (ADC_RANGE == XdrvMailbox.payload) { + Settings.adc_param3 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 4), nullptr, 10)); + Settings.adc_param4 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 5), nullptr, 10)); + } else { + Settings.adc_param3 = (int)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000); + } + if (ADC_CT_POWER == XdrvMailbox.payload) { + if (((1 == Settings.adc_param1) & CT_FLAG_ENERGY_RESET) > 0) { + for (uint32_t idx = 0; idx < MAX_ADCS; idx++) { + Adc[idx].energy = 0; + } + Settings.adc_param1 ^= CT_FLAG_ENERGY_RESET; // Cancel energy reset flag + } + } + } else { // Set default values based on current adc type + // AdcParam 2 + // AdcParam 3 + // AdcParam 6 + // AdcParam 7 + Settings.adc_param_type = 0; + AdcInitParams(); + } + } + } + + // AdcParam + Response_P(PSTR("{\"" D_CMND_ADCPARAM "\":[%d,%d,%d"), Settings.adc_param_type, Settings.adc_param1, Settings.adc_param2); + if (ADC_RANGE == my_adc0) { + ResponseAppend_P(PSTR(",%d,%d"), Settings.adc_param3, Settings.adc_param4); + } else { + int value = Settings.adc_param3; + uint8_t precision; + for (precision = 4; precision > 0; precision--) { + if (value % 10) { break; } + value /= 10; + } + char param3[33]; + dtostrfd(((double)Settings.adc_param3)/10000, precision, param3); + ResponseAppend_P(PSTR(",%s"), param3); + } + ResponseAppend_P(PSTR("]}")); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xsns02(uint8_t function) { + bool result = false; + + switch (function) { + case FUNC_COMMAND: + result = DecodeCommand(kAdcCommands, AdcCommand); + break; + case FUNC_INIT: + AdcInit(); + break; + default: + if (adc_present) { + switch (function) { +#ifdef USE_RULES + case FUNC_EVERY_250_MSECOND: + AdcEvery250ms(); + break; +#endif // USE_RULES + case FUNC_EVERY_SECOND: + AdcEverySecond(); + break; + case FUNC_JSON_APPEND: + AdcShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_SENSOR: + AdcShow(0); + break; +#endif // USE_WEBSERVER + } + } + } + return result; +} + +#endif // USE_ADC +#endif // ESP32 From 35b0d671b7d585d29a1f853a7681c092d67ad9a3 Mon Sep 17 00:00:00 2001 From: stefanbode Date: Tue, 4 Aug 2020 08:31:50 +0200 Subject: [PATCH 89/91] Update xsns_29_mcp230xx.ino - Removed custom code for INTERLOCK. referenced to normal INTERLOCK groups trough POWER command. - Compiler Options to save space - redirect sensor29 set relay status to POWER command --- tasmota/xsns_29_mcp230xx.ino | 80 +++++++++++++++++------------------- 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/tasmota/xsns_29_mcp230xx.ino b/tasmota/xsns_29_mcp230xx.ino index 70255df12..b12eceeff 100644 --- a/tasmota/xsns_29_mcp230xx.ino +++ b/tasmota/xsns_29_mcp230xx.ino @@ -46,7 +46,9 @@ uint8_t MCP230xx_GPIO = 0x09; uint8_t mcp230xx_type = 0; uint8_t mcp230xx_pincount = 0; uint8_t mcp230xx_oldoutpincount = 0; +#ifdef USE_MCP230xx_OUTPUT uint8_t mcp230xx_outpinmapping[16]; +#endif uint8_t mcp230xx_int_en = 0; uint8_t mcp230xx_int_prio_counter = 0; uint8_t mcp230xx_int_counter_en = 0; @@ -347,24 +349,24 @@ void MCP230xx_Show(bool json) (gpiob>>0)&1, (gpiob>>1)&1, (gpiob>>2)&1, (gpiob>>3)&1, (gpiob>>4)&1, (gpiob>>5)&1, (gpiob>>6)&1, (gpiob>>7)&1); } -#ifdef USE_MCP230xx_OUTPUT - uint8_t outputcount = 0; - for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { - if (Settings.mcp230xx_config[pinx].pinmode >= 5) { outputcount++; } - } - if (outputcount) { - uint16_t gpiototal = ((uint16_t)gpiob << 8) | gpio; - ResponseAppend_P(PSTR(",\"MCP230_OUT\":{")); - char stt[7]; - for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { - if (Settings.mcp230xx_config[pinx].pinmode >= 5) { - sprintf(stt, ConvertNumTxt(((gpiototal>>pinx)&1), Settings.mcp230xx_config[pinx].pinmode)); - ResponseAppend_P(PSTR("\"OUT_D%i\":\"%s\","), pinx, stt); - } - } - ResponseAppend_P(PSTR("\"END\":1}")); - } -#endif // USE_MCP230xx_OUTPUT +#ifdef USE_MCP230xx_OUTPUT + uint8_t outputcount = 0; + for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { + if (Settings.mcp230xx_config[pinx].pinmode >= 5) { outputcount++; } + } + if (outputcount) { + uint16_t gpiototal = ((uint16_t)gpiob << 8) | gpio; + ResponseAppend_P(PSTR(",\"MCP230_OUT\":{")); + char stt[7]; + for (uint32_t pinx = 0; pinx < mcp230xx_pincount; pinx++) { + if (Settings.mcp230xx_config[pinx].pinmode >= 5) { + sprintf(stt, ConvertNumTxt(((gpiototal>>pinx)&1), Settings.mcp230xx_config[pinx].pinmode)); + ResponseAppend_P(PSTR("\"OUT_D%i\":\"%s\","), pinx, stt); + } + } + ResponseAppend_P(PSTR("\"END\":1}")); + } +#endif // USE_MCP230xx_OUTPUT ResponseJsonEnd(); } } @@ -380,27 +382,13 @@ void MCP230xx_SetOutPin(uint8_t pin,uint8_t pinstate) { char cmnd[7], stt[4]; if (pin > 7) { port = 1; } portpins = MCP230xx_readGPIO(port); - if (interlock && (pinmo == Settings.mcp230xx_config[pin+pinadd].pinmode)) { - if (pinstate < 2) { - if (6 == pinmo) { - if (pinstate) portpins |= (1 << (pin-(port*8))); else portpins |= (1 << (pin+pinadd-(port*8))),portpins &= ~(1 << (pin-(port*8))); - } else { - if (pinstate) portpins &= ~(1 << (pin+pinadd-(port*8))),portpins |= (1 << (pin-(port*8))); else portpins &= ~(1 << (pin-(port*8))); - } - } else { - if (6 == pinmo) { - portpins |= (1 << (pin+pinadd-(port*8))),portpins ^= (1 << (pin-(port*8))); - } else { - portpins &= ~(1 << (pin+pinadd-(port*8))),portpins ^= (1 << (pin-(port*8))); - } - } + + if (pinstate < 2) { + if (pinstate) portpins |= (1 << (pin-(port*8))); else portpins &= ~(1 << (pin-(port*8))); } else { - if (pinstate < 2) { - if (pinstate) portpins |= (1 << (pin-(port*8))); else portpins &= ~(1 << (pin-(port*8))); - } else { - portpins ^= (1 << (pin-(port*8))); - } + portpins ^= (1 << (pin-(port*8))); } + I2cWrite8(USE_MCP230xx_ADDR, MCP230xx_GPIO + port, portpins); if (Settings.flag.save_state) { // SetOption0 - Save power state and use after restart - Firmware configured to save last known state in settings Settings.mcp230xx_config[pin].saved_state=portpins>>(pin-(port*8))&1; @@ -657,16 +645,21 @@ bool MCP230xx_Command(void) #ifdef USE_MCP230xx_OUTPUT if (Settings.mcp230xx_config[pin].pinmode >= 5) { uint8_t pincmd = Settings.mcp230xx_config[pin].pinmode - 5; + uint8_t relay_no = 0; + for (relay_no = 0; relay_no < mcp230xx_pincount ; relay_no ++) { + if ( mcp230xx_outpinmapping[relay_no] == pin) break; + } + relay_no = devices_present - mcp230xx_oldoutpincount + relay_no +1; if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "ON")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "1"))) { - MCP230xx_SetOutPin(pin,abs(pincmd-1)); + ExecuteCommandPower(relay_no, 1, SRC_IGNORE); return serviced; } if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "OFF")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "0"))) { - MCP230xx_SetOutPin(pin,pincmd); + ExecuteCommandPower(relay_no, 0, SRC_IGNORE); return serviced; } if ((!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "T")) || (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 2), "2"))) { - MCP230xx_SetOutPin(pin,2); + ExecuteCommandPower(relay_no, 2, SRC_IGNORE); return serviced; } } @@ -802,9 +795,8 @@ void MCP230xx_Interrupt_Retain_Report(void) { MqttPublishTeleSensor(); } +#ifdef USE_MCP230xx_OUTPUT void MCP230xx_SwitchRelay() { - - //AddLog_P2(LOG_LEVEL_DEBUG, PSTR("MCP: devices_present %d"), devices_present); for (uint32_t i = devices_present - mcp230xx_oldoutpincount; i < devices_present; i++) { uint8_t pin = mcp230xx_outpinmapping[i - (devices_present - mcp230xx_oldoutpincount)]; uint8_t pincmd = Settings.mcp230xx_config[pin].pinmode - 5; @@ -820,7 +812,7 @@ void MCP230xx_SwitchRelay() { } } } - +#endif // USE_MCP230xx_OUTPUT /*********************************************************************************************\ Interface @@ -864,9 +856,11 @@ bool Xsns29(uint8_t function) */ } break; +#ifdef USE_MCP230xx_OUTPUT case FUNC_SET_POWER: MCP230xx_SwitchRelay(); break; +#endif // USE_MCP230xx_OUTPUT case FUNC_JSON_APPEND: MCP230xx_Show(1); break; From ce388c799f52ceb92c6a4d3404202ebfa850552a Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 4 Aug 2020 16:33:05 +0200 Subject: [PATCH 90/91] Add ESP32 Analog input support for GPIO32 to GPIO39 --- RELEASENOTES.md | 1 + tasmota/CHANGELOG.md | 1 + tasmota/language/bg_BG.h | 7 + tasmota/language/cs_CZ.h | 7 + tasmota/language/de_DE.h | 7 + tasmota/language/el_GR.h | 7 + tasmota/language/en_GB.h | 7 + tasmota/language/es_ES.h | 7 + tasmota/language/fr_FR.h | 7 + tasmota/language/he_HE.h | 7 + tasmota/language/hu_HU.h | 7 + tasmota/language/it_IT.h | 7 + tasmota/language/ko_KO.h | 7 + tasmota/language/nl_NL.h | 7 + tasmota/language/pl_PL.h | 7 + tasmota/language/pt_BR.h | 7 + tasmota/language/pt_PT.h | 7 + tasmota/language/ro_RO.h | 7 + tasmota/language/ru_RU.h | 7 + tasmota/language/sk_SK.h | 7 + tasmota/language/sv_SE.h | 7 + tasmota/language/tr_TR.h | 7 + tasmota/language/uk_UA.h | 7 + tasmota/language/zh_CN.h | 7 + tasmota/language/zh_TW.h | 7 + tasmota/my_user_config.h | 2 + tasmota/support.ino | 26 ++- tasmota/tasmota.h | 5 +- tasmota/tasmota_template_ESP32.h | 22 +- tasmota/xsns_02_analog_esp32.ino | 332 +++++++++++++++++-------------- 30 files changed, 385 insertions(+), 165 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 5a0d46ab4..1bfd9e2d3 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -57,3 +57,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Fix ESP32 PWM range - Add Zigbee better support for IKEA Motion Sensor +- Add ESP32 Analog input support for GPIO32 to GPIO39 diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 7ceb6f7c1..f850de769 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -4,6 +4,7 @@ - Fix ESP32 PWM range - Add Zigbee better support for IKEA Motion Sensor +- Add ESP32 Analog input support for GPIO32 to GPIO39 ### 8.4.0 20200730 diff --git a/tasmota/language/bg_BG.h b/tasmota/language/bg_BG.h index f0ff9b818..4439692f0 100644 --- a/tasmota/language/bg_BG.h +++ b/tasmota/language/bg_BG.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/cs_CZ.h b/tasmota/language/cs_CZ.h index f85fc4439..3bc5f33d4 100644 --- a/tasmota/language/cs_CZ.h +++ b/tasmota/language/cs_CZ.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/de_DE.h b/tasmota/language/de_DE.h index 05d72f4db..f4e624ed4 100644 --- a/tasmota/language/de_DE.h +++ b/tasmota/language/de_DE.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/el_GR.h b/tasmota/language/el_GR.h index ea2db9c98..f557444de 100644 --- a/tasmota/language/el_GR.h +++ b/tasmota/language/el_GR.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/en_GB.h b/tasmota/language/en_GB.h index 9a79758d8..6fe834fc2 100644 --- a/tasmota/language/en_GB.h +++ b/tasmota/language/en_GB.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/es_ES.h b/tasmota/language/es_ES.h index 02f41e118..8fd50b7a2 100644 --- a/tasmota/language/es_ES.h +++ b/tasmota/language/es_ES.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/fr_FR.h b/tasmota/language/fr_FR.h index 05bbf565e..7d0868aa8 100644 --- a/tasmota/language/fr_FR.h +++ b/tasmota/language/fr_FR.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/he_HE.h b/tasmota/language/he_HE.h index 2db6b36ab..a34c84329 100644 --- a/tasmota/language/he_HE.h +++ b/tasmota/language/he_HE.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/hu_HU.h b/tasmota/language/hu_HU.h index 917d2a155..41a6b472e 100644 --- a/tasmota/language/hu_HU.h +++ b/tasmota/language/hu_HU.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/it_IT.h b/tasmota/language/it_IT.h index c45dc094f..f03d8c06f 100644 --- a/tasmota/language/it_IT.h +++ b/tasmota/language/it_IT.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/ko_KO.h b/tasmota/language/ko_KO.h index 61c9ba720..84bd1b003 100644 --- a/tasmota/language/ko_KO.h +++ b/tasmota/language/ko_KO.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/nl_NL.h b/tasmota/language/nl_NL.h index 139bf4837..0a96682d3 100644 --- a/tasmota/language/nl_NL.h +++ b/tasmota/language/nl_NL.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/pl_PL.h b/tasmota/language/pl_PL.h index c31dc569a..5582fd7ea 100644 --- a/tasmota/language/pl_PL.h +++ b/tasmota/language/pl_PL.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/pt_BR.h b/tasmota/language/pt_BR.h index dcb308ae9..872459542 100644 --- a/tasmota/language/pt_BR.h +++ b/tasmota/language/pt_BR.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/pt_PT.h b/tasmota/language/pt_PT.h index a34d0e1d1..b68d06861 100644 --- a/tasmota/language/pt_PT.h +++ b/tasmota/language/pt_PT.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/ro_RO.h b/tasmota/language/ro_RO.h index fa01b1705..5ff7697df 100644 --- a/tasmota/language/ro_RO.h +++ b/tasmota/language/ro_RO.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/ru_RU.h b/tasmota/language/ru_RU.h index 3079c00ac..35d838d45 100644 --- a/tasmota/language/ru_RU.h +++ b/tasmota/language/ru_RU.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/sk_SK.h b/tasmota/language/sk_SK.h index 09402307c..812ea402a 100644 --- a/tasmota/language/sk_SK.h +++ b/tasmota/language/sk_SK.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/sv_SE.h b/tasmota/language/sv_SE.h index c6b3ef835..7102eaa20 100644 --- a/tasmota/language/sv_SE.h +++ b/tasmota/language/sv_SE.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/tr_TR.h b/tasmota/language/tr_TR.h index 010228272..f729ff276 100644 --- a/tasmota/language/tr_TR.h +++ b/tasmota/language/tr_TR.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/uk_UA.h b/tasmota/language/uk_UA.h index 1f8bb46b1..df346b31a 100644 --- a/tasmota/language/uk_UA.h +++ b/tasmota/language/uk_UA.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/zh_CN.h b/tasmota/language/zh_CN.h index 7b925abc6..375f25188 100644 --- a/tasmota/language/zh_CN.h +++ b/tasmota/language/zh_CN.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/language/zh_TW.h b/tasmota/language/zh_TW.h index 6031e82a8..f8e3f94d3 100644 --- a/tasmota/language/zh_TW.h +++ b/tasmota/language/zh_TW.h @@ -687,6 +687,13 @@ #define D_SENSOR_TELEINFO_RX "TInfo Rx" #define D_SENSOR_TELEINFO_ENABLE "TInfo EN" #define D_SENSOR_LMT01_PULSE "LMT01 Pulse" +#define D_SENSOR_ADC_INPUT "ADC Input" +#define D_SENSOR_ADC_TEMP "ADC Temp" +#define D_SENSOR_ADC_LIGHT "ADC Light" +#define D_SENSOR_ADC_BUTTON "ADC Button" +#define D_SENSOR_ADC_RANGE "ADC Range" +#define D_SENSOR_ADC_CT_POWER "ADC CT Power" +#define D_SENSOR_ADC_JOYSTICK "ADC Joystick" #define D_GPIO_WEBCAM_PWDN "CAM_PWDN" #define D_GPIO_WEBCAM_RESET "CAM_RESET" #define D_GPIO_WEBCAM_XCLK "CAM_XCLK" diff --git a/tasmota/my_user_config.h b/tasmota/my_user_config.h index 69f51a546..b967db5b0 100644 --- a/tasmota/my_user_config.h +++ b/tasmota/my_user_config.h @@ -768,6 +768,8 @@ // #define ETH_ADDR 0 // [EthAddress] 0 = PHY0 .. 31 = PHY31 // #define ETH_CLKMODE 0 // [EthClockMode] 0 = ETH_CLOCK_GPIO0_IN, 1 = ETH_CLOCK_GPIO0_OUT, 2 = ETH_CLOCK_GPIO16_OUT, 3 = ETH_CLOCK_GPIO17_OUT +#define USE_ADC // Add support for ADC on GPIO32 to GPIO39 + //#define USE_SPI // Add support for hardware SPI //#define USE_MI_ESP32 // Add support for ESP32 as a BLE-bridge (+9k2 mem, +292k flash) //#define USE_WEBCAM // Add support for webcam diff --git a/tasmota/support.ino b/tasmota/support.ino index 92ab14a99..5e5a11f35 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -127,6 +127,18 @@ size_t strchrspn(const char *str1, int character) return ret; } +uint32_t ChrCount(const char *str, const char *delim) { + uint32_t count = 0; + char* read = (char*)str; + char ch = '.'; + + while (ch != '\0') { + ch = *read++; + if (ch == *delim) { count++; } + } + return count; +} + // Function to return a substring defined by a delimiter at an index char* subStr(char* dest, char* str, const char *delim, int index) { @@ -152,6 +164,8 @@ float CharToFloat(const char *str) strlcpy(strbuf, str, sizeof(strbuf)); char *pt = strbuf; + if (*pt == '\0') { return 0.0; } + while ((*pt != '\0') && isblank(*pt)) { pt++; } // Trim leading spaces signed char sign = 1; @@ -394,11 +408,13 @@ char* UpperCase_P(char* dest, const char* source) char* Trim(char* p) { - while ((*p != '\0') && isblank(*p)) { p++; } // Trim leading spaces - char* q = p + strlen(p) -1; - while ((q >= p) && isblank(*q)) { q--; } // Trim trailing spaces - q++; - *q = '\0'; + if (*p != '\0') { + while ((*p != '\0') && isblank(*p)) { p++; } // Trim leading spaces + char* q = p + strlen(p) -1; + while ((q >= p) && isblank(*q)) { q--; } // Trim trailing spaces + q++; + *q = '\0'; + } return p; } diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 29c8875c7..642389741 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -85,7 +85,7 @@ const uint8_t MAX_DEV_GROUP_NAMES = 4; // Max number of Device Group names const uint8_t MAX_HUE_DEVICES = 15; // Max number of Philips Hue device per emulation const uint8_t MAX_ROTARIES = 2; // Max number of Rotary Encoders -const uint8_t MAX_ADCS = 18; // Max number of ESP32 ADC pins +const uint8_t MAX_ADCS = 8; // Max number of ESP32 ADC pins (ADC2 pins are unusable with Wifi enabled) const char MQTT_TOKEN_PREFIX[] PROGMEM = "%prefix%"; // To be substituted by mqtt_prefix[x] const char MQTT_TOKEN_TOPIC[] PROGMEM = "%topic%"; // To be substituted by mqtt_topic, mqtt_grptopic, mqtt_buttontopic, mqtt_switchtopic @@ -297,6 +297,9 @@ enum SettingsTextIndex { SET_OTAURL, SET_DEV_GROUP_NAME1, SET_DEV_GROUP_NAME2, SET_DEV_GROUP_NAME3, SET_DEV_GROUP_NAME4, SET_DEVICENAME, SET_TELEGRAM_TOKEN, SET_TELEGRAM_CHATID, +#ifdef ESP32 + SET_ADC_PARAM1, SET_ADC_PARAM2, SET_ADC_PARAM3, SET_ADC_PARAM4, SET_ADC_PARAM5, SET_ADC_PARAM6, SET_ADC_PARAM7, SET_ADC_PARAM8, // Relates to MAX_ADCS +#endif SET_MAX }; enum DevGroupMessageType { DGR_MSGTYP_FULL_STATUS, DGR_MSGTYP_PARTIAL_UPDATE, DGR_MSGTYP_UPDATE, DGR_MSGTYP_UPDATE_MORE_TO_COME, DGR_MSGTYP_UPDATE_DIRECT, DGR_MSGTYPE_UPDATE_COMMAND }; diff --git a/tasmota/tasmota_template_ESP32.h b/tasmota/tasmota_template_ESP32.h index 923a278c6..ac422cfc6 100644 --- a/tasmota/tasmota_template_ESP32.h +++ b/tasmota/tasmota_template_ESP32.h @@ -88,8 +88,9 @@ enum UserSelectablePins { GPIO_ARIRFRCV, GPIO_ARIRFSEL, // Arilux RF Receive input GPIO_TXD, GPIO_RXD, // Serial interface GPIO_ROT1A, GPIO_ROT1B, // Rotary switch + GPIO_ADC_JOY, // Analog joystick - GPIO_SPARE1, GPIO_SPARE2, // Spare GPIOs + GPIO_SPARE1, // Spare GPIOs GPIO_HRE_CLOCK, GPIO_HRE_DATA, // HR-E Water Meter GPIO_ADE7953_IRQ, // ADE7953 IRQ @@ -193,8 +194,9 @@ const char kSensorNames[] PROGMEM = D_SENSOR_ARIRFRCV "|" D_SENSOR_ARIRFSEL "|" D_SENSOR_TXD "|" D_SENSOR_RXD "|" D_SENSOR_ROTARY "_a|" D_SENSOR_ROTARY "_b|" + D_SENSOR_ADC_JOYSTICK "|" - "Spare1|Spare2|" + "Spare1|" D_SENSOR_HRE_CLOCK "|" D_SENSOR_HRE_DATA "|" D_SENSOR_ADE7953_IRQ "|" @@ -216,11 +218,12 @@ const char kSensorNames[] PROGMEM = D_SENSOR_HRXL_RX "|" D_SENSOR_ELECTRIQ_MOODL "|" D_SENSOR_AS3935 "|" - D_ANALOG_INPUT "|" - D_TEMPERATURE "|" D_LIGHT "|" - D_SENSOR_BUTTON "|" D_SENSOR_BUTTON "_i|" - D_RANGE "|" - D_CT_POWER "|" + D_SENSOR_ADC_INPUT "|" + D_SENSOR_ADC_TEMP "|" + D_SENSOR_ADC_LIGHT "|" + D_SENSOR_ADC_BUTTON "|" D_SENSOR_ADC_BUTTON "_i|" + D_SENSOR_ADC_RANGE "|" + D_SENSOR_ADC_CT_POWER "|" D_GPIO_WEBCAM_PWDN "|" D_GPIO_WEBCAM_RESET "|" D_GPIO_WEBCAM_XCLK "|" D_GPIO_WEBCAM_SIOD "|" D_GPIO_WEBCAM_SIOC "|" D_GPIO_WEBCAM_DATA "|" @@ -564,6 +567,7 @@ const uint16_t kGpioNiceList[] PROGMEM = { AGPIO(GPIO_ADC_BUTTON_INV) + MAX_ADCS, AGPIO(GPIO_ADC_RANGE) + MAX_ADCS, // Range AGPIO(GPIO_ADC_CT_POWER) + MAX_ADCS, // Current + AGPIO(GPIO_ADC_JOY) + MAX_ADCS, // Joystick #endif #ifdef USE_WEBCAM AGPIO(GPIO_WEBCAM_PWDN), @@ -598,7 +602,7 @@ enum UserSelectableAdc { ADC_BUTTON_INV, ADC_RANGE, // Range ADC_CT_POWER, // Current - + ADC_JOY, // Joystick // ADC_SWITCH, // Switch // ADC_SWITCH_INV, ADC_END }; @@ -609,7 +613,7 @@ enum UserSelectableAdc { #define WEMOS_MODULE 0 // Wemos module // 0 1 2 3 4 5 6 7 8 9101112131415161718192021222324252627282930313233343536373839 -const char PINS_WEMOS[] PROGMEM = "IOTXIORXIOIOflashcFLFLolIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOA6A7A0IoIoA3"; +const char PINS_WEMOS[] PROGMEM = "IOTXIORXIOIOflashcFLFLolIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOIOAOAOIAIAIAIAIAIA"; //******************************************************************************************** diff --git a/tasmota/xsns_02_analog_esp32.ino b/tasmota/xsns_02_analog_esp32.ino index 0339f8345..8ec129daf 100644 --- a/tasmota/xsns_02_analog_esp32.ino +++ b/tasmota/xsns_02_analog_esp32.ino @@ -20,11 +20,14 @@ #ifdef ESP32 #ifdef USE_ADC /*********************************************************************************************\ - * ADC support + * ADC support for up to 8 channels on GPIO32 to GPIO39 \*********************************************************************************************/ #define XSNS_02 2 +#define ANALOG_RESOLUTION 12 // 12 = 4095, 11 = 2047, 10 = 1023 +#define ANALOG_RANGE 4095 + #define TO_CELSIUS(x) ((x) - 273.15) #define TO_KELVIN(x) ((x) + 273.15) @@ -57,132 +60,140 @@ // Default settings for a 20A/1V Current Transformer. // Analog peak to peak range is measured and converted to RMS current using ANALOG_CT_MULTIPLIER #define ANALOG_CT_FLAGS 0 // (uint32_t) reserved for possible future use -#define ANALOG_CT_MULTIPLIER 2146 // (uint32_t) Multiplier*100000 to convert raw ADC peak to peak range 0..1023 to RMS current in Amps. Value of 100000 corresponds to 1 +#define ANALOG_CT_MULTIPLIER 2146 // (uint32_t) Multiplier*100000 to convert raw ADC peak to peak range 0..ANALOG_RANGE to RMS current in Amps. Value of 100000 corresponds to 1 #define ANALOG_CT_VOLTAGE 2300 // (int) Convert current in Amps to apparrent power in Watts using voltage in Volts*10. Value of 2200 corresponds to 220V #define CT_FLAG_ENERGY_RESET (1 << 0) // Reset energy total -uint8_t adc_present = 0; +struct { + uint8_t present = 0; + uint8_t type = 0; +} Adcs; struct { float temperature = 0; float current = 0; float energy = 0; + uint32_t param1 = 0; + uint32_t param2 = 0; + int param3 = 0; + int param4 = 0; uint32_t previous_millis = 0; uint16_t last_value = 0; uint8_t type = 0; uint8_t pin = 0; } Adc[MAX_ADCS]; -void AdcInitParams(void) { - my_adc0 = Adc[0].type; +void AdcSaveSettings(uint32_t idx) { + char parameters[32]; + snprintf_P(parameters, sizeof(parameters), PSTR("%d,%d,%d,%d,%d"), + Adc[idx].type, Adc[idx].param1, Adc[idx].param2, Adc[idx].param3, Adc[idx].param4); + SettingsUpdateText(SET_ADC_PARAM1 + idx, parameters); +} - if ((Settings.adc_param_type != my_adc0) || (Settings.adc_param1 > 1000000)) { - if (ADC_TEMP == my_adc0) { +void AdcGetSettings(uint32_t idx) { + char parameters[32]; + Adcs.type = 0; + Adc[idx].param1 = 0; + Adc[idx].param2 = 0; + Adc[idx].param3 = 0; + Adc[idx].param4 = 0; + if (strstr(SettingsText(SET_ADC_PARAM1 + idx), ",") != nullptr) { + Adcs.type = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 1)); + Adc[idx].param1 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 2)); + Adc[idx].param2 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 3)); + Adc[idx].param3 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 4)); + Adc[idx].param4 = atoi(subStr(parameters, SettingsText(SET_ADC_PARAM1 + idx), ",", 5)); + } +} + +void AdcInitParams(uint8_t idx) { + if ((Adcs.type != Adc[idx].type) || (Adc[idx].param1 > 1000000)) { + if (ADC_TEMP == Adc[idx].type) { // Default Shelly 2.5 and 1PM parameters - Settings.adc_param_type = ADC_TEMP; - Settings.adc_param1 = ANALOG_NTC_BRIDGE_RESISTANCE; - Settings.adc_param2 = ANALOG_NTC_RESISTANCE; - Settings.adc_param3 = ANALOG_NTC_B_COEFFICIENT * 10000; + Adc[idx].param1 = ANALOG_NTC_BRIDGE_RESISTANCE; + Adc[idx].param2 = ANALOG_NTC_RESISTANCE; + Adc[idx].param3 = ANALOG_NTC_B_COEFFICIENT * 10000; } - else if (ADC_LIGHT == my_adc0) { - Settings.adc_param_type = ADC_LIGHT; - Settings.adc_param1 = ANALOG_LDR_BRIDGE_RESISTANCE; - Settings.adc_param2 = ANALOG_LDR_LUX_CALC_SCALAR; - Settings.adc_param3 = ANALOG_LDR_LUX_CALC_EXPONENT * 10000; + else if (ADC_LIGHT == Adc[idx].type) { + Adc[idx].param1 = ANALOG_LDR_BRIDGE_RESISTANCE; + Adc[idx].param2 = ANALOG_LDR_LUX_CALC_SCALAR; + Adc[idx].param3 = ANALOG_LDR_LUX_CALC_EXPONENT * 10000; } - else if (ADC_RANGE == my_adc0) { - Settings.adc_param_type = ADC_RANGE; - Settings.adc_param1 = 0; - Settings.adc_param2 = 1023; - Settings.adc_param3 = 0; - Settings.adc_param4 = 100; + else if (ADC_RANGE == Adc[idx].type) { + Adc[idx].param1 = 0; + Adc[idx].param2 = ANALOG_RANGE; + Adc[idx].param3 = 0; + Adc[idx].param4 = 100; } - else if (ADC_CT_POWER == my_adc0) { - Settings.adc_param_type = ADC_CT_POWER; - Settings.adc_param1 = ANALOG_CT_FLAGS; //(uint32_t) 0 - Settings.adc_param2 = ANALOG_CT_MULTIPLIER; //(uint32_t) 100000 - Settings.adc_param3 = ANALOG_CT_VOLTAGE; //(int) 10 + else if (ADC_CT_POWER == Adc[idx].type) { + Adc[idx].param1 = ANALOG_CT_FLAGS; //(uint32_t) 0 + Adc[idx].param2 = ANALOG_CT_MULTIPLIER; //(uint32_t) 100000 + Adc[idx].param3 = ANALOG_CT_VOLTAGE; //(int) 10 } + else if (ADC_JOY == Adc[idx].type) { + Adc[idx].param1 = (ANALOG_RANGE / 2) -128; + } + } +} + +void AdcAttach(uint8_t pin, uint8_t type) { + Adc[Adcs.present].pin = pin; + if (adcAttachPin(Adc[Adcs.present].pin)) { + Adc[Adcs.present].type = type; +// analogSetPinAttenuation(Adc[Adcs.present].pin, ADC_11db); // Default + Adcs.present++; } } void AdcInit(void) { - adc_present = 0; + Adcs.present = 0; for (uint32_t i = 0; i < MAX_ADCS; i++) { if (PinUsed(GPIO_ADC_INPUT, i)) { - Adc[adc_present].pin = Pin(GPIO_ADC_INPUT, i); - if (adcAttachPin(Adc[adc_present].pin)) { - Adc[adc_present].type = ADC_INPUT; -// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default - adc_present++; - } + AdcAttach(Pin(GPIO_ADC_INPUT, i), ADC_INPUT); } if (PinUsed(GPIO_ADC_TEMP, i)) { - Adc[adc_present].pin = Pin(GPIO_ADC_TEMP, i); - if (adcAttachPin(Adc[adc_present].pin)) { - Adc[adc_present].type = ADC_TEMP; -// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default - adc_present++; - } + AdcAttach(Pin(GPIO_ADC_TEMP, i), ADC_TEMP); } if (PinUsed(GPIO_ADC_LIGHT, i)) { - Adc[adc_present].pin = Pin(GPIO_ADC_LIGHT, i); - if (adcAttachPin(Adc[adc_present].pin)) { - Adc[adc_present].type = ADC_LIGHT; -// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default - adc_present++; - } + AdcAttach(Pin(GPIO_ADC_LIGHT, i), ADC_LIGHT); } if (PinUsed(GPIO_ADC_BUTTON, i)) { - Adc[adc_present].pin = Pin(GPIO_ADC_BUTTON, i); - if (adcAttachPin(Adc[adc_present].pin)) { - Adc[adc_present].type = ADC_BUTTON; -// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default - adc_present++; - } + AdcAttach(Pin(GPIO_ADC_BUTTON, i), ADC_BUTTON); } - if (PinUsed(ADC_BUTTON_INV, i)) { - Adc[adc_present].pin = Pin(ADC_BUTTON_INV, i); - if (adcAttachPin(Adc[adc_present].pin)) { - Adc[adc_present].type = ADC_BUTTON_INV; -// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default - adc_present++; - } + if (PinUsed(GPIO_ADC_BUTTON_INV, i)) { + AdcAttach(Pin(GPIO_ADC_BUTTON_INV, i), ADC_BUTTON_INV); } if (PinUsed(GPIO_ADC_RANGE, i)) { - Adc[adc_present].pin = Pin(GPIO_ADC_RANGE, i); - if (adcAttachPin(Adc[adc_present].pin)) { - Adc[adc_present].type = ADC_RANGE; -// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default - adc_present++; - } + AdcAttach(Pin(GPIO_ADC_RANGE, i), ADC_RANGE); } if (PinUsed(GPIO_ADC_CT_POWER, i)) { - Adc[adc_present].pin = Pin(GPIO_ADC_CT_POWER, i); - if (adcAttachPin(Adc[adc_present].pin)) { - Adc[adc_present].type = ADC_CT_POWER; -// analogSetPinAttenuation(Adc[adc_present].pin, ADC_11db); // Default - adc_present++; - } + AdcAttach(Pin(GPIO_ADC_CT_POWER, i), ADC_CT_POWER); + } + if (PinUsed(GPIO_ADC_JOY, i)) { + AdcAttach(Pin(GPIO_ADC_JOY, i), ADC_JOY); } } - if (adc_present) { - analogSetClockDiv(1); // Default 1 - analogSetWidth(12); // Default 12 bits (0 - 4095) - analogSetAttenuation(ADC_11db); // Default 11db + if (Adcs.present) { + analogSetClockDiv(1); // Default 1 + analogSetWidth(ANALOG_RESOLUTION); // Default 12 bits (0 - 4095) + analogSetAttenuation(ADC_11db); // Default 11db + for (uint32_t idx = 0; idx < Adcs.present; idx++) { + AdcGetSettings(idx); + AdcInitParams(idx); + AdcSaveSettings(idx); + } } - AdcInitParams(); } -uint16_t AdcRead(uint8_t pin, uint8_t factor) { +uint16_t AdcRead(uint32_t pin, uint32_t factor) { // factor 1 = 2 samples // factor 2 = 4 samples // factor 3 = 8 samples // factor 4 = 16 samples // factor 5 = 32 samples - uint8_t samples = 1 << factor; - uint16_t analog = 0; + uint32_t samples = 1 << factor; + uint32_t analog = 0; for (uint32_t i = 0; i < samples; i++) { analog += analogRead(pin); delay(1); @@ -193,7 +204,7 @@ uint16_t AdcRead(uint8_t pin, uint8_t factor) { #ifdef USE_RULES void AdcEvery250ms(void) { - for (uint32_t idx = 0; idx < adc_present; idx++) { + for (uint32_t idx = 0; idx < Adcs.present; idx++) { if (ADC_INPUT == Adc[idx].type) { uint16_t new_value = AdcRead(Adc[idx].pin, 5); if ((new_value < Adc[idx].last_value -10) || (new_value > Adc[idx].last_value +10)) { @@ -203,27 +214,38 @@ void AdcEvery250ms(void) { XdrvRulesProcess(); } } + else if (ADC_JOY == Adc[idx].type) { + uint16_t new_value = AdcRead(Adc[idx].pin, 1); + if (new_value && (new_value != Adc[idx].last_value)) { + Adc[idx].last_value = new_value; + uint16_t value = new_value / Adc[idx].param1; + Response_P(PSTR("{\"ANALOG\":{\"JOY%d\":%d}}"), idx, value); + XdrvRulesProcess(); + } else { + Adc[idx].last_value = 0; + } + } } } #endif // USE_RULES -uint16_t AdcGetLux(uint8_t pin) { - int adc = AdcRead(pin, 2); +uint16_t AdcGetLux(uint32_t idx) { + int adc = AdcRead(Adc[idx].pin, 2); // Source: https://www.allaboutcircuits.com/projects/design-a-luxmeter-using-a-light-dependent-resistor/ - double resistorVoltage = ((double)adc / 1023) * ANALOG_V33; + double resistorVoltage = ((double)adc / ANALOG_RANGE) * ANALOG_V33; double ldrVoltage = ANALOG_V33 - resistorVoltage; - double ldrResistance = ldrVoltage / resistorVoltage * (double)Settings.adc_param1; - double ldrLux = (double)Settings.adc_param2 * FastPrecisePow(ldrResistance, (double)Settings.adc_param3 / 10000); + double ldrResistance = ldrVoltage / resistorVoltage * (double)Adc[idx].param1; + double ldrLux = (double)Adc[idx].param2 * FastPrecisePow(ldrResistance, (double)Adc[idx].param3 / 10000); return (uint16_t)ldrLux; } -uint16_t AdcGetRange(uint8_t pin) { +uint16_t AdcGetRange(uint32_t idx) { // formula for calibration: value, fromLow, fromHigh, toLow, toHigh // Example: 514, 632, 236, 0, 100 // int( (( - ) / ( - ) ) * ( - ) ) + ) - int adc = AdcRead(pin, 2); - double adcrange = ( ((double)Settings.adc_param2 - (double)adc) / ( ((double)Settings.adc_param2 - (double)Settings.adc_param1)) * ((double)Settings.adc_param3 - (double)Settings.adc_param4) + (double)Settings.adc_param4 ); + int adc = AdcRead(Adc[idx].pin, 2); + double adcrange = ( ((double)Adc[idx].param2 - (double)adc) / ( ((double)Adc[idx].param2 - (double)Adc[idx].param1)) * ((double)Adc[idx].param3 - (double)Adc[idx].param4) + (double)Adc[idx].param4 ); return (uint16_t)adcrange; } @@ -235,10 +257,10 @@ void AdcGetCurrentPower(uint8_t idx, uint8_t factor) { // factor 5 = 32 samples uint8_t samples = 1 << factor; uint16_t analog = 0; - uint16_t analog_min = 1023; + uint16_t analog_min = ANALOG_RANGE; uint16_t analog_max = 0; - if (0 == Settings.adc_param1) { + if (0 == Adc[idx].param1) { for (uint32_t i = 0; i < samples; i++) { analog = analogRead(Adc[idx].pin); if (analog < analog_min) { @@ -249,32 +271,32 @@ void AdcGetCurrentPower(uint8_t idx, uint8_t factor) { } delay(1); } - Adc[idx].current = (float)(analog_max-analog_min) * ((float)(Settings.adc_param2) / 100000); + Adc[idx].current = (float)(analog_max-analog_min) * ((float)(Adc[idx].param2) / 100000); } else { analog = AdcRead(Adc[idx].pin, 5); - if (analog > Settings.adc_param1) { - Adc[idx].current = ((float)(analog) - (float)Settings.adc_param1) * ((float)(Settings.adc_param2) / 100000); + if (analog > Adc[idx].param1) { + Adc[idx].current = ((float)(analog) - (float)Adc[idx].param1) * ((float)(Adc[idx].param2) / 100000); } else { Adc[idx].current = 0; } } - float power = Adc[idx].current * (float)(Settings.adc_param3) / 10; + float power = Adc[idx].current * (float)(Adc[idx].param3) / 10; uint32_t current_millis = millis(); Adc[idx].energy = Adc[idx].energy + ((power * (current_millis - Adc[idx].previous_millis)) / 3600000000); Adc[idx].previous_millis = current_millis; } void AdcEverySecond(void) { - for (uint32_t idx = 0; idx < adc_present; idx++) { + for (uint32_t idx = 0; idx < Adcs.present; idx++) { if (ADC_TEMP == Adc[idx].type) { int adc = AdcRead(Adc[idx].pin, 2); // Steinhart-Hart equation for thermistor as temperature sensor - double Rt = (adc * Settings.adc_param1) / (1024.0 * ANALOG_V33 - (double)adc); - double BC = (double)Settings.adc_param3 / 10000; - double T = BC / (BC / ANALOG_T0 + TaylorLog(Rt / (double)Settings.adc_param2)); + double Rt = (adc * Adc[idx].param1) / (1024.0 * ANALOG_V33 - (double)adc); + double BC = (double)Adc[idx].param3 / 10000; + double T = BC / (BC / ANALOG_T0 + TaylorLog(Rt / (double)Adc[idx].param2)); Adc[idx].temperature = ConvertTemp(TO_CELSIUS(T)); } else if (ADC_CT_POWER == Adc[idx].type) { @@ -286,7 +308,7 @@ void AdcEverySecond(void) { void AdcShow(bool json) { bool domo_flag[ADC_END] = { false }; char adc_name[10]; // ANALOG12 - for (uint32_t idx = 0; idx < adc_present; idx++) { + for (uint32_t idx = 0; idx < Adcs.present; idx++) { snprintf_P(adc_name, sizeof(adc_name), PSTR("ANALOG%d"), idx); switch (Adc[idx].type) { @@ -325,7 +347,7 @@ void AdcShow(bool json) { break; } case ADC_LIGHT: { - uint16_t adc_light = AdcGetLux(Adc[idx].pin); + uint16_t adc_light = AdcGetLux(idx); if (json) { ResponseAppend_P(JSON_SNS_ILLUMINANCE, adc_name, adc_light); @@ -343,7 +365,7 @@ void AdcShow(bool json) { break; } case ADC_RANGE: { - uint16_t adc_range = AdcGetRange(Adc[idx].pin); + uint16_t adc_range = AdcGetRange(idx); if (json) { ResponseAppend_P(JSON_SNS_RANGE, adc_name, adc_range); @@ -357,7 +379,7 @@ void AdcShow(bool json) { case ADC_CT_POWER: { AdcGetCurrentPower(idx, 5); - float voltage = (float)(Settings.adc_param3) / 10; + float voltage = (float)(Adc[idx].param3) / 10; char voltage_chr[FLOATSZ]; dtostrfd(voltage, Settings.flag2.voltage_resolution, voltage_chr); char current_chr[FLOATSZ]; @@ -403,60 +425,70 @@ void (* const AdcCommand[])(void) PROGMEM = { &CmndAdcParam }; void CmndAdcParam(void) { - if (XdrvMailbox.data_len) { - if ((ADC_TEMP == XdrvMailbox.payload) || - (ADC_LIGHT == XdrvMailbox.payload) || - (ADC_RANGE == XdrvMailbox.payload) || - (ADC_CT_POWER == XdrvMailbox.payload)) { - if (strstr(XdrvMailbox.data, ",") != nullptr) { // Process parameter entry - char sub_string[XdrvMailbox.data_len +1]; - // AdcParam 2, 32000, 10000, 3350 - // AdcParam 3, 10000, 12518931, -1.405 - // AdcParam 6, 0, 1023, 0, 100 - Settings.adc_param_type = XdrvMailbox.payload; - Settings.adc_param1 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); - Settings.adc_param2 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 3), nullptr, 10); - if (ADC_RANGE == XdrvMailbox.payload) { - Settings.adc_param3 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 4), nullptr, 10)); - Settings.adc_param4 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 5), nullptr, 10)); - } else { - Settings.adc_param3 = (int)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000); - } - if (ADC_CT_POWER == XdrvMailbox.payload) { - if (((1 == Settings.adc_param1) & CT_FLAG_ENERGY_RESET) > 0) { - for (uint32_t idx = 0; idx < MAX_ADCS; idx++) { - Adc[idx].energy = 0; - } - Settings.adc_param1 ^= CT_FLAG_ENERGY_RESET; // Cancel energy reset flag + if ((XdrvMailbox.index > 0) && (XdrvMailbox.index <= MAX_ADCS)) { + uint8_t idx = XdrvMailbox.index -1; + if (XdrvMailbox.data_len) { + if ((ADC_TEMP == XdrvMailbox.payload) || + (ADC_LIGHT == XdrvMailbox.payload) || + (ADC_RANGE == XdrvMailbox.payload) || + (ADC_CT_POWER == XdrvMailbox.payload) || + (ADC_JOY == XdrvMailbox.payload)) { + AdcGetSettings(idx); + if (ChrCount(XdrvMailbox.data, ",") > 2) { // Process parameter entry + char sub_string[XdrvMailbox.data_len +1]; + // AdcParam 2, 32000, 10000, 3350 + // AdcParam 3, 10000, 12518931, -1.405 + // AdcParam 6, 0, ANALOG_RANGE, 0, 100 + // AdcParam 7, 0, 2146, 0.23 + // AdcParam 8, 1000, 0, 0 + Adc[idx].type = XdrvMailbox.payload; + Adc[idx].param1 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 2), nullptr, 10); + Adc[idx].param2 = strtol(subStr(sub_string, XdrvMailbox.data, ",", 3), nullptr, 10); + if (ADC_RANGE == XdrvMailbox.payload) { + Adc[idx].param3 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 4), nullptr, 10)); + Adc[idx].param4 = abs(strtol(subStr(sub_string, XdrvMailbox.data, ",", 5), nullptr, 10)); + } else { + Adc[idx].param3 = (int)(CharToFloat(subStr(sub_string, XdrvMailbox.data, ",", 4)) * 10000); } + if (ADC_CT_POWER == XdrvMailbox.payload) { + if (((1 == Adc[idx].param1) & CT_FLAG_ENERGY_RESET) > 0) { + for (uint32_t idx = 0; idx < MAX_ADCS; idx++) { + Adc[idx].energy = 0; + } + Adc[idx].param1 ^= CT_FLAG_ENERGY_RESET; // Cancel energy reset flag + } + } + } else { // Set default values based on current adc type + // AdcParam 2 + // AdcParam 3 + // AdcParam 6 + // AdcParam 7 + // AdcParam 8 + Adcs.type = 0; + AdcInitParams(idx); } - } else { // Set default values based on current adc type - // AdcParam 2 - // AdcParam 3 - // AdcParam 6 - // AdcParam 7 - Settings.adc_param_type = 0; - AdcInitParams(); + AdcSaveSettings(idx); } } - } - // AdcParam - Response_P(PSTR("{\"" D_CMND_ADCPARAM "\":[%d,%d,%d"), Settings.adc_param_type, Settings.adc_param1, Settings.adc_param2); - if (ADC_RANGE == my_adc0) { - ResponseAppend_P(PSTR(",%d,%d"), Settings.adc_param3, Settings.adc_param4); - } else { - int value = Settings.adc_param3; - uint8_t precision; - for (precision = 4; precision > 0; precision--) { - if (value % 10) { break; } - value /= 10; + // AdcParam + AdcGetSettings(idx); + Response_P(PSTR("{\"" D_CMND_ADCPARAM "%d\":[%d,%d,%d"), idx +1, Adcs.type, Adc[idx].param1, Adc[idx].param2); + if (ADC_RANGE == my_adc0) { + ResponseAppend_P(PSTR(",%d,%d"), Adc[idx].param3, Adc[idx].param4); + } else { + int value = Adc[idx].param3; + uint8_t precision; + for (precision = 4; precision > 0; precision--) { + if (value % 10) { break; } + value /= 10; + } + char param3[33]; + dtostrfd(((double)Adc[idx].param3)/10000, precision, param3); + ResponseAppend_P(PSTR(",%s"), param3); } - char param3[33]; - dtostrfd(((double)Settings.adc_param3)/10000, precision, param3); - ResponseAppend_P(PSTR(",%s"), param3); + ResponseAppend_P(PSTR("]}")); } - ResponseAppend_P(PSTR("]}")); } /*********************************************************************************************\ @@ -474,7 +506,7 @@ bool Xsns02(uint8_t function) { AdcInit(); break; default: - if (adc_present) { + if (Adcs.present) { switch (function) { #ifdef USE_RULES case FUNC_EVERY_250_MSECOND: From d321b6cf68334a278dac0acb2d3f3e0312619dd1 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 4 Aug 2020 18:01:51 +0200 Subject: [PATCH 91/91] Fix ESP32 analog indexes --- tasmota/xsns_02_analog_esp32.ino | 52 ++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/tasmota/xsns_02_analog_esp32.ino b/tasmota/xsns_02_analog_esp32.ino index 8ec129daf..a47db706a 100644 --- a/tasmota/xsns_02_analog_esp32.ino +++ b/tasmota/xsns_02_analog_esp32.ino @@ -210,7 +210,7 @@ void AdcEvery250ms(void) { if ((new_value < Adc[idx].last_value -10) || (new_value > Adc[idx].last_value +10)) { Adc[idx].last_value = new_value; uint16_t value = Adc[idx].last_value / 10; - Response_P(PSTR("{\"ANALOG\":{\"A%ddiv10\":%d}}"), idx, (value > 99) ? 100 : value); + Response_P(PSTR("{\"ANALOG\":{\"A%ddiv10\":%d}}"), idx +1, (value > 99) ? 100 : value); XdrvRulesProcess(); } } @@ -219,7 +219,7 @@ void AdcEvery250ms(void) { if (new_value && (new_value != Adc[idx].last_value)) { Adc[idx].last_value = new_value; uint16_t value = new_value / Adc[idx].param1; - Response_P(PSTR("{\"ANALOG\":{\"JOY%d\":%d}}"), idx, value); + Response_P(PSTR("{\"ANALOG\":{\"Joy%d\":%d}}"), idx +1, value); XdrvRulesProcess(); } else { Adc[idx].last_value = 0; @@ -305,21 +305,33 @@ void AdcEverySecond(void) { } } +void AdcShowContinuation(bool *jsonflg) { + if (*jsonflg) { + ResponseAppend_P(PSTR(",")); + } else { + ResponseAppend_P(PSTR(",\"ANALOG\":{")); + *jsonflg = true; + } +} + void AdcShow(bool json) { bool domo_flag[ADC_END] = { false }; - char adc_name[10]; // ANALOG12 + char adc_name[10]; // ANALOG8 + + bool jsonflg = false; for (uint32_t idx = 0; idx < Adcs.present; idx++) { - snprintf_P(adc_name, sizeof(adc_name), PSTR("ANALOG%d"), idx); + snprintf_P(adc_name, sizeof(adc_name), PSTR("Analog%d"), idx +1); switch (Adc[idx].type) { case ADC_INPUT: { uint16_t analog = AdcRead(Adc[idx].pin, 5); if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"A0\":%d}"), adc_name, analog); + AdcShowContinuation(&jsonflg); + ResponseAppend_P(PSTR("\"A%d\":%d"), idx +1, analog); #ifdef USE_WEBSERVER } else { - WSContentSend_PD(HTTP_SNS_ANALOG, "", idx, analog); + WSContentSend_PD(HTTP_SNS_ANALOG, "", idx +1, analog); #endif // USE_WEBSERVER } break; @@ -329,7 +341,8 @@ void AdcShow(bool json) { dtostrfd(Adc[idx].temperature, Settings.flag2.temperature_resolution, temperature); if (json) { - ResponseAppend_P(JSON_SNS_TEMP, adc_name, temperature); + AdcShowContinuation(&jsonflg); + ResponseAppend_P(PSTR("\"" D_JSON_TEMPERATURE "%d\":%s"), idx +1, temperature); if ((0 == tele_period) && (!domo_flag[ADC_TEMP])) { #ifdef USE_DOMOTICZ DomoticzSensor(DZ_TEMP, temperature); @@ -350,7 +363,8 @@ void AdcShow(bool json) { uint16_t adc_light = AdcGetLux(idx); if (json) { - ResponseAppend_P(JSON_SNS_ILLUMINANCE, adc_name, adc_light); + AdcShowContinuation(&jsonflg); + ResponseAppend_P(PSTR("\"" D_JSON_ILLUMINANCE "%d\":%d"), idx +1, adc_light); #ifdef USE_DOMOTICZ if ((0 == tele_period) && (!domo_flag[ADC_LIGHT])) { DomoticzSensor(DZ_ILLUMINANCE, adc_light); @@ -368,7 +382,8 @@ void AdcShow(bool json) { uint16_t adc_range = AdcGetRange(idx); if (json) { - ResponseAppend_P(JSON_SNS_RANGE, adc_name, adc_range); + AdcShowContinuation(&jsonflg); + ResponseAppend_P(PSTR("\"" D_JSON_RANGE "%d\":%d"), idx +1, adc_range); #ifdef USE_WEBSERVER } else { WSContentSend_PD(HTTP_SNS_RANGE, adc_name, adc_range); @@ -390,8 +405,9 @@ void AdcShow(bool json) { dtostrfd(Adc[idx].energy, Settings.flag2.energy_resolution, energy_chr); if (json) { - ResponseAppend_P(PSTR(",\"%s\":{\"" D_JSON_ENERGY "\":%s,\"" D_JSON_POWERUSAGE "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), - adc_name, energy_chr, power_chr, voltage_chr, current_chr); + AdcShowContinuation(&jsonflg); + ResponseAppend_P(PSTR("\"CTEnergy%d\":{\"" D_JSON_ENERGY "\":%s,\"" D_JSON_POWERUSAGE "\":%s,\"" D_JSON_VOLTAGE "\":%s,\"" D_JSON_CURRENT "\":%s}"), + idx +1, energy_chr, power_chr, voltage_chr, current_chr); #ifdef USE_DOMOTICZ if ((0 == tele_period) && (!domo_flag[ADC_CT_POWER])) { DomoticzSensor(DZ_POWER_ENERGY, power_chr); @@ -410,8 +426,20 @@ void AdcShow(bool json) { } break; } + case ADC_JOY: { + uint16_t new_value = AdcRead(Adc[idx].pin, 1); + uint16_t value = new_value / Adc[idx].param1; + if (json) { + AdcShowContinuation(&jsonflg); + ResponseAppend_P(PSTR("\"Joy%d\":%d"), idx +1, value); + } + break; + } } } + if (jsonflg) { + ResponseJsonEnd(); + } } /*********************************************************************************************\ @@ -474,7 +502,7 @@ void CmndAdcParam(void) { // AdcParam AdcGetSettings(idx); Response_P(PSTR("{\"" D_CMND_ADCPARAM "%d\":[%d,%d,%d"), idx +1, Adcs.type, Adc[idx].param1, Adc[idx].param2); - if (ADC_RANGE == my_adc0) { + if (ADC_RANGE == Adc[idx].type) { ResponseAppend_P(PSTR(",%d,%d"), Adc[idx].param3, Adc[idx].param4); } else { int value = Adc[idx].param3;