From c20caf8097c897d9c44b0d2c2e0edfc77f414e07 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sun, 14 Jan 2024 00:16:43 +0100 Subject: [PATCH] Feature: Support HMS/HMT inverters in different countries with different frequency bands Thanks to @Fribur, @homeautomation2022 and @stefan123t --- include/Configuration.h | 1 + include/WebApi_dtu.h | 3 +- include/WebApi_errors.h | 3 +- include/defaults.h | 1 + lib/CMT2300a/cmt2300a_params_860.h | 2 - lib/CMT2300a/cmt2300a_params_900.h | 2 - lib/CMT2300a/cmt2300wrapper.cpp | 11 +---- lib/CMT2300a/cmt2300wrapper.h | 16 ++++++- lib/Hoymiles/src/HoymilesRadio_CMT.cpp | 46 ++++++++++++-------- lib/Hoymiles/src/HoymilesRadio_CMT.h | 24 ++++++++++- src/Configuration.cpp | 2 + src/InverterSettings.cpp | 4 +- src/WebApi_dtu.cpp | 58 +++++++++++++++++++------- webapp/src/locales/de.json | 8 +++- webapp/src/locales/en.json | 8 +++- webapp/src/locales/fr.json | 8 +++- webapp/src/types/DtuConfig.ts | 12 +++++- webapp/src/views/DtuAdminView.vue | 39 +++++++++++++++-- 18 files changed, 188 insertions(+), 60 deletions(-) diff --git a/include/Configuration.h b/include/Configuration.h index fb047e3a..4ae77a55 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -129,6 +129,7 @@ struct CONFIG_T { struct { int8_t PaLevel; uint32_t Frequency; + uint8_t CountryMode; } Cmt; } Dtu; diff --git a/include/WebApi_dtu.h b/include/WebApi_dtu.h index 45f58d32..98d28652 100644 --- a/include/WebApi_dtu.h +++ b/include/WebApi_dtu.h @@ -13,4 +13,5 @@ private: void onDtuAdminPost(AsyncWebServerRequest* request); AsyncWebServer* _server; -}; \ No newline at end of file + bool _performReload = false; +}; diff --git a/include/WebApi_errors.h b/include/WebApi_errors.h index e5703a83..efb890c5 100644 --- a/include/WebApi_errors.h +++ b/include/WebApi_errors.h @@ -15,6 +15,7 @@ enum WebApiError { DtuPollZero, DtuInvalidPowerLevel, DtuInvalidCmtFrequency, + DtuInvalidCmtCountry, ConfigBase = 3000, ConfigNotDeleted, @@ -89,4 +90,4 @@ enum WebApiError { HardwareBase = 12000, HardwarePinMappingLength, -}; \ No newline at end of file +}; diff --git a/include/defaults.h b/include/defaults.h index 9bc349be..ac871fc9 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -84,6 +84,7 @@ #define DTU_NRF_PA_LEVEL 0U #define DTU_CMT_PA_LEVEL 0 #define DTU_CMT_FREQUENCY 865000000U +#define DTU_CMT_COUNTRY_MODE 0U #define MQTT_HASS_ENABLED false #define MQTT_HASS_EXPIRE true diff --git a/lib/CMT2300a/cmt2300a_params_860.h b/lib/CMT2300a/cmt2300a_params_860.h index 7c49c4f7..94f15526 100644 --- a/lib/CMT2300a/cmt2300a_params_860.h +++ b/lib/CMT2300a/cmt2300a_params_860.h @@ -91,8 +91,6 @@ #include "cmt2300a_defs.h" #include -#define CMT_BASE_FREQ_860 860000000 - /* [CMT Bank] with RSSI offset of +- 0 (and Tx power double bit not set) */ static uint8_t g_cmt2300aCmtBank_860[CMT2300A_CMT_BANK_SIZE] = { 0x00, diff --git a/lib/CMT2300a/cmt2300a_params_900.h b/lib/CMT2300a/cmt2300a_params_900.h index 70722b24..19b8eeac 100644 --- a/lib/CMT2300a/cmt2300a_params_900.h +++ b/lib/CMT2300a/cmt2300a_params_900.h @@ -91,8 +91,6 @@ #include "cmt2300a_defs.h" #include -#define CMT_BASE_FREQ_900 900000000 - /* [CMT Bank] with RSSI offset of +- 0 (and Tx power double bit not set) */ static uint8_t g_cmt2300aCmtBank_900[CMT2300A_CMT_BANK_SIZE] = { 0x00, diff --git a/lib/CMT2300a/cmt2300wrapper.cpp b/lib/CMT2300a/cmt2300wrapper.cpp index 19e743ba..87ed3bae 100644 --- a/lib/CMT2300a/cmt2300wrapper.cpp +++ b/lib/CMT2300a/cmt2300wrapper.cpp @@ -243,16 +243,9 @@ bool CMT2300A::rxFifoAvailable() ) & CMT2300A_ReadReg(CMT2300A_CUS_INT_FLAG); } -uint32_t CMT2300A::getBaseFrequency() +uint32_t CMT2300A::getBaseFrequency() const { - switch (_frequencyBand) { - case FrequencyBand_t::BAND_900: - return CMT_BASE_FREQ_900; - break; - default: - return CMT_BASE_FREQ_860; - break; - } + return getBaseFrequency(_frequencyBand); } FrequencyBand_t CMT2300A::getFrequencyBand() const diff --git a/lib/CMT2300a/cmt2300wrapper.h b/lib/CMT2300a/cmt2300wrapper.h index d3ce1d0d..aab5e7bf 100644 --- a/lib/CMT2300a/cmt2300wrapper.h +++ b/lib/CMT2300a/cmt2300wrapper.h @@ -7,6 +7,9 @@ #define FH_OFFSET 100 // value * CMT2300A_ONE_STEP_SIZE = channel frequency offset #define CMT_SPI_SPEED 4000000 // 4 MHz +#define CMT_BASE_FREQ_900 900000000 +#define CMT_BASE_FREQ_860 860000000 + enum FrequencyBand_t { BAND_860, BAND_900, @@ -91,7 +94,18 @@ public: bool rxFifoAvailable(); - uint32_t getBaseFrequency(); + uint32_t getBaseFrequency() const; + static constexpr uint32_t getBaseFrequency(FrequencyBand_t band) + { + switch (band) { + case FrequencyBand_t::BAND_900: + return CMT_BASE_FREQ_900; + break; + default: + return CMT_BASE_FREQ_860; + break; + } + } FrequencyBand_t getFrequencyBand() const; void setFrequencyBand(const FrequencyBand_t mode); diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp index d0e0b0e9..c58056c3 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp @@ -8,17 +8,15 @@ #include #include -struct CountryFrequencyDefinition_t { - FrequencyBand_t Band; - uint32_t Freq_Legal_Min; - uint32_t Freq_Legal_Max; - uint32_t Freq_Default; - uint32_t Freq_StartUp; -}; - constexpr CountryFrequencyDefinition_t make_value(FrequencyBand_t Band, uint32_t Freq_Legal_Min, uint32_t Freq_Legal_Max, uint32_t Freq_Default, uint32_t Freq_StartUp) { - CountryFrequencyDefinition_t v = { Band, Freq_Legal_Min, Freq_Legal_Max, Freq_Default, Freq_StartUp }; + // frequency can not be lower than actual initailized base freq + 250000 + uint32_t minFrequency = CMT2300A::getBaseFrequency(Band) + HoymilesRadio_CMT::getChannelWidth(); + + // =923500, 0xFF does not work + uint32_t maxFrequency = CMT2300A::getBaseFrequency(Band) + 0xFE * HoymilesRadio_CMT::getChannelWidth(); + + CountryFrequencyDefinition_t v = { Band, minFrequency, maxFrequency, Freq_Legal_Min, Freq_Legal_Max, Freq_Default, Freq_StartUp }; return v; } @@ -54,6 +52,25 @@ uint8_t HoymilesRadio_CMT::getChannelFromFrequency(const uint32_t frequency) con return (frequency - _radio->getBaseFrequency()) / getChannelWidth(); // frequency to channel } +std::vector HoymilesRadio_CMT::getCountryFrequencyList() +{ + std::vector v; + for (const auto& [key, value] : countryDefinition) { + CountryFrequencyList_t s; + s.mode = key; + s.definition.Band = value.Band; + s.definition.Freq_Default = value.Freq_Default; + s.definition.Freq_StartUp = value.Freq_StartUp; + s.definition.Freq_Min = value.Freq_Min; + s.definition.Freq_Max = value.Freq_Max; + s.definition.Freq_Legal_Max = value.Freq_Legal_Max; + s.definition.Freq_Legal_Min = value.Freq_Legal_Min; + + v.push_back(s); + } + return v; +} + bool HoymilesRadio_CMT::cmtSwitchDtuFreq(const uint32_t to_frequency) { const uint8_t toChannel = getChannelFromFrequency(to_frequency); @@ -207,19 +224,12 @@ bool HoymilesRadio_CMT::isConnected() const uint32_t HoymilesRadio_CMT::getMinFrequency() const { - // frequency can not be lower than actual initailized base freq + 250000 - return _radio->getBaseFrequency() + getChannelWidth(); + return countryDefinition.at(_countryMode).Freq_Min; } uint32_t HoymilesRadio_CMT::getMaxFrequency() const { - // =923500, 0xFF does not work - return _radio->getBaseFrequency() + 0xFE * getChannelWidth(); -} - -uint32_t HoymilesRadio_CMT::getChannelWidth() -{ - return FH_OFFSET * CMT2300A_ONE_STEP_SIZE; + return countryDefinition.at(_countryMode).Freq_Max; } CountryModeId_t HoymilesRadio_CMT::getCountryMode() const diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.h b/lib/Hoymiles/src/HoymilesRadio_CMT.h index ad63d8c1..aa584d60 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.h +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.h @@ -8,6 +8,7 @@ #include #include #include +#include // number of fragments hold in buffer #define FRAGMENT_BUFFER_SIZE 30 @@ -20,6 +21,22 @@ enum CountryModeId_t { MODE_EU, MODE_US, MODE_BR, + CountryModeId_Max +}; + +struct CountryFrequencyDefinition_t { + FrequencyBand_t Band; + uint32_t Freq_Min; + uint32_t Freq_Max; + uint32_t Freq_Legal_Min; + uint32_t Freq_Legal_Max; + uint32_t Freq_Default; + uint32_t Freq_StartUp; +}; + +struct CountryFrequencyList_t { + CountryModeId_t mode; + CountryFrequencyDefinition_t definition; }; class HoymilesRadio_CMT : public HoymilesRadio { @@ -34,7 +51,10 @@ public: uint32_t getMinFrequency() const; uint32_t getMaxFrequency() const; - static uint32_t getChannelWidth(); + static constexpr uint32_t getChannelWidth() + { + return FH_OFFSET * CMT2300A_ONE_STEP_SIZE; + } CountryModeId_t getCountryMode() const; void setCountryMode(CountryModeId_t mode); @@ -44,6 +64,8 @@ public: uint32_t getFrequencyFromChannel(const uint8_t channel) const; uint8_t getChannelFromFrequency(const uint32_t frequency) const; + std::vector getCountryFrequencyList(); + private: void ARDUINO_ISR_ATTR handleInt1(); void ARDUINO_ISR_ATTR handleInt2(); diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 70a3a280..5181ebe4 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -95,6 +95,7 @@ bool ConfigurationClass::write() dtu["nrf_pa_level"] = config.Dtu.Nrf.PaLevel; dtu["cmt_pa_level"] = config.Dtu.Cmt.PaLevel; dtu["cmt_frequency"] = config.Dtu.Cmt.Frequency; + dtu["cmt_country_mode"] = config.Dtu.Cmt.CountryMode; JsonObject security = doc.createNestedObject("security"); security["password"] = config.Security.Password; @@ -263,6 +264,7 @@ bool ConfigurationClass::read() config.Dtu.Nrf.PaLevel = dtu["nrf_pa_level"] | DTU_NRF_PA_LEVEL; config.Dtu.Cmt.PaLevel = dtu["cmt_pa_level"] | DTU_CMT_PA_LEVEL; config.Dtu.Cmt.Frequency = dtu["cmt_frequency"] | DTU_CMT_FREQUENCY; + config.Dtu.Cmt.CountryMode = dtu["cmt_country_mode"] | DTU_CMT_COUNTRY_MODE; JsonObject security = doc["security"]; strlcpy(config.Security.Password, security["password"] | ACCESS_POINT_PASSWORD, sizeof(config.Security.Password)); diff --git a/src/InverterSettings.cpp b/src/InverterSettings.cpp index 506adacc..21bf2d93 100644 --- a/src/InverterSettings.cpp +++ b/src/InverterSettings.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2023 Thomas Basler and others + * Copyright (C) 2023-2024 Thomas Basler and others */ #include "InverterSettings.h" #include "Configuration.h" @@ -45,6 +45,8 @@ void InverterSettingsClass::init(Scheduler& scheduler) if (PinMapping.isValidCmt2300Config()) { Hoymiles.initCMT(pin.cmt_sdio, pin.cmt_clk, pin.cmt_cs, pin.cmt_fcs, pin.cmt_gpio2, pin.cmt_gpio3); + MessageOutput.println(F(" Setting country mode... ")); + Hoymiles.getRadioCmt()->setCountryMode(static_cast(config.Dtu.Cmt.CountryMode)); MessageOutput.println(F(" Setting CMT target frequency... ")); Hoymiles.getRadioCmt()->setInverterTargetFrequency(config.Dtu.Cmt.Frequency); } diff --git a/src/WebApi_dtu.cpp b/src/WebApi_dtu.cpp index ccf0aa08..a9828a11 100644 --- a/src/WebApi_dtu.cpp +++ b/src/WebApi_dtu.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2022-2023 Thomas Basler and others + * Copyright (C) 2022-2024 Thomas Basler and others */ #include "WebApi_dtu.h" #include "Configuration.h" @@ -21,6 +21,18 @@ void WebApiDtuClass::init(AsyncWebServer& server) void WebApiDtuClass::loop() { + if (_performReload) { + // Execute stuff in main thread to avoid busy SPI bus + CONFIG_T& config = Configuration.get(); + Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu.Nrf.PaLevel); + Hoymiles.getRadioCmt()->setPALevel(config.Dtu.Cmt.PaLevel); + Hoymiles.getRadioNrf()->setDtuSerial(config.Dtu.Serial); + Hoymiles.getRadioCmt()->setDtuSerial(config.Dtu.Serial); + Hoymiles.getRadioCmt()->setCountryMode(static_cast(config.Dtu.Cmt.CountryMode)); + Hoymiles.getRadioCmt()->setInverterTargetFrequency(config.Dtu.Cmt.Frequency); + Hoymiles.setPollInterval(config.Dtu.PollInterval); + _performReload = false; + } } void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request) @@ -45,10 +57,20 @@ void WebApiDtuClass::onDtuAdminGet(AsyncWebServerRequest* request) root["cmt_enabled"] = Hoymiles.getRadioCmt()->isInitialized(); root["cmt_palevel"] = config.Dtu.Cmt.PaLevel; root["cmt_frequency"] = config.Dtu.Cmt.Frequency; - root["cmt_min_freq"] = Hoymiles.getRadioCmt()->getMinFrequency(); - root["cmt_max_freq"] = Hoymiles.getRadioCmt()->getMaxFrequency(); + root["cmt_country"] = config.Dtu.Cmt.CountryMode; root["cmt_chan_width"] = Hoymiles.getRadioCmt()->getChannelWidth(); + auto data = root.createNestedArray("country_def"); + auto countryDefs = Hoymiles.getRadioCmt()->getCountryFrequencyList(); + for (const auto& definition : countryDefs) { + auto obj = data.createNestedObject(); + obj["freq_default"] = definition.definition.Freq_Default; + obj["freq_min"] = definition.definition.Freq_Min; + obj["freq_max"] = definition.definition.Freq_Max; + obj["freq_legal_min"] = definition.definition.Freq_Legal_Min; + obj["freq_legal_max"] = definition.definition.Freq_Legal_Max; + } + response->setLength(); request->send(response); } @@ -96,7 +118,8 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) && root.containsKey("pollinterval") && root.containsKey("nrf_palevel") && root.containsKey("cmt_palevel") - && root.containsKey("cmt_frequency"))) { + && root.containsKey("cmt_frequency") + && root.containsKey("cmt_country"))) { retMsg["message"] = "Values are missing!"; retMsg["code"] = WebApiError::GenericValueMissing; response->setLength(); @@ -136,14 +159,23 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) return; } - if (root["cmt_frequency"].as() < Hoymiles.getRadioCmt()->getMinFrequency() - || root["cmt_frequency"].as() > Hoymiles.getRadioCmt()->getMaxFrequency() - || root["cmt_frequency"].as() % 250 > 0) { + if (root["cmt_country"].as() >= CountryModeId_t::CountryModeId_Max) { + retMsg["message"] = "Invalid country setting!"; + retMsg["code"] = WebApiError::DtuInvalidCmtCountry; + response->setLength(); + request->send(response); + return; + } + + auto FrequencyDefinition = Hoymiles.getRadioCmt()->getCountryFrequencyList()[root["cmt_country"].as()].definition; + if (root["cmt_frequency"].as() < FrequencyDefinition.Freq_Min + || root["cmt_frequency"].as() > FrequencyDefinition.Freq_Max + || root["cmt_frequency"].as() % Hoymiles.getRadioCmt()->getChannelWidth() > 0) { retMsg["message"] = "Invalid CMT frequency setting!"; retMsg["code"] = WebApiError::DtuInvalidCmtFrequency; - retMsg["param"]["min"] = Hoymiles.getRadioCmt()->getMinFrequency(); - retMsg["param"]["max"] = Hoymiles.getRadioCmt()->getMaxFrequency(); + retMsg["param"]["min"] = FrequencyDefinition.Freq_Min; + retMsg["param"]["max"] = FrequencyDefinition.Freq_Max; response->setLength(); request->send(response); return; @@ -157,16 +189,12 @@ void WebApiDtuClass::onDtuAdminPost(AsyncWebServerRequest* request) config.Dtu.Nrf.PaLevel = root["nrf_palevel"].as(); config.Dtu.Cmt.PaLevel = root["cmt_palevel"].as(); config.Dtu.Cmt.Frequency = root["cmt_frequency"].as(); + config.Dtu.Cmt.CountryMode = root["cmt_country"].as(); WebApi.writeConfig(retMsg); response->setLength(); request->send(response); - Hoymiles.getRadioNrf()->setPALevel((rf24_pa_dbm_e)config.Dtu.Nrf.PaLevel); - Hoymiles.getRadioCmt()->setPALevel(config.Dtu.Cmt.PaLevel); - Hoymiles.getRadioNrf()->setDtuSerial(config.Dtu.Serial); - Hoymiles.getRadioCmt()->setDtuSerial(config.Dtu.Serial); - Hoymiles.getRadioCmt()->setInverterTargetFrequency(config.Dtu.Cmt.Frequency); - Hoymiles.setPollInterval(config.Dtu.PollInterval); + _performReload = true; } diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 2f0fb839..c7a70736 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -47,6 +47,7 @@ "2002": "Das Abfraginterval muss größer als 0 sein!", "2003": "Ungültige Sendeleistung angegeben!", "2004": "Die Frequenz muss zwischen {min} und {max} kHz liegen und ein vielfaches von 250kHz betragen!", + "2005": "Ungültige Landesauswahl!", "3001": "Nichts gelöscht!", "3002": "Konfiguration zurückgesetzt. Starte jetzt neu...", "4001": "@:apiresponse.2001", @@ -359,9 +360,14 @@ "CmtPaLevel": "CMT2300A Sendeleistung:", "NrfPaLevelHint": "Verwendet für HM-Wechselrichter. Stellen Sie sicher, dass Ihre Stromversorgung stabil genug ist, bevor Sie die Sendeleistung erhöhen.", "CmtPaLevelHint": "Verwendet für HMS/HMT-Wechselrichter. Stellen Sie sicher, dass Ihre Stromversorgung stabil genug ist, bevor Sie die Sendeleistung erhöhen.", + "CmtCountry": "Region/Land:", + "CmtCountryHint": "Jedes Land hat unterschiedliche Frequenzzuteilungen.", + "country_0": "Europa ({min}MHz - {max}MHz)", + "country_1": "Nordamerika ({min}MHz - {max}MHz)", + "country_2": "Brasilien ({min}MHz - {max}MHz)", "CmtFrequency": "CMT2300A Frequenz:", "CmtFrequencyHint": "Stelle sicher, dass du nur Frequenzen verwendet werden welche im entsprechenden Land erlaubt sind! Nach einer Frequenzänderung kann es bis zu 15min dauern bis eine Verbindung hergestellt wird.", - "CmtFrequencyWarning": "Die ausgewählte Frequenz befindet außerhalb des in der EU zugelassenen Bereiches. Vergewissere dich, dass mit dieser Auswahl keine lokalen Regularien verletzt werden.", + "CmtFrequencyWarning": "Die gewählte Frequenz liegt außerhalb des zulässigen Bereichs in der gewählten Region/dem Land. Vergewissere dich, dass mit dieser Auswahl keine lokalen Regularien verletzt werden.", "MHz": "{mhz} MHz", "dBm": "{dbm} dBm", "Min": "Minimum ({db} dBm)", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 31cff24a..0f5618e5 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -47,6 +47,7 @@ "2002": "Poll interval must be greater zero!", "2003": "Invalid power level setting!", "2004": "The frequency must be set between {min} and {max} kHz and must be a multiple of 250kHz!", + "2005": "Invalid country selection!", "3001": "Not deleted anything!", "3002": "Configuration resettet. Rebooting now...", "4001": "@:apiresponse.2001", @@ -359,9 +360,14 @@ "CmtPaLevel": "CMT2300A Transmitting power:", "NrfPaLevelHint": "Used for HM-Inverters. Make sure your power supply is stable enough before increasing the transmit power.", "CmtPaLevelHint": "Used for HMS/HMT-Inverters. Make sure your power supply is stable enough before increasing the transmit power.", + "CmtCountry": "Region/Country:", + "CmtCountryHint": "Each country has different frequency allocations.", + "country_0": "Europe ({min}MHz - {max}MHz)", + "country_1": "North America ({min}MHz - {max}MHz)", + "country_2": "Brazil ({min}MHz - {max}MHz)", "CmtFrequency": "CMT2300A Frequency:", "CmtFrequencyHint": "Make sure to only use frequencies that are allowed in the respective country! After a frequency change, it can take up to 15min until a connection is established.", - "CmtFrequencyWarning": "The selected frequency is outside the range allowed in the EU. Make sure that this selection does not violate any local regulations.", + "CmtFrequencyWarning": "The selected frequency is outside the allowed range in your selected region/country. Make sure that this selection does not violate any local regulations.", "MHz": "{mhz} MHz", "dBm": "{dbm} dBm", "Min": "Minimum ({db} dBm)", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 3404efd6..cd968c5d 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -47,6 +47,7 @@ "2002": "L'intervalle de sondage doit être supérieur à zéro !", "2003": "Réglage du niveau de puissance invalide !", "2004": "The frequency must be set between {min} and {max} kHz and must be a multiple of 250kHz!", + "2005": "Invalid country selection !", "3001": "Rien n'a été supprimé !", "3002": "Configuration réinitialisée. Redémarrage maintenant...", "4001": "@:apiresponse.2001", @@ -359,9 +360,14 @@ "CmtPaLevel": "CMT2300A Niveau de puissance d'émission", "NrfPaLevelHint": "Used for HM-Inverters. Assurez-vous que votre alimentation est suffisamment stable avant d'augmenter la puissance d'émission.", "CmtPaLevelHint": "Used for HMS/HMT-Inverters. Assurez-vous que votre alimentation est suffisamment stable avant d'augmenter la puissance d'émission.", + "CmtCountry": "Region/Country:", + "CmtCountryHint": "Each country has different frequency allocations.", + "country_0": "Europe ({min}MHz - {max}MHz)", + "country_1": "North America ({min}MHz - {max}MHz)", + "country_2": "Brazil ({min}MHz - {max}MHz)", "CmtFrequency": "CMT2300A Frequency:", "CmtFrequencyHint": "Make sure to only use frequencies that are allowed in the respective country! After a frequency change, it can take up to 15min until a connection is established.", - "CmtFrequencyWarning": "The selected frequency is outside the range allowed in the EU. Make sure that this selection does not violate any local regulations.", + "CmtFrequencyWarning": "The selected frequency is outside the allowed range in your selected region/country. Make sure that this selection does not violate any local regulations.", "MHz": "{mhz} MHz", "dBm": "{dbm} dBm", "Min": "Minimum ({db} dBm)", diff --git a/webapp/src/types/DtuConfig.ts b/webapp/src/types/DtuConfig.ts index 5ebc0afd..98dc36bc 100644 --- a/webapp/src/types/DtuConfig.ts +++ b/webapp/src/types/DtuConfig.ts @@ -1,3 +1,11 @@ +export interface CountryDef { + freq_default: number; + freq_min: number; + freq_max: number; + freq_legal_min: number; + freq_legal_max: number; +} + export interface DtuConfig { serial: number; pollinterval: number; @@ -6,7 +14,7 @@ export interface DtuConfig { cmt_enabled: boolean; cmt_palevel: number; cmt_frequency: number; - cmt_min_freq: number; - cmt_max_freq: number; + cmt_country: number; + country_def: Array; cmt_chan_width: number; } diff --git a/webapp/src/views/DtuAdminView.vue b/webapp/src/views/DtuAdminView.vue index b98c2ccc..7d882908 100644 --- a/webapp/src/views/DtuAdminView.vue +++ b/webapp/src/views/DtuAdminView.vue @@ -47,6 +47,20 @@ +
+ +
+ +
+
+
@@ -116,8 +130,25 @@ export default defineComponent({ cmtPaLevelText() { return this.$t("dtuadmin.dBm", { dbm: this.$n(this.dtuConfigList.cmt_palevel * 1) }); }, - cmtIsOutOfEu() { - return this.dtuConfigList.cmt_frequency < 863000000 || this.dtuConfigList.cmt_frequency > 870000000; + cmtMinFrequency() { + return this.dtuConfigList.country_def[this.dtuConfigList.cmt_country].freq_min; + }, + cmtMaxFrequency() { + return this.dtuConfigList.country_def[this.dtuConfigList.cmt_country].freq_max; + }, + cmtIsOutOfLegalRange() { + return this.dtuConfigList.cmt_frequency < this.dtuConfigList.country_def[this.dtuConfigList.cmt_country].freq_legal_min + || this.dtuConfigList.cmt_frequency > this.dtuConfigList.country_def[this.dtuConfigList.cmt_country].freq_legal_max; + } + }, + watch: { + 'dtuConfigList.cmt_country'(newValue, oldValue) { + // Don't do anything on initial load (then oldValue equals undefined) + if (oldValue != undefined) { + this.$nextTick(() => { + this.dtuConfigList.cmt_frequency = this.dtuConfigList.country_def[newValue].freq_default; + }); + } } }, methods: {