diff --git a/data-src/index.html b/data-src/index.html index 616a1c2..e46ab30 100644 --- a/data-src/index.html +++ b/data-src/index.html @@ -913,6 +913,10 @@ +
+ + +
diff --git a/data-src/index.js b/data-src/index.js index d2400e8..46f0a39 100644 --- a/data-src/index.js +++ b/data-src/index.js @@ -1954,7 +1954,7 @@ class Somfy { this.loadPins('input', document.getElementById('selTransRXPin')); //this.loadSomfy(); ui.toElement(document.getElementById('divTransceiverSettings'), { - transceiver: { config: { proto: 0, SCKPin: 18, CSNPin: 5, MOSIPin: 23, MISOPin: 19, TXPin: 12, RXPin: 13, frequency: 433.42, rxBandwidth: 97.96, type: 56, deviation: 11.43, txPower: 10, enabled: false } } + transceiver: { config: { proto: 0, SCKPin: 18, CSNPin: 5, MOSIPin: 23, MISOPin: 19, TXPin: 12, RXPin: 13, frequency: 433.42, rxBandwidth: 97.96, type: 56, deviation: 11.43, txPower: 10, enabled: false, noiseDetection: false } } }); this.loadPins('out', document.getElementById('selShadeGPIOUp')); this.loadPins('out', document.getElementById('selShadeGPIODown')); diff --git a/esp32_3MB.csv b/esp32_3MB.csv index 9457d66..f56623f 100644 --- a/esp32_3MB.csv +++ b/esp32_3MB.csv @@ -3,4 +3,5 @@ nvs, data, nvs, 0x9000, 0x5000 otadata, data, ota, 0xE000, 0x2000 app0, app, ota_0, 0x10000, 0x180000 app1, app, ota_1, 0x190000, 0x180000 -spiffs, data, spiffs, 0x310000, 0x0F0000 +spiffs, data, spiffs, 0x310000, 0x0E0000 +coredump, data, coredump, 0x3F0000, 0x10000 diff --git a/src/ConfigFile.cpp b/src/ConfigFile.cpp index d496632..5dc1801 100644 --- a/src/ConfigFile.cpp +++ b/src/ConfigFile.cpp @@ -708,7 +708,8 @@ bool ShadeConfigFile::readTransRecord(transceiver_config_t &cfg) { cfg.frequency = this->readFloat(cfg.frequency); cfg.rxBandwidth = this->readFloat(cfg.rxBandwidth); cfg.deviation = this->readFloat(cfg.deviation); - cfg.txPower = this->readInt8(cfg.txPower); + cfg.txPower = this->readInt8(cfg.txPower); + cfg.noiseDetection = this->readBool(false); if(this->file.position() != startPos + this->header.transRecordSize) { ESP_LOGD(TAG, "Reading to end of transceiver record"); this->seekChar(CFG_REC_END); @@ -1065,7 +1066,8 @@ bool ShadeConfigFile::writeTransRecord(transceiver_config_t &cfg) { this->writeFloat(cfg.frequency, 3); this->writeFloat(cfg.rxBandwidth, 2); this->writeFloat(cfg.deviation, 2); - this->writeInt8(cfg.txPower, CFG_REC_END); + this->writeInt8(cfg.txPower); + this->writeBool(cfg.noiseDetection, CFG_REC_END); return true; } bool ShadeConfigFile::exists() { return LittleFS.exists("/shades.cfg"); } diff --git a/src/Somfy.cpp b/src/Somfy.cpp index 7a8ad51..c5c3e31 100644 --- a/src/Somfy.cpp +++ b/src/Somfy.cpp @@ -3,6 +3,7 @@ #include #include #include +#include "driver/gpio.h" #include "esp_log.h" #include "Utils.h" #include "ConfigSettings.h" @@ -45,6 +46,9 @@ int sort_asc(const void *cmp1, const void *cmp2) { } static int interruptPin = 0; +static volatile bool noiseDetected = false; +static volatile unsigned long noiseStart = 0; +static volatile uint32_t noiseCount = 0; static uint8_t bit_length = 56; somfy_commands translateSomfyCommand(const String& string) { if (string.equalsIgnoreCase("My")) return somfy_commands::My; @@ -4187,6 +4191,21 @@ void Transceiver::sendFrame(byte *frame, uint8_t sync, uint8_t bitLength) { } } void RECEIVE_ATTR Transceiver::handleReceive() { + if (noiseDetected) return; + if (somfy.transceiver.config.noiseDetection) { + unsigned long now = millis(); + if (noiseStart == 0) noiseStart = now; + if (now - noiseStart >= 10000) { + noiseStart = now; + noiseCount = 0; + } + noiseCount++; + if (noiseCount > 100) { + gpio_intr_disable((gpio_num_t)interruptPin); + noiseDetected = true; + return; + } + } static unsigned long last_time = 0; const long time = micros(); const unsigned int duration = time - last_time; @@ -4358,7 +4377,7 @@ void Transceiver::processFrequencyScan(bool received) { currRSSI = -100; } - if(millis() - lastScan > 100 && somfy_rx.status == waiting_synchro) { + if(millis() - lastScan > 100 && (somfy_rx.status == waiting_synchro || noiseDetected)) { lastScan = millis(); this->emitFrequencyScan(); currFreq += 0.01f; @@ -4538,6 +4557,7 @@ void transceiver_config_t::fromJSON(JsonObject& obj) { if(!obj["enabled"].isNull()) this->enabled = obj["enabled"]; if(!obj["txPower"].isNull()) this->txPower = obj["txPower"]; if(!obj["proto"].isNull()) this->proto = static_cast(obj["proto"].as()); + if(!obj["noiseDetection"].isNull()) this->noiseDetection = obj["noiseDetection"]; /* if (!obj["internalCCMode"].isNull()) this->internalCCMode = obj["internalCCMode"]; if (!obj["modulationMode"].isNull()) this->modulationMode = obj["modulationMode"]; @@ -4625,7 +4645,8 @@ void transceiver_config_t::save() { pref.putBool("radioInit", true); pref.putChar("txPower", this->txPower); pref.putChar("proto", static_cast(this->proto)); - + pref.putBool("noiseDetect", this->noiseDetection); + /* pref.putBool("internalCCMode", this->internalCCMode); pref.putUChar("modulationMode", this->modulationMode); @@ -4724,6 +4745,7 @@ void transceiver_config_t::load() { this->txPower = pref.getChar("txPower", this->txPower); this->rxBandwidth = pref.getFloat("rxBandwidth", this->rxBandwidth); this->proto = static_cast(pref.getChar("proto", static_cast(this->proto))); + this->noiseDetection = pref.getBool("noiseDetect", false); this->removeNVSKey("internalCCMode"); this->removeNVSKey("modulationMode"); this->removeNVSKey("channel"); @@ -4857,6 +4879,14 @@ bool Transceiver::begin() { } void Transceiver::loop() { somfy_rx_t rx; + if (noiseDetected && rxmode != 3 && this->config.noiseDetection) { + if (millis() - noiseStart > 100) { + gpio_intr_enable((gpio_num_t)interruptPin); + noiseDetected = false; + noiseStart = 0; + noiseCount = 0; + } + } if(rxmode == 3) { if(this->receive(&rx)) this->processFrequencyScan(true); diff --git a/src/Somfy.h b/src/Somfy.h index 1ef4255..6630db6 100644 --- a/src/Somfy.h +++ b/src/Somfy.h @@ -426,6 +426,7 @@ struct transceiver_config_t { float deviation = 47.60; // Set the Frequency deviation in kHz. Value from 1.58 to 380.85. Default is 47.60 kHz. float rxBandwidth = 99.97; // Receive bandwidth in kHz. Value from 58.03 to 812.50. Default is 99.97kHz. int8_t txPower = 10; // Transmission power {-30, -20, -15, -10, -6, 0, 5, 7, 10, 11, 12}. Default is 12. + bool noiseDetection = false; // Disable RX interrupt when RF noise is detected (>100 pulses/10s) /* bool internalCCMode = false; // Use internal transmission mode FIFO buffers. byte modulationMode = 2; // Modulation mode. 0 = 2-FSK, 1 = GFSK, 2 = ASK/OOK, 3 = 4-FSK, 4 = MSK. diff --git a/src/SomfyController.ino.cpp b/src/SomfyController.ino.cpp new file mode 100644 index 0000000..ce50111 --- /dev/null +++ b/src/SomfyController.ino.cpp @@ -0,0 +1,147 @@ +# 1 "C:\\Users\\oem\\AppData\\Local\\Temp\\tmpahrx2jqr" +#include +# 1 "C:/Users/oem/Documents/PlatformIO/Projects/ESPSomfy-RTS/src/SomfyController.ino" +#include "esp_log.h" +#include +#include +#include +#include "ConfigSettings.h" +#include "ESPNetwork.h" +#include "Web.h" +#include "Sockets.h" +#include "Utils.h" +#include "Somfy.h" +#include "MQTT.h" +#include "GitOTA.h" +#include "esp_core_dump.h" + +static const char *TAG = "Main"; + +ConfigSettings settings; +Web webServer; +SocketEmitter sockEmit; +ESPNetwork net; +rebootDelay_t rebootDelay; +SomfyShadeController somfy; +MQTTClass mqtt; +GitUpdater git; + +uint32_t oldheap = 0; +void listDir(const char *dirname, uint8_t levels); +void setup(); +void loop(); +#line 28 "C:/Users/oem/Documents/PlatformIO/Projects/ESPSomfy-RTS/src/SomfyController.ino" +void listDir(const char *dirname, uint8_t levels) { + ESP_LOGI(TAG, "Listing: %s", dirname); + File root = LittleFS.open(dirname); + if (!root || !root.isDirectory()) { + ESP_LOGE(TAG, "Failed to open directory"); + return; + } + File file = root.openNextFile(); + while (file) { + if (file.isDirectory()) { + ESP_LOGI(TAG, " DIR : %s", file.name()); + if (levels) listDir(file.path(), levels - 1); + } else { + ESP_LOGI(TAG, " FILE: %-30s %d bytes", file.name(), file.size()); + } + file = root.openNextFile(); + } +} + +void setup() { + Serial.begin(115200); + ESP_LOGI(TAG, "Startup/Boot...."); + esp_core_dump_summary_t summary; + if (esp_core_dump_get_summary(&summary) == ESP_OK) { + ESP_LOGW(TAG, "*** Previous crash coredump found ***"); + ESP_LOGW(TAG, " Task: %s", summary.exc_task); + ESP_LOGW(TAG, " PC: 0x%08x", summary.exc_pc); +#ifdef CONFIG_IDF_TARGET_ARCH_XTENSA + ESP_LOGW(TAG, " Cause: %d", summary.ex_info.exc_cause); + char bt_buf[256] = {0}; + int pos = 0; + for (int i = 0; i < summary.exc_bt_info.depth; i++) { + pos += snprintf(bt_buf + pos, sizeof(bt_buf) - pos, " 0x%08x", summary.exc_bt_info.bt[i]); + } + ESP_LOGW(TAG, " Backtrace:%s", bt_buf); +#elif CONFIG_IDF_TARGET_ARCH_RISCV + ESP_LOGW(TAG, " Cause: %d", summary.ex_info.mcause); + ESP_LOGW(TAG, " MTVAL: 0x%08x RA: 0x%08x SP: 0x%08x", + summary.ex_info.mtval, summary.ex_info.ra, summary.ex_info.sp); +#endif + } + ESP_LOGI(TAG, "Mounting File System..."); + + + if (LittleFS.begin()) { + ESP_LOGI(TAG, "Total: %d bytes", LittleFS.totalBytes()); + ESP_LOGI(TAG, "Used: %d bytes", LittleFS.usedBytes()); + ESP_LOGI(TAG, "Free: %d bytes", LittleFS.totalBytes() - LittleFS.usedBytes()); + listDir("/", 3); + } else { + ESP_LOGE(TAG, "LittleFS mount failed!"); + } + + if(LittleFS.begin()) ESP_LOGI(TAG, "File system mounted successfully"); + else ESP_LOGE(TAG, "Error mounting file system"); + settings.begin(); + if(WiFi.status() == WL_CONNECTED) WiFi.disconnect(true); + delay(10); + webServer.startup(); + webServer.begin(); + delay(1000); + net.setup(); + somfy.begin(); + +#if ESP_ARDUINO_VERSION_MAJOR >= 3 + const esp_task_wdt_config_t wdt_config = { .timeout_ms = 15000, .idle_core_mask = 1, .trigger_panic = true }; + esp_task_wdt_init(&wdt_config); +#else + esp_task_wdt_init(15, true); +#endif + esp_task_wdt_add(NULL); + +} + +void loop() { + + + if(rebootDelay.reboot && millis() > rebootDelay.rebootTime) { + ESP_LOGI(TAG, "Rebooting after %lums", rebootDelay.rebootTime); + net.end(); + ESP.restart(); + return; + } + uint32_t timing = millis(); + + net.loop(); + if(millis() - timing > 100) ESP_LOGD(TAG, "Timing Net: %ldms", millis() - timing); + timing = millis(); + esp_task_wdt_reset(); + somfy.loop(); + if(millis() - timing > 100) ESP_LOGD(TAG, "Timing Somfy: %ldms", millis() - timing); + timing = millis(); + esp_task_wdt_reset(); + if(net.connected() || net.softAPOpened) { + if(!rebootDelay.reboot && net.connected() && !net.softAPOpened) { + git.loop(); + esp_task_wdt_reset(); + } + webServer.loop(); + esp_task_wdt_reset(); + if(millis() - timing > 100) ESP_LOGD(TAG, "Timing WebServer: %ldms", millis() - timing); + esp_task_wdt_reset(); + timing = millis(); + sockEmit.loop(); + if(millis() - timing > 100) ESP_LOGD(TAG, "Timing Socket: %ldms", millis() - timing); + esp_task_wdt_reset(); + timing = millis(); + } + if(rebootDelay.reboot && millis() > rebootDelay.rebootTime) { + net.end(); + ESP.restart(); + } + esp_task_wdt_reset(); +} \ No newline at end of file diff --git a/src/Web.cpp b/src/Web.cpp index 907f40f..ca40c14 100644 --- a/src/Web.cpp +++ b/src/Web.cpp @@ -374,6 +374,7 @@ static void serializeTransceiverConfig(JsonFormatter &json) { json.addElem("txPower", cfg.txPower); json.addElem("proto", static_cast(cfg.proto)); json.addElem("enabled", cfg.enabled); + json.addElem("noiseDetection", cfg.noiseDetection); json.addElem("radioInit", cfg.radioInit); } static void serializeAppVersion(JsonFormatter &json, appver_t &ver) {