diff --git a/src/CHANGES.md b/src/CHANGES.md index cb9d8deb2..3dc4a7237 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,8 @@ ## 0.8.4 - 2023-11-10 * changed MqTT alarm topic, removed retained flag #1212 * reduce last_success MQTT messages (#1124) +* introduced tabs in WebGUI (inverter settings) +* added inverter-wise power level and frequency ## 0.8.3 - 2023-11-09 * fix yield day reset during day #848 diff --git a/src/app.cpp b/src/app.cpp index afe171322..38f31e070 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -34,7 +34,7 @@ void app::setup() { DBGPRINTLN(F("false")); if(mConfig->nrf.enabled) { - mNrfRadio.setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); + mNrfRadio.setup(mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); mNrfRadio.enableDebug(); } #if defined(ESP32) diff --git a/src/config/config.h b/src/config/config.h index f03ac702a..e9d3adece 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -132,9 +132,6 @@ #define LED_HIGH_ACTIVE false #endif -// default NRF24 power, possible values (0 - 3) -#define DEF_AMPLIFIERPOWER 1 - // number of packets hold in buffer #define PACKET_BUFFER_SIZE 30 diff --git a/src/config/settings.h b/src/config/settings.h index 0771c148e..d46e5687e 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -30,6 +30,8 @@ * https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#flash-layout * */ +#define CONFIG_VERSION 1 + #define PROT_MASK_INDEX 0x0001 #define PROT_MASK_LIVE 0x0002 @@ -88,7 +90,6 @@ typedef struct { uint8_t pinMiso; uint8_t pinMosi; uint8_t pinSclk; - uint8_t amplifierPower; } cfgNrf24_t; typedef struct { @@ -142,6 +143,8 @@ typedef struct { uint16_t chMaxPwr[6]; double yieldCor[6]; // YieldTotal correction value char chName[6][MAX_NAME_LENGTH]; + uint8_t frequency; + uint8_t powerLevel; } cfgIv_t; typedef struct { @@ -188,6 +191,7 @@ typedef struct { cfgInst_t inst; plugins_t plugin; bool valid; + uint16_t configVersion; } settings_t; class settings { @@ -284,6 +288,7 @@ class settings { if(root.containsKey(F("led"))) jsonLed(root[F("led")]); if(root.containsKey(F("plugin"))) jsonPlugin(root[F("plugin")]); if(root.containsKey(F("inst"))) jsonInst(root[F("inst")]); + getConfigVersion(root.as()); } else { Serial.println(F("failed to parse json, using default config")); @@ -299,6 +304,7 @@ class settings { DynamicJsonDocument json(MAX_ALLOWED_BUF_SIZE); JsonObject root = json.to(); + json[F("version")] = CONFIG_VERSION; jsonNetwork(root.createNestedObject(F("wifi")), true); jsonNrf(root.createNestedObject(F("nrf")), true); #if defined(ESP32) @@ -391,7 +397,6 @@ class settings { mCfg.nrf.pinMosi = DEF_NRF_MOSI_PIN; mCfg.nrf.pinSclk = DEF_NRF_SCLK_PIN; - mCfg.nrf.amplifierPower = DEF_AMPLIFIERPOWER & 0x03; mCfg.nrf.enabled = true; #if defined(ESP32) @@ -436,6 +441,11 @@ class settings { mCfg.inst.rstMaxValsMidNight = false; mCfg.inst.yieldEffiency = 0.955f; + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value + mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + } + mCfg.led.led0 = DEF_LED0; mCfg.led.led1 = DEF_LED1; mCfg.led.led_high_active = LED_HIGH_ACTIVE; @@ -446,13 +456,30 @@ class settings { mCfg.plugin.display.contrast = 60; mCfg.plugin.display.pxShift = true; mCfg.plugin.display.rot = 0; - mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA - mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL + mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA + mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL mCfg.plugin.display.disp_cs = DEF_PIN_OFF; mCfg.plugin.display.disp_reset = DEF_PIN_OFF; mCfg.plugin.display.disp_busy = DEF_PIN_OFF; mCfg.plugin.display.disp_dc = DEF_PIN_OFF; - } + } + + void loadAddedDefaults() { + if(0 == mCfg.configVersion) { + for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { + mCfg.inst.iv[i].powerLevel = 0xff; // impossible high value + mCfg.inst.iv[i].frequency = 0x12; // 863MHz (minimum allowed frequency) + } + } + } + + void getConfigVersion(JsonObject obj) { + getVal(obj, F("version"), &mCfg.configVersion); + DPRINT(DBG_INFO, F("Config Version: ")); + DBGPRINTLN(String(mCfg.configVersion)); + if(CONFIG_VERSION != mCfg.configVersion) + loadAddedDefaults(); + } void jsonNetwork(JsonObject obj, bool set = false) { if(set) { @@ -506,7 +533,6 @@ class settings { obj[F("sclk")] = mCfg.nrf.pinSclk; obj[F("mosi")] = mCfg.nrf.pinMosi; obj[F("miso")] = mCfg.nrf.pinMiso; - obj[F("pwr")] = mCfg.nrf.amplifierPower; obj[F("en")] = (bool) mCfg.nrf.enabled; } else { getVal(obj, F("intvl"), &mCfg.nrf.sendInterval); @@ -516,7 +542,6 @@ class settings { getVal(obj, F("sclk"), &mCfg.nrf.pinSclk); getVal(obj, F("mosi"), &mCfg.nrf.pinMosi); getVal(obj, F("miso"), &mCfg.nrf.pinMiso); - getVal(obj, F("pwr"), &mCfg.nrf.amplifierPower); #if !defined(ESP32) mCfg.nrf.enabled = true; // ESP8266, read always as enabled #else @@ -707,6 +732,8 @@ class settings { obj[F("en")] = (bool)cfg->enabled; obj[F("name")] = cfg->name; obj[F("sn")] = cfg->serial.u64; + obj[F("freq")] = cfg->frequency; + obj[F("pa")] = cfg->powerLevel; for(uint8_t i = 0; i < 6; i++) { obj[F("yield")][i] = cfg->yieldCor[i]; obj[F("pwr")][i] = cfg->chMaxPwr[i]; @@ -716,6 +743,8 @@ class settings { getVal(obj, F("en"), &cfg->enabled); getChar(obj, F("name"), cfg->name, MAX_NAME_LENGTH); getVal(obj, F("sn"), &cfg->serial.u64); + getVal(obj, F("freq"), &cfg->frequency); + getVal(obj, F("pa"), &cfg->powerLevel); uint8_t size = 4; if(obj.containsKey(F("pwr"))) size = obj[F("pwr")].size(); diff --git a/src/hm/Communication.h b/src/hm/Communication.h index 95f438d58..2675d1a27 100644 --- a/src/hm/Communication.h +++ b/src/hm/Communication.h @@ -92,7 +92,7 @@ class Communication : public CommQueue<> { q->iv->radioStatistics.rxFailNoAnser++; // got nothing mHeu.setGotNothing(q->iv); if((IV_HMS == q->iv->ivGen) || (IV_HMT == q->iv->ivGen)) { - q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, WORK_FREQ_KHZ); + q->iv->radio->switchFrequency(q->iv, HOY_BOOT_FREQ_KHZ, (q->iv->config->frequency*FREQ_STEP_KHZ + HOY_BASE_FREQ_KHZ)); mWaitTimeout = millis() + 1000; } } else diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 9bfe28b62..52b7c5dd5 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -129,6 +129,7 @@ class Inverter { statistics_t radioStatistics; // information about transmitted, failed, ... packets int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h') uint8_t txRfChId; // RF TX channel id + uint8_t curCmtFreq; // current used CMT frequency, used to check if freq. was changed during runtime static uint32_t *timestamp; // system timestamp static cfgInst_t *generalConfig; // general inverter configuration from setup @@ -194,6 +195,7 @@ class Inverter { initAssignment(&recordConfig, SystemConfigPara); initAssignment(&recordAlarm, AlarmData); toRadioId(); + curCmtFreq = this->config->frequency; // update to frequency read from settings } uint8_t getPosByChFld(uint8_t channel, uint8_t fieldId, record_t<> *rec) { diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 203f39aa6..a55c7d3ca 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -45,7 +45,7 @@ class HmRadio : public Radio { } ~HmRadio() {} - void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { + void setup(uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); pinMode(irq, INPUT_PULLUP); @@ -81,9 +81,7 @@ class HmRadio : public Radio { // enable all receiving interrupts mNrf24.maskIRQ(false, false, false); - DPRINT(DBG_INFO, F("RF24 Amp Pwr: RF24_PA_")); - DPRINTLN(DBG_INFO, String(rf24AmpPowerNames[ampPwr])); - mNrf24.setPALevel(ampPwr & 0x03); + mNrf24.setPALevel(1); // low is default if(mNrf24.isChipConnected()) { DPRINTLN(DBG_INFO, F("Radio Config:")); @@ -269,6 +267,7 @@ class HmRadio : public Radio { } void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { + mNrf24.setPALevel(iv->config->powerLevel & 0x03); updateCrcs(&len, appendCrc16); // set TX and RX channels diff --git a/src/hms/cmt2300a.h b/src/hms/cmt2300a.h index ab54617d3..75d2ce5c7 100644 --- a/src/hms/cmt2300a.h +++ b/src/hms/cmt2300a.h @@ -422,6 +422,10 @@ class Cmt2300a { return HOY_BASE_FREQ_KHZ + (mCurCh * FREQ_STEP_KHZ); } + uint8_t getCurrentChannel(void) { + return mCurCh; + } + void setPaLevel(int8_t level) { if(level < -10) level = -10; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index 097a3f03b..811c60d2b 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -66,6 +66,11 @@ class CmtRadio : public Radio { uint8_t fromCh = mCmt.freq2Chan(fromkHz); uint8_t toCh = mCmt.freq2Chan(tokHz); + return switchFrequencyCh(iv, fromCh, toCh); + } + + private: + bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { if((0xff == fromCh) || (0xff == toCh)) return false; @@ -75,8 +80,17 @@ class CmtRadio : public Radio { return true; } - private: void sendPacket(Inverter<> *iv, uint8_t len, bool isRetransmit, bool appendCrc16=true) { + // frequency was changed during runtime + if(iv->curCmtFreq != iv->config->frequency) { + if(switchFrequencyCh(iv, iv->curCmtFreq, iv->config->frequency)) + iv->curCmtFreq = iv->config->frequency; + } else { + // inverters have maybe different settings regarding frequency + if(mCmt.getCurrentChannel() != iv->config->frequency) + mCmt.switchChannel(iv->config->frequency); + } + updateCrcs(&len, appendCrc16); if(mSerialDebug) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 2267661e9..6e977309e 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -346,7 +346,14 @@ class RestApi { obj2[F("name")] = String(iv->config->name); obj2[F("serial")] = String(iv->config->serial.u64, HEX); obj2[F("channels")] = iv->channels; - obj2[F("version")] = String(iv->getFwVersion()); + obj2[F("freq")] = iv->config->frequency; + if(0xff == iv->config->powerLevel) { + if((IV_HMT == iv->ivGen) || (IV_HMS == iv->ivGen)) + obj2[F("pa")] = 30; // 20dBm + else + obj2[F("pa")] = 1; // low + } else + obj2[F("pa")] = iv->config->powerLevel; for(uint8_t j = 0; j < iv->channels; j ++) { obj2[F("ch_yield_cor")][j] = (double)iv->config->yieldCor[j]; @@ -529,7 +536,6 @@ class RestApi { void getRadioNrf(JsonObject obj) { obj[F("en")] = (bool) mConfig->nrf.enabled; obj[F("isconnected")] = mRadioNrf->isChipConnected(); - obj[F("power_level")] = mConfig->nrf.amplifierPower; obj[F("dataRate")] = mRadioNrf->getDataRate(); //obj[F("isPVariant")] = mRadioNrf->isPVariant(); } @@ -736,6 +742,8 @@ class RestApi { case 0x61: iv->type = INV_TYPE_4CH; iv->channels = 4; break; default: break; } + iv->config->frequency = jsonIn[F("freq")]; + iv->config->powerLevel = jsonIn[F("pa")]; mApp->saveSettings(false); // without reboot } else { jsonOut[F("error")] = F("unknown cmd"); diff --git a/src/web/html/api.js b/src/web/html/api.js index 8c0ba54e2..11db6c45f 100644 --- a/src/web/html/api.js +++ b/src/web/html/api.js @@ -192,6 +192,34 @@ function badge(success, text, second="error") { return ml("span", {class: "badge badge-" + ((success) ? "success" : second)}, text); } +function tabChange(id) { + var els = document.getElementsByClassName("nav-link"); + [].forEach.call(els, function(e) { + if(e.id != id) + e.classList.remove('active'); + else + e.classList.add('active'); + }); + + els = document.getElementsByClassName("tab-content"); + [].forEach.call(els, function(e) { + if(e.id == ("div"+id.substring(3))) + e.classList.remove('hide'); + else + e.classList.add('hide'); + }); +} + +function tabs(items) { + var li = []; + var cl = " active"; + for(it of items) { + li.push(ml("li", {class: "nav-item"},ml("a", {id: "tab"+it, class: "nav-link" + cl, href: "#", onclick: function(){tabChange(this.id)}}, it))) + cl = ""; + } + return ml("ul", {class: "nav nav-tabs mb-4"}, li); +} + function des(val) { e = document.createElement('p'); e.classList.add("subdes"); @@ -223,13 +251,11 @@ function inp(name, val, max=32, cl=["text"], id=null, type=null, pattern=null, t } function sel(name, options, selId) { - e = document.createElement('select'); - e.name = name; + var o = []; for(it of options) { - o = opt(it[0], it[1], (it[0] == selId)); - e.appendChild(o); + o.push(opt(it[0], it[1], (it[0] == selId))); } - return e; + return ml("select", {name: name}, o); } function selDelAllOpt(sel) { @@ -240,9 +266,7 @@ function selDelAllOpt(sel) { } function opt(val, html, sel=false) { - o = document.createElement('option'); - o.value = val; - o.innerHTML = html; + var o = ml("option", {value: val}, html); if(sel) o.selected = true; return o; @@ -301,7 +325,7 @@ function svg(data=null, w=24, h=24, cl=null, tooltip=null) { function modal(title, body) { if(null == document.getElementById("modal")) { document.getElementById("wrapper").append( - ml("div", {id: "modal-wrapper", class: "modal", onclick: modalClose}), + ml("div", {id: "modal-wrapper", onclick: modalClose}), ml("div", {id: "modal", class: "modal"}, ml("div", {class: "modal-content"}, [ ml("div", {class: "modal-header"}, [ diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 2ec5d2b55..1ca46ced0 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -438,6 +438,23 @@ [47, "GPIO47"], [48, "GPIO48"], ]; + var nrfPa = [ + [0, "MIN (recommended)"], + [1, "LOW"], + [2, "HIGH"], + [3, "MAX (experimental)"] + ]; + var esp32cmtPa = []; + var esp32cmtFreq = []; + var freqFmt = new Intl.NumberFormat('en-US', { + minimumIntegerDigits: 3, + minimumFractionDigits: 2 + }); + for(var i = 0; i < 31; i++) { + esp32cmtPa.push([i, String(i-10) + " dBm"]); + if(i < 29) + esp32cmtFreq.push([i, freqFmt.format(860 + i*0.25) + " MHz"]); + } /*ENDIF_ESP32*/ var led_high_active = [ [0, "low active"], @@ -647,6 +664,7 @@ ml("th", {}, "Name (optional)"), ml("th", {}, "Yield Correction [kWh] (optional)") ])); + for(let i = 0; i < 6; i++) { lines.push(ml("tr", {id: "ch"+i}, [ ml("td", {}, String(i+1)), @@ -655,29 +673,54 @@ ml("td", {}, ml("input", {name: "yld_c"+i, class: "text", type: "number", max: 999999, value: obj.ch_yield_cor[i]}, null)) ])); } + var cbEn = ml("input", {name: "enable", type: "checkbox"}, null); if(obj.enabled) cbEn.checked = true; var ser = ml("input", {name: "ser", class: "text", type: "number", max: 138999999999, value: obj.serial}, null); var html = ml("div", {}, [ - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Serial"), - ml("div", {class: "col-8"}, ser) + tabs(["General", "Inputs", "Radio"]), + ml("div", {id: "divGeneral", class: "tab-content"}, [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4"}, "Enable"), + ml("div", {class: "col-8"}, cbEn) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Serial"), + ml("div", {class: "col-8"}, ser) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Name"), + ml("div", {class: "col-8"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) + ]) ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Name"), - ml("div", {class: "col-8"}, ml("input", {name: "name", class: "text", type: "text", value: obj.name}, null)) + ml("div", {id: "divInputs", class: "tab-content hide"}, [ + ml("div", {class: "row mb-3"}, + ml("table", {class: "table"}, + ml("tbody", {}, lines) + ) + ) ]), - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-4"}, "Enable"), - ml("div", {class: "col-8"}, cbEn) + ml("div", {id: "divRadio", class: "tab-content hide"}, [ + ml("input", {type: "hidden", name: "isnrf"}, null), + ml("div", {id: "setcmt"}, [ + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Frequency"), + ml("div", {class: "col-8"}, sel("freq", esp32cmtFreq, obj.freq)) + ]), + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Power Level"), + ml("div", {class: "col-8"}, sel("cmtpa", esp32cmtPa, obj.pa)) + ]), + ]), + ml("div", {id: "setnrf"}, + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-4 mt-2"}, "Power Level"), + ml("div", {class: "col-8"}, sel("nrfpa", nrfPa, obj.pa)) + ]), + ), ]), - ml("div", {class: "row mb-3"}, - ml("table", {class: "table"}, - ml("tbody", {}, lines) - ) - ), - ml("div", {class: "row mb-3"}, [ + ml("div", {class: "row mt-5"}, [ ml("div", {class: "col-8", id: "res"}, ""), ml("div", {class: "col-4 a-r"}, ml("input", {type: "button", value: "save", class: "btn", onclick: function() { ivSave(); }}, null)) ]) @@ -685,28 +728,34 @@ ['keyup', 'change'].forEach(function(evt) { ser.addEventListener(evt, (e) => { - var serial = ser.value.substring(0,4); + var sn = parseInt(ser.value, 16); + sn = Math.floor(sn / Math.pow(2, 32)); + var max = 1; + switch(sn & 0x00f0) { + case 0x0010: max = 1; break; + case 0x0040: max = 2; break; + case 0x0060: max = 4; break; + case 0x0080: max = 6; break; + } for(var i = 0; i < 6; i++) { - setHide("ch"+i, true); + setHide("ch"+i, (i >= max)); } - if(serial.charAt(0) == 1) { - if((serial.charAt(1) == 0) || (serial.charAt(1) == 1) || (serial.charAt(1) == 3)) { - if((serial.charAt(3) == 1) || (serial.charAt(3) == 2) || (serial.charAt(3) == 4)) { - switch(serial.charAt(2)) { - default: - case "2": max = 1; break; - case "4": max = 2; break; - case "6": max = 4; break; - case "8": max = 6; break; - } + var nrf = true; + switch(sn & 0xff00) { + case 0x1000: nrf = true; break; + case 0x1100: + switch(sn & 0x000f) { + case 0x0004: nrf = false; break; + default: nrf = true; break; } - } - } - for(var i = 0; i < max; i++) { - setHide("ch"+i, false); + break; + case 0x1300: nrf = false; break; } + setHide("setcmt", nrf); + setHide("setnrf", !nrf); + document.getElementsByName("isnrf")[0].value = nrf; }) }); @@ -728,6 +777,11 @@ q.yld = document.getElementsByName("yld_c"+i)[0].value; o.ch.push(q); } + if("true" == document.getElementsByName("isnrf")[0].value) + o.pa = document.getElementsByName("nrfpa")[0].value; + else + o.pa = document.getElementsByName("cmtpa")[0].value; + o.freq = document.getElementsByName("freq")[0].value; getAjax("/api/setup", cb, "POST", JSON.stringify(o)); } @@ -845,19 +899,6 @@ ]) ); } - e.append( - ml("div", {class: "row mb-3"}, [ - ml("div", {class: "col-12 col-sm-3 my-2"}, "Power Level"), - ml("div", {class: "col-12 col-sm-9"}, - sel("rf24Power", [ - [0, "MIN (recommended)"], - [1, "LOW"], - [2, "HIGH"], - [3, "MAX (experimental)"] - ], obj["power_level"]) - ) - ]) - ); } /*IF_ESP32*/ diff --git a/src/web/html/style.css b/src/web/html/style.css index 8c40c7805..064819f53 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -686,7 +686,7 @@ div.hr { margin: 1.75rem auto; } -.modal { +.modal, #modal-wrapper { position: fixed; top: 0; right: 0; @@ -695,6 +695,10 @@ div.hr { display: block; } +.modal { + height: calc(100% - 3.5rem); +} + #modal-wrapper { background-color: #000; opacity: 0.5; @@ -710,6 +714,8 @@ div.hr { background-clip: padding-box; border: 1px solid var(--fg); flex-direction: column; + max-height: 100%; + overflow: hidden; } .modal-header { @@ -717,7 +723,7 @@ div.hr { align-items: flex-start; justify-content: space-between; padding: 1rem; - border-bottom: 1px solid #e9ecef; + border-bottom: 1px solid var(--table-border); } .modal-header .close { @@ -726,7 +732,8 @@ div.hr { } .modal-body { - padding: 1rem 1rem 2rem 1rem; + padding: 1rem; + overflow-y: auto; } .close { @@ -779,3 +786,41 @@ h5 { vertical-align: baseline; border-radius: .25rem; } + +ul { + margin-top: 0; +} + +.nav { + display: flex; + flex-wrap: wrap; + padding-left: 0; + list-style: none; +} + +.nav-tabs { + border-bottom: 1px solid var(--fg); +} + +.nav-tabs .nav-link { + margin-bottom: -1px; + border: 1px solid transparent; + border-top-left-radius: .25rem; + border-top-right-radius: .25rem; +} + +.nav-link { + display: block; + padding: .5rem 1rem; + text-decoration: none; + color: var(--fg); +} + +.nav-tabs .nav-link.active { + border-color: var(--fg) var(--fg) var(--bg); +} + +.nav-link:hover, .nav-link:visited { + background-color: var(--input-bg); + color: var(--fg); +} diff --git a/src/web/html/system.html b/src/web/html/system.html index 7eddd7b0d..a310890d5 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -45,13 +45,11 @@ } function parseRadio(obj) { - const pa = ["MIN (recommended)", "LOW", "HIGH", "MAX"]; const dr = ["1 M", "2 M", "250 k"] if(obj.radioNrf.en) { lines = [ tr("NRF24L01", badge(obj.radioNrf.isconnected, ((obj.radioNrf.isconnected) ? "" : "not ") + "connected")), - tr("NRF24 Power Level", pa[obj.radioNrf.power_level]), tr("NRF24 Data Rate", dr[obj.radioNrf.dataRate] + "bps") ]; } else diff --git a/src/web/web.h b/src/web/web.h index 002c3cbcb..c37db811a 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -519,8 +519,6 @@ class Web { } } - // nrf24 amplifier power - mConfig->nrf.amplifierPower = request->arg("rf24Power").toInt() & 0x03; mConfig->nrf.enabled = (request->arg("nrfEnable") == "on"); // cmt