diff --git a/include/YaSolRWebsite.h b/include/YaSolRWebsite.h index 78597f75..ab185b90 100644 --- a/include/YaSolRWebsite.h +++ b/include/YaSolRWebsite.h @@ -6,6 +6,7 @@ #include <YaSolR.h> +#include <string> #include <unordered_map> namespace YaSolR { @@ -19,23 +20,164 @@ namespace YaSolR { void resetPID(); private: - void _boolConfig(Card& card, const char* key); - void _daysConfig(Card& card, const char* key); - void _floatConfig(Card& card, const char* key); - void _numConfig(Card& card, const char* key); - void _pinConfig(Card& card, const char* key); - void _passwordConfig(Card& card, const char* key); - void _sliderConfig(Card& card, const char* key); - void _percentageSlider(Card& card, const char* key); - void _textConfig(Card& card, const char* key); - - void _outputDimmerSlider(Card& card, Mycila::RouterOutput& output); - void _outputBypassSwitch(Card& card, Mycila::RouterOutput& output); - void _relaySwitch(Card& card, Mycila::RouterRelay& relay); - - void _pinout(Card& card, int32_t pin, std::unordered_map<int32_t, Card*>& pinout); - void _status(Card& card, const char* key, bool enabled, bool state = true, const char* err = ""); - void _temperature(Card& card, Mycila::DS18& sensor); - void _temperature(Card& card, Mycila::RouterOutput& output); + void _boolConfig(dash::SwitchCard& card, const char* key) { + card.onChange([key, &card, this](bool value) { + config.setBool(key, value); + card.setValue(config.getBool(key) ? 1 : 0); + dashboard.refresh(card); + dashboardInitTask.resume(); + }); + } + + template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true> + void _sliderConfig(dash::SliderCard<T>& card, const char* key) { + card.onChange([key, &card](const T& value) { + config.set(key, std::to_string(value)); + card.setValue(static_cast<T>(config.getInt(key))); + dashboard.refresh(card); + }); + } + + void _outputDimmerSlider(dash::SliderCard<float, 2>& card, Mycila::RouterOutput& output) { + card.onChange([&card, &output, this](float value) { + if (output.isDimmerEnabled()) { + output.setDimmerDutyCycle(value / 100); + } + card.setValue(output.getDimmerDutyCycle() * 100); + dashboard.refresh(card); + dashboardUpdateTask.requestEarlyRun(); + }); + } + + void _outputBypassSwitch(dash::SwitchCard& card, Mycila::RouterOutput& output) { + card.onChange([&card, &output, this](bool value) { + if (output.isBypassEnabled()) { + output.setBypass(value); + } + card.setValue(output.isBypassOn()); + dashboard.refresh(card); + dashboardUpdateTask.requestEarlyRun(); + }); + } + + void _relaySwitch(dash::SwitchCard& card, Mycila::RouterRelay& relay) { + card.onChange([&card, &relay, this](bool value) { + relay.tryRelayState(value); + card.setValue(relay.isOn()); + dashboard.refresh(card); + }); + } + +#ifdef APP_MODEL_PRO + void _daysConfig(dash::WeekCard<const char*>& card, const char* key) { + card.onChange([key, &card, this](const char* value) { + config.set(key, value[0] ? value : YASOLR_WEEK_DAYS_EMPTY); + card.setValue(value); + dashboard.refresh(card); + }); + } + + template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true> + void _numConfig(dash::TextInputCard<T>& card, const char* key) { + card.onChange([key, &card](const std::optional<T>& value) { + if (value.has_value()) { + config.set(key, std::to_string(value.value())); + } else { + config.unset(key); + } + card.setValue(static_cast<T>(config.getInt(key))); + dashboard.refresh(card); + }); + } + + template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = true> + void _numConfig(dash::DropdownCard<T>& card, const char* key) { + card.onChange([key, &card](const T& value) { + config.set(key, std::to_string(value)); + card.setValue(config.getInt(key)); + dashboard.refresh(card); + }); + } + + void _pinConfig(dash::FeedbackTextInputCard<int32_t>& card, const char* key) { + card.onChange([key, &card, this](const std::optional<int32_t> value) { + if (value.has_value()) { + config.set(key, std::to_string(value.value())); + } else { + config.unset(key); + } + card.setValue(config.getInt(key)); + initCards(); + dashboard.refresh(card); + }); + } + + void _passwordConfig(dash::PasswordCard& card, const char* key) { + card.onChange([key, &card, this](const std::optional<const char*>& value) { + if (value.has_value()) { + config.set(key, value.value()); + card.setValue(value.value()); // will be replaced by stars + } else { + config.unset(key); + card.removeValue(); + } + dashboard.refresh(card); + }); + } + + void _textConfig(dash::DropdownCard<const char*>& card, const char* key) { + card.onChange([key, &card](const char* value) { + config.set(key, value); + card.setValue(config.get(key)); + dashboard.refresh(card); + }); + } + + void _textConfig(dash::TextInputCard<const char*>& card, const char* key) { + card.onChange([key, &card](const std::optional<std::string>& value) { + if (value.has_value()) { + config.set(key, value.value()); + card.setValue(config.get(key)); + } else { + config.unset(key); + card.removeValue(); + } + dashboard.refresh(card); + }); + } + + void _pinout(dash::FeedbackTextInputCard<int32_t>& card, const char* key, std::unordered_map<int32_t, dash::FeedbackTextInputCard<int32_t>*>& pinout) { + int32_t pin = config.getInt(key); + card.setValue(pin); + if (pin == GPIO_NUM_NC) { + card.setFeedback("(" YASOLR_LBL_115 ")", dash::Status::IDLE); + } else if (pinout.find(pin) != pinout.end()) { + pinout[pin]->setFeedback("(" YASOLR_LBL_153 ")", dash::Status::DANGER); + card.setFeedback("(" YASOLR_LBL_153 ")", dash::Status::DANGER); + } else if (!GPIO_IS_VALID_GPIO(pin)) { + pinout[pin] = &card; + card.setFeedback("(" YASOLR_LBL_154 ")", dash::Status::DANGER); + } else if (!GPIO_IS_VALID_OUTPUT_GPIO(pin)) { + pinout[pin] = &card; + card.setFeedback("(" YASOLR_LBL_155 ")", dash::Status::WARNING); + } else { + pinout[pin] = &card; + card.setFeedback("(" YASOLR_LBL_156 ")", dash::Status::SUCCESS); + } + } + + void _status(dash::FeedbackSwitchCard& card, const char* key, bool enabled, bool active = true, const char* err = "") { + const bool configEnabled = config.getBool(key); + card.setValue(configEnabled); + if (!configEnabled) + card.setFeedback(YASOLR_LBL_115, dash::Status::IDLE); + else if (!enabled) + card.setFeedback(YASOLR_LBL_124, dash::Status::DANGER); + else if (!active) + card.setFeedback(err, dash::Status::WARNING); + else + card.setFeedback(YASOLR_LBL_130, dash::Status::SUCCESS); + } +#endif }; } // namespace YaSolR diff --git a/lib/ESPDASHPro b/lib/ESPDASHPro index 72144f70..9db15bda 160000 --- a/lib/ESPDASHPro +++ b/lib/ESPDASHPro @@ -1 +1 @@ -Subproject commit 72144f7077d9f47f4e2c121c3104462268f7f363 +Subproject commit 9db15bdaf005c5deced496eb4388e460572ebe0b diff --git a/platformio.ini b/platformio.ini index 2f0715ee..cdafc7e1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -166,7 +166,7 @@ build_flags = -D APP_MODEL_OSS lib_deps = mathieucarbou/MycilaWebSerial @ 7.0.1 ; ayushsharma82/ESP-DASH @ 4.0.8 - https://github.com/mathieucarbou/ayushsharma82-ESP-DASH#dev + https://github.com/mathieucarbou/ayushsharma82-ESP-DASH#dev-v5 lib_ignore = ESPDASHPro WebSerialPro diff --git a/src/Website.cpp b/src/Website.cpp index 11b78b56..babda5b9 100644 --- a/src/Website.cpp +++ b/src/Website.cpp @@ -7,12 +7,10 @@ #include <string> #include <unordered_map> -#define HIDDEN_PWD "********" - #ifdef APP_MODEL_OSS - #define LINE_CHART BAR_CHART - #define AREA_CHART BAR_CHART - #define ENERGY_CARD GENERIC_CARD + #define LineChart BarChart + #define AreaChart BarChart + #define EnergyCard GenericCard #endif #ifdef APP_MODEL_PRO @@ -22,92 +20,93 @@ static const ChartSize chartSize = {.xs = 12, .sm = 12, .md = 12, .lg = 12, .xl int _historyX[YASOLR_GRAPH_POINTS] = {0}; // statistics -Statistic _appName = Statistic(&dashboard, YASOLR_LBL_001); -Statistic _appModel = Statistic(&dashboard, YASOLR_LBL_002); -Statistic _appVersion = Statistic(&dashboard, YASOLR_LBL_003); -Statistic _appManufacturer = Statistic(&dashboard, YASOLR_LBL_004); - -Statistic _deviceBootCount = Statistic(&dashboard, YASOLR_LBL_005); -Statistic _deviceBootReason = Statistic(&dashboard, YASOLR_LBL_192); -Statistic _deviceCores = Statistic(&dashboard, YASOLR_LBL_006); -Statistic _deviceHeapTotal = Statistic(&dashboard, YASOLR_LBL_007); -Statistic _deviceHeapUsage = Statistic(&dashboard, YASOLR_LBL_008); -Statistic _deviceHeapUsed = Statistic(&dashboard, YASOLR_LBL_009); -Statistic _deviceID = Statistic(&dashboard, YASOLR_LBL_010); -Statistic _deviceModel = Statistic(&dashboard, YASOLR_LBL_011); -Statistic _deviceRev = Statistic(&dashboard, YASOLR_LBL_012); - -Statistic _firmwareBuildHash = Statistic(&dashboard, YASOLR_LBL_013); -Statistic _firmwareBuildTimestamp = Statistic(&dashboard, YASOLR_LBL_014); -Statistic _firmwareFilename = Statistic(&dashboard, YASOLR_LBL_015); - -Statistic _gridEnergy = Statistic(&dashboard, YASOLR_LBL_016); -Statistic _gridEnergyReturned = Statistic(&dashboard, YASOLR_LBL_017); -Statistic _gridFrequency = Statistic(&dashboard, YASOLR_LBL_018); - -Statistic _udpMessageRateBuffer = Statistic(&dashboard, YASOLR_LBL_157); - -Statistic _networkHostname = Statistic(&dashboard, YASOLR_LBL_019); -Statistic _networkInterface = Statistic(&dashboard, YASOLR_LBL_020); -Statistic _networkAPIP = Statistic(&dashboard, YASOLR_LBL_021); -Statistic _networkAPMAC = Statistic(&dashboard, YASOLR_LBL_022); -Statistic _networkEthIP = Statistic(&dashboard, YASOLR_LBL_023); -Statistic _networkEthMAC = Statistic(&dashboard, YASOLR_LBL_024); -Statistic _networkWiFiIP = Statistic(&dashboard, YASOLR_LBL_025); -Statistic _networkWiFiMAC = Statistic(&dashboard, YASOLR_LBL_026); -Statistic _networkWiFiSSID = Statistic(&dashboard, YASOLR_LBL_027); -Statistic _networkWiFiRSSI = Statistic(&dashboard, YASOLR_LBL_028); -Statistic _networkWiFiSignal = Statistic(&dashboard, YASOLR_LBL_029); - -Statistic _output1RelaySwitchCount = Statistic(&dashboard, YASOLR_LBL_030); -Statistic _output2RelaySwitchCount = Statistic(&dashboard, YASOLR_LBL_031); -Statistic _relay1SwitchCount = Statistic(&dashboard, YASOLR_LBL_032); -Statistic _relay2SwitchCount = Statistic(&dashboard, YASOLR_LBL_033); - -Statistic _time = Statistic(&dashboard, YASOLR_LBL_034); -Statistic _uptime = Statistic(&dashboard, YASOLR_LBL_035); +dash::StatisticValue<const char*> _appName(dashboard, YASOLR_LBL_001); +dash::StatisticValue<const char*> _appModel(dashboard, YASOLR_LBL_002); +dash::StatisticValue<const char*> _appVersion(dashboard, YASOLR_LBL_003); +dash::StatisticValue<const char*> _appManufacturer(dashboard, YASOLR_LBL_004); + +dash::StatisticValue<uint32_t> _deviceBootCount(dashboard, YASOLR_LBL_005); +dash::StatisticValue<const char*> _deviceBootReason(dashboard, YASOLR_LBL_192); +dash::StatisticValue<uint8_t> _deviceCores(dashboard, YASOLR_LBL_006); +dash::StatisticValue<size_t> _deviceHeapTotal(dashboard, YASOLR_LBL_007); +dash::StatisticValue<float, 2> _deviceHeapUsage(dashboard, YASOLR_LBL_008); +dash::StatisticValue<size_t> _deviceHeapUsed(dashboard, YASOLR_LBL_009); +dash::StatisticValue<const char*> _deviceID(dashboard, YASOLR_LBL_010); +dash::StatisticValue<const char*> _deviceModel(dashboard, YASOLR_LBL_011); +dash::StatisticValue<uint16_t> _deviceRev(dashboard, YASOLR_LBL_012); + +dash::StatisticValue<const char*> _firmwareBuildHash(dashboard, YASOLR_LBL_013); +dash::StatisticValue<const char*> _firmwareBuildTimestamp(dashboard, YASOLR_LBL_014); +dash::StatisticValue<const char*> _firmwareFilename(dashboard, YASOLR_LBL_015); + +dash::StatisticValue<float, 3> _gridEnergy(dashboard, YASOLR_LBL_016); +dash::StatisticValue<float, 3> _gridEnergyReturned(dashboard, YASOLR_LBL_017); +dash::StatisticValue<float, 0> _gridFrequency(dashboard, YASOLR_LBL_018); + +dash::StatisticValue<float, 2> _udpMessageRateBuffer(dashboard, YASOLR_LBL_157); + +dash::StatisticValue<const char*> _networkHostname(dashboard, YASOLR_LBL_019); +dash::StatisticValue<const char*> _networkInterface(dashboard, YASOLR_LBL_020); +dash::StatisticValue _networkAPIP(dashboard, YASOLR_LBL_021); +dash::StatisticValue _networkAPMAC(dashboard, YASOLR_LBL_022); +dash::StatisticValue _networkEthIP(dashboard, YASOLR_LBL_023); +dash::StatisticValue _networkEthMAC(dashboard, YASOLR_LBL_024); +dash::StatisticValue _networkWiFiIP(dashboard, YASOLR_LBL_025); +dash::StatisticValue _networkWiFiMAC(dashboard, YASOLR_LBL_026); +dash::StatisticValue _networkWiFiSSID(dashboard, YASOLR_LBL_027); +dash::StatisticValue<int8_t> _networkWiFiRSSI(dashboard, YASOLR_LBL_028); +dash::StatisticValue<int8_t> _networkWiFiSignal(dashboard, YASOLR_LBL_029); + +dash::StatisticValue<uint64_t> _output1RelaySwitchCount(dashboard, YASOLR_LBL_030); +dash::StatisticValue<uint64_t> _output2RelaySwitchCount(dashboard, YASOLR_LBL_031); +dash::StatisticValue<uint64_t> _relay1SwitchCount(dashboard, YASOLR_LBL_032); +dash::StatisticValue<uint64_t> _relay2SwitchCount(dashboard, YASOLR_LBL_033); + +dash::StatisticValue _time(dashboard, YASOLR_LBL_034); +dash::StatisticValue _uptime(dashboard, YASOLR_LBL_035); #ifdef APP_MODEL_TRIAL -Statistic _trialRemainingTime = Statistic(&dashboard, "Trial Remaining Time"); +dash::StatisticValue _trialRemainingTime(dashboard, "Trial Remaining Time"); #endif // home -Card _routerPower = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_036, "W"); -Card _routerApparentPower = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_037, "VA"); -Card _routerPowerFactor = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_038); -Card _routerTHDi = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_039, "%"); -Card _routerVoltage = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_040, "V"); -Card _routerCurrent = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_041, "A"); -Card _routerResistance = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_042, "Ω"); -Card _routerEnergy = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_043, "kWh"); -Card _gridPower = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_044, "W"); -Card _routerDS18State = Card(&dashboard, TEMPERATURE_CARD, YASOLR_LBL_045, "°C"); +dash::EnergyCard<float, 0> _routerPower(dashboard, YASOLR_LBL_036, "W"); +dash::EnergyCard<float, 0> _routerApparentPower(dashboard, YASOLR_LBL_037, "VA"); +dash::EnergyCard<float, 2> _routerPowerFactor(dashboard, YASOLR_LBL_038); +dash::EnergyCard<float, 2> _routerTHDi(dashboard, YASOLR_LBL_039, "%"); +dash::EnergyCard<float, 0> _routerVoltage(dashboard, YASOLR_LBL_040, "V"); +dash::EnergyCard<float, 0> _routerCurrent(dashboard, YASOLR_LBL_041, "A"); +dash::EnergyCard<float, 0> _routerResistance(dashboard, YASOLR_LBL_042, "Ω"); +dash::EnergyCard<float, 3> _routerEnergy(dashboard, YASOLR_LBL_043, "kWh"); +dash::EnergyCard<float, 0> _gridPower(dashboard, YASOLR_LBL_044, "W"); +dash::TemperatureCard<float, 2> _routerDS18State(dashboard, YASOLR_LBL_045); + #ifdef APP_MODEL_OSS -Card _relay1Switch = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_073); -Card _relay2Switch = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_076); - -Card _output1State = Card(&dashboard, STATUS_CARD, YASOLR_LBL_046, DASH_STATUS_IDLE); -Card _output1DS18State = Card(&dashboard, TEMPERATURE_CARD, YASOLR_LBL_046 ": " YASOLR_LBL_048, "°C"); -Card _output1DimmerSlider = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_046 ": " YASOLR_LBL_050, "%", 0.0f, 100.0f, 0.01f); -Card _output1Bypass = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_046 ": " YASOLR_LBL_051); - -Card _output2State = Card(&dashboard, STATUS_CARD, YASOLR_LBL_070, DASH_STATUS_IDLE); -Card _output2DS18State = Card(&dashboard, TEMPERATURE_CARD, YASOLR_LBL_070 ": " YASOLR_LBL_048, "°C"); -Card _output2DimmerSlider = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_070 ": " YASOLR_LBL_050, "%", 0.0f, 100.0f, 0.01f); -Card _output2Bypass = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_070 ": " YASOLR_LBL_051); +dash::SwitchCard _relay1Switch(dashboard, YASOLR_LBL_073); +dash::SwitchCard _relay2Switch(dashboard, YASOLR_LBL_076); + +dash::FeedbackCard<const char*> _output1State(dashboard, YASOLR_LBL_046); +dash::TemperatureCard<float, 2> _output1DS18State(dashboard, YASOLR_LBL_046 ": " YASOLR_LBL_048); +dash::SliderCard<float, 2> _output1DimmerSlider(dashboard, YASOLR_LBL_046 ": " YASOLR_LBL_050, 0.0f, 100.0f, 0.01f, "%"); +dash::SwitchCard _output1Bypass(dashboard, YASOLR_LBL_046 ": " YASOLR_LBL_051); + +dash::FeedbackCard<const char*> _output2State(dashboard, YASOLR_LBL_070); +dash::TemperatureCard<float, 2> _output2DS18State(dashboard, YASOLR_LBL_070 ": " YASOLR_LBL_048); +dash::SliderCard<float, 2> _output2DimmerSlider(dashboard, YASOLR_LBL_070 ": " YASOLR_LBL_050, 0.0f, 100.0f, 0.01f, "%"); +dash::SwitchCard _output2Bypass(dashboard, YASOLR_LBL_070 ": " YASOLR_LBL_051); #endif int _gridPowerHistoryY[YASOLR_GRAPH_POINTS] = {0}; int _routedPowerHistoryY[YASOLR_GRAPH_POINTS] = {0}; int _routerTHDiHistoryY[YASOLR_GRAPH_POINTS] = {0}; -Chart _gridPowerHistory = Chart(&dashboard, LINE_CHART, YASOLR_LBL_044 " (W)"); -Chart _routedPowerHistory = Chart(&dashboard, AREA_CHART, YASOLR_LBL_036 " (W)"); -Chart _routerTHDiHistory = Chart(&dashboard, BAR_CHART, YASOLR_LBL_039 " (%)"); +dash::LineChart<int, int> _gridPowerHistory(dashboard, YASOLR_LBL_044 " (W)"); +dash::AreaChart<int, int> _routedPowerHistory(dashboard, YASOLR_LBL_036 " (W)"); +dash::BarChart<int, int> _routerTHDiHistory(dashboard, YASOLR_LBL_039 " (%)"); #ifdef APP_MODEL_OSS -Card _output1PZEMSync = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_147); -Card _output2PZEMSync = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_148); -Card _resistanceCalibration = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_186); +dash::SwitchCard _output1PZEMSync(dashboard, YASOLR_LBL_147); +dash::SwitchCard _output2PZEMSync(dashboard, YASOLR_LBL_148); +dash::SwitchCard _resistanceCalibration(dashboard, YASOLR_LBL_186); #endif #ifdef APP_MODEL_PRO @@ -115,175 +114,175 @@ Card _resistanceCalibration = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_186); // https://en.wikipedia.org/wiki/List_of_Unicode_characters#Miscellaneous_Symbols // https://en.wikipedia.org/wiki/List_of_Unicode_characters#Dingbats -Tab _output1Tab = Tab(&dashboard, "\u2600 " YASOLR_LBL_046); -Card _output1State = Card(&dashboard, STATUS_CARD, YASOLR_LBL_047, DASH_STATUS_IDLE); -Card _output1DS18State = Card(&dashboard, TEMPERATURE_CARD, YASOLR_LBL_048, "°C"); -Card _output1DimmerSlider = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_050, "%", 0.0f, 100.0f, 0.01f); -Card _output1DimmerSliderRO = Card(&dashboard, PROGRESS_CARD, YASOLR_LBL_050, "%", 0.0f, 100.0f, 0.01f); -Card _output1Bypass = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_051); -Card _output1BypassRO = Card(&dashboard, STATUS_CARD, YASOLR_LBL_051); -Card _output1Power = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_052, "W"); -Card _output1ApparentPower = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_053, "VA"); -Card _output1PowerFactor = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_054); -Card _output1THDi = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_055, "%"); -Card _output1Voltage = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_056, "V"); -Card _output1Current = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_057, "A"); -Card _output1Resistance = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_058, "Ω"); -Card _output1Energy = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_059, "kWh"); -Card _output1DimmerDutyLimiter = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_062, "%", 0, 100, 1); -Card _output1DimmerTempLimiter = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_063, "°C"); -Card _output1DimmerAuto = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_060); -Card _output1DimmerReservedExcess = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_061, "%", 0, 100, 1); -Card _output1BypassAuto = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_064); -Card _output1AutoStartTemp = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_065, "°C"); -Card _output1AutoStoptTemp = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_066, "°C"); -Card _output1AutoStartTime = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_067); -Card _output1AutoStoptTime = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_068); -Card _output1AutoStartWDays = Card(&dashboard, WEEK_SELECTOR_CARD, YASOLR_LBL_069); - -Tab _output2Tab = Tab(&dashboard, "\u2600 " YASOLR_LBL_070); -Card _output2State = Card(&dashboard, STATUS_CARD, YASOLR_LBL_047, DASH_STATUS_IDLE); -Card _output2DS18State = Card(&dashboard, TEMPERATURE_CARD, YASOLR_LBL_048, "°C"); -Card _output2DimmerSlider = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_050, "%", 0.0f, 100.0f, 0.01f); -Card _output2DimmerSliderRO = Card(&dashboard, PROGRESS_CARD, YASOLR_LBL_050, "%", 0.0f, 100.0f, 0.01f); -Card _output2Bypass = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_051); -Card _output2BypassRO = Card(&dashboard, STATUS_CARD, YASOLR_LBL_051); -Card _output2Power = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_052, "W"); -Card _output2ApparentPower = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_053, "VA"); -Card _output2PowerFactor = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_054); -Card _output2THDi = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_055, "%"); -Card _output2Voltage = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_056, "V"); -Card _output2Current = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_057, "A"); -Card _output2Resistance = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_058, "Ω"); -Card _output2Energy = Card(&dashboard, ENERGY_CARD, YASOLR_LBL_059, "kWh"); -Card _output2DimmerDutyLimiter = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_062, "%", 0, 100, 1); -Card _output2DimmerTempLimiter = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_063, "°C"); -Card _output2DimmerAuto = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_060); -Card _output2DimmerReservedExcess = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_158, "%", 0, 100, 1); -Card _output2BypassAuto = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_064); -Card _output2AutoStartTemp = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_065); -Card _output2AutoStoptTemp = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_066); -Card _output2AutoStartTime = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_067); -Card _output2AutoStoptTime = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_068); -Card _output2AutoStartWDays = Card(&dashboard, WEEK_SELECTOR_CARD, YASOLR_LBL_069); - -Tab _relaysTab = Tab(&dashboard, "\u2600 " YASOLR_LBL_071); -Card _relay1Switch = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_073); -Card _relay1SwitchRO = Card(&dashboard, STATUS_CARD, YASOLR_LBL_074); -Card _relay2Switch = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_076); -Card _relay2SwitchRO = Card(&dashboard, STATUS_CARD, YASOLR_LBL_077); - -Tab _managementTab = Tab(&dashboard, "\u2764 " YASOLR_LBL_078); -Card _configBackup = Card(&dashboard, LINK_CARD, YASOLR_LBL_079); -Card _configRestore = Card(&dashboard, FILE_UPLOAD_CARD, YASOLR_LBL_080, ".txt"); -Card _restart = Card(&dashboard, PUSH_BUTTON_CARD, YASOLR_LBL_082); -Card _safeBoot = Card(&dashboard, PUSH_BUTTON_CARD, YASOLR_LBL_081); -Card _energyReset = Card(&dashboard, PUSH_BUTTON_CARD, YASOLR_LBL_085); -Card _reset = Card(&dashboard, PUSH_BUTTON_CARD, YASOLR_LBL_086); -Card _debugMode = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_083); -Card _consoleLink = Card(&dashboard, LINK_CARD, YASOLR_LBL_084); -Card _debugInfo = Card(&dashboard, LINK_CARD, YASOLR_LBL_178); - -Tab _networkConfigTab = Tab(&dashboard, "\u2728 " YASOLR_LBL_087); -Card _adminPwd = Card(&dashboard, PASSWORD_CARD, YASOLR_LBL_088); -Card _ntpServer = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_089); -Card _ntpTimezone = Card(&dashboard, ASYNC_DROPDOWN_CARD, YASOLR_LBL_090); -Card _ntpSync = Card(&dashboard, TIME_SYNC_CARD, YASOLR_LBL_091); -Card _wifiSSID = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_092); -Card _wifiPwd = Card(&dashboard, PASSWORD_CARD, YASOLR_LBL_093); -Card _staticIP = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_188); -Card _subnetMask = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_189); -Card _gateway = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_190); -Card _dnsServer = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_191); -Card _apMode = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_094); - -Tab _mqttConfigTab = Tab(&dashboard, "\u2728 " YASOLR_LBL_095); -Card _mqttServer = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_096); -Card _mqttPort = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_097); -Card _mqttUser = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_098); -Card _mqttPwd = Card(&dashboard, PASSWORD_CARD, YASOLR_LBL_099); -Card _mqttSecured = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_100); -Card _mqttServerCert = Card(&dashboard, FILE_UPLOAD_CARD, YASOLR_LBL_101, ".pem"); -Card _mqttServerCertDelete = Card(&dashboard, PUSH_BUTTON_CARD, YASOLR_LBL_049); -Card _mqttPublishInterval = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_102, "s", 1, 30, 1); -Card _mqttTopic = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_103); -Card _haDiscovery = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_104); -Card _haDiscoveryTopic = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_105); -Card _mqttGridVoltage = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_106); -Card _mqttGridPower = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_107); -Card _mqttTempO1 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_181); -Card _mqttTempO2 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_182); - -Tab _pinConfigTab = Tab(&dashboard, "\u21C6 " YASOLR_LBL_108); -Card _pinDisplayClock = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_111); -Card _pinDisplayData = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_112); -Card _pinJsyRX = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_116); -Card _pinJsyTX = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_117); -Card _pinLEDGreen = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_118); -Card _pinLEDRed = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_119); -Card _pinLEDYellow = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_120); -Card _pinDimmerO1 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_131); -Card _pinDS18O1 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_132); -Card _pinRelayO1 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_134); -Card _pinDimmerO2 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_135); -Card _pinDS18O2 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_136); -Card _pinRelayO2 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_138); -Card _pinPZEMRX = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_121); -Card _pinPZEMTX = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_122); -Card _pinRelay1 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_074); -Card _pinRelay2 = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_077); -Card _pinDS18Router = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_139); -Card _pinZCD = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_125); - -Tab _hardwareEnableTab = Tab(&dashboard, "\u2699 " YASOLR_LBL_126); -Card _display = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_127); -Card _jsy = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_128); -Card _led = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_129); -Card _mqtt = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_095); -Card _output1Dimmer = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_131); -Card _output1DS18 = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_132); -Card _output1PZEM = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_133); -Card _output1Relay = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_134); -Card _output2Dimmer = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_135); -Card _output2DS18 = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_136); -Card _output2PZEM = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_137); -Card _output2Relay = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_138); -Card _relay1 = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_074); -Card _relay2 = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_077); -Card _routerDS18 = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_139); -Card _zcd = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_125); - -Tab _hardwareConfigTab = Tab(&dashboard, "\u2699 " YASOLR_LBL_140); -Card _gridFreq = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_141); -Card _displaySpeed = Card(&dashboard, SLIDER_CARD, YASOLR_LBL_142, "s", 1, 10, 1); -Card _displayType = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_143); -Card _displayRotation = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_144); -Card _relay1Type = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_151); -Card _relay2Type = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_152); -Card _relay1Load = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_072); -Card _relay2Load = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_075); -Card _output1RelayType = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_149); -Card _output2RelayType = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_150); -Card _output1DimmerMapper = Card(&dashboard, RANGE_SLIDER_CARD, YASOLR_LBL_183, "%", 0, 100, 1); -Card _output2DimmerMapper = Card(&dashboard, RANGE_SLIDER_CARD, YASOLR_LBL_184, "%", 0, 100, 1); -Card _output1PZEMSync = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_147); -Card _output2PZEMSync = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_148); -Card _output1ResistanceInput = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_145); -Card _output2ResistanceInput = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_146); -Card _resistanceCalibration = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_186); - -Tab _pidTab = Tab(&dashboard, "\u2699 " YASOLR_LBL_159); -Card _pidView = Card(&dashboard, BUTTON_CARD, YASOLR_LBL_169); -Card _pidPMode = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_160); -Card _pidDMode = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_161); -Card _pidICMode = Card(&dashboard, DROPDOWN_CARD, YASOLR_LBL_162); -Card _pidSetpoint = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_163); -Card _pidKp = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_166); -Card _pidKi = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_167); -Card _pidKd = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_168); -Card _pidOutMin = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_164); -Card _pidOutMax = Card(&dashboard, TEXT_INPUT_CARD, YASOLR_LBL_165); -Card _pidReset = Card(&dashboard, PUSH_BUTTON_CARD, YASOLR_LBL_177); +dash::Tab _output1Tab(dashboard, "\u2600 " YASOLR_LBL_046); +dash::FeedbackCard<const char*> _output1State(dashboard, YASOLR_LBL_047); +dash::TemperatureCard<float, 2> _output1DS18State(dashboard, YASOLR_LBL_048); +dash::SliderCard<float, 2> _output1DimmerSlider(dashboard, YASOLR_LBL_050, 0.0f, 100.0f, 0.01f, "%"); +dash::ProgressCard<float, 2> _output1DimmerSliderRO(dashboard, YASOLR_LBL_050, 0.0f, 100.0f, "%"); +dash::SwitchCard _output1Bypass(dashboard, YASOLR_LBL_051); +dash::FeedbackCard<const char*> _output1BypassRO(dashboard, YASOLR_LBL_051); +dash::EnergyCard<float, 0> _output1Power(dashboard, YASOLR_LBL_052, "W"); +dash::EnergyCard<float, 0> _output1ApparentPower(dashboard, YASOLR_LBL_053, "VA"); +dash::EnergyCard<float, 2> _output1PowerFactor(dashboard, YASOLR_LBL_054); +dash::EnergyCard<float, 2> _output1THDi(dashboard, YASOLR_LBL_055, "%"); +dash::EnergyCard<float, 0> _output1Voltage(dashboard, YASOLR_LBL_056, "V"); +dash::EnergyCard<float, 0> _output1Current(dashboard, YASOLR_LBL_057, "A"); +dash::EnergyCard<float, 0> _output1Resistance(dashboard, YASOLR_LBL_058, "Ω"); +dash::EnergyCard<float, 3> _output1Energy(dashboard, YASOLR_LBL_059, "kWh"); +dash::PercentageSliderCard _output1DimmerDutyLimiter(dashboard, YASOLR_LBL_062); +dash::TextInputCard<uint8_t> _output1DimmerTempLimiter(dashboard, YASOLR_LBL_063); +dash::SwitchCard _output1DimmerAuto(dashboard, YASOLR_LBL_060); +dash::PercentageSliderCard _output1DimmerReservedExcess(dashboard, YASOLR_LBL_061); +dash::SwitchCard _output1BypassAuto(dashboard, YASOLR_LBL_064); +dash::TextInputCard<uint8_t> _output1AutoStartTemp(dashboard, YASOLR_LBL_065); +dash::TextInputCard<uint8_t> _output1AutoStoptTemp(dashboard, YASOLR_LBL_066); +dash::TextInputCard<const char*> _output1AutoStartTime(dashboard, YASOLR_LBL_067); +dash::TextInputCard<const char*> _output1AutoStoptTime(dashboard, YASOLR_LBL_068); +dash::WeekCard<const char*> _output1AutoStartWDays(dashboard, YASOLR_LBL_069); + +dash::Tab _output2Tab(dashboard, "\u2600 " YASOLR_LBL_070); +dash::FeedbackCard<const char*> _output2State(dashboard, YASOLR_LBL_047); +dash::TemperatureCard<float, 2> _output2DS18State(dashboard, YASOLR_LBL_048); +dash::SliderCard<float, 2> _output2DimmerSlider(dashboard, YASOLR_LBL_050, 0.0f, 100.0f, 0.01f, "%"); +dash::ProgressCard<float, 2> _output2DimmerSliderRO(dashboard, YASOLR_LBL_050, 0.0f, 100.0f, "%"); +dash::SwitchCard _output2Bypass(dashboard, YASOLR_LBL_051); +dash::FeedbackCard<const char*> _output2BypassRO(dashboard, YASOLR_LBL_051); +dash::EnergyCard<float, 0> _output2Power(dashboard, YASOLR_LBL_052, "W"); +dash::EnergyCard<float, 0> _output2ApparentPower(dashboard, YASOLR_LBL_053, "VA"); +dash::EnergyCard<float, 2> _output2PowerFactor(dashboard, YASOLR_LBL_054); +dash::EnergyCard<float, 2> _output2THDi(dashboard, YASOLR_LBL_055, "%"); +dash::EnergyCard<float, 0> _output2Voltage(dashboard, YASOLR_LBL_056, "V"); +dash::EnergyCard<float, 0> _output2Current(dashboard, YASOLR_LBL_057, "A"); +dash::EnergyCard<float, 0> _output2Resistance(dashboard, YASOLR_LBL_058, "Ω"); +dash::EnergyCard<float, 3> _output2Energy(dashboard, YASOLR_LBL_059, "kWh"); +dash::PercentageSliderCard _output2DimmerDutyLimiter(dashboard, YASOLR_LBL_062); +dash::TextInputCard<uint8_t> _output2DimmerTempLimiter(dashboard, YASOLR_LBL_063); +dash::SwitchCard _output2DimmerAuto(dashboard, YASOLR_LBL_060); +dash::PercentageSliderCard _output2DimmerReservedExcess(dashboard, YASOLR_LBL_158); +dash::SwitchCard _output2BypassAuto(dashboard, YASOLR_LBL_064); +dash::TextInputCard<uint8_t> _output2AutoStartTemp(dashboard, YASOLR_LBL_065); +dash::TextInputCard<uint8_t> _output2AutoStoptTemp(dashboard, YASOLR_LBL_066); +dash::TextInputCard<const char*> _output2AutoStartTime(dashboard, YASOLR_LBL_067); +dash::TextInputCard<const char*> _output2AutoStoptTime(dashboard, YASOLR_LBL_068); +dash::WeekCard<const char*> _output2AutoStartWDays(dashboard, YASOLR_LBL_069); + +dash::Tab _relaysTab(dashboard, "\u2600 " YASOLR_LBL_071); +dash::SwitchCard _relay1Switch(dashboard, YASOLR_LBL_073); +dash::FeedbackCard<const char*> _relay1SwitchRO(dashboard, YASOLR_LBL_074); +dash::SwitchCard _relay2Switch(dashboard, YASOLR_LBL_076); +dash::FeedbackCard<const char*> _relay2SwitchRO(dashboard, YASOLR_LBL_077); + +dash::Tab _managementTab(dashboard, "\u2764 " YASOLR_LBL_078); +dash::LinkCard<const char*> _configBackup(dashboard, YASOLR_LBL_079); +dash::FileUploadCard<const char*> _configRestore(dashboard, YASOLR_LBL_080, ".txt"); +dash::PushButtonCard _restart(dashboard, YASOLR_LBL_082); +dash::PushButtonCard _safeBoot(dashboard, YASOLR_LBL_081); +dash::PushButtonCard _energyReset(dashboard, YASOLR_LBL_085); +dash::PushButtonCard _reset(dashboard, YASOLR_LBL_086); +dash::SwitchCard _debugMode(dashboard, YASOLR_LBL_083); +dash::LinkCard<const char*> _consoleLink(dashboard, YASOLR_LBL_084); +dash::LinkCard<const char*> _debugInfo(dashboard, YASOLR_LBL_178); + +dash::Tab _networkConfigTab(dashboard, "\u2728 " YASOLR_LBL_087); +dash::PasswordCard _adminPwd(dashboard, YASOLR_LBL_088, YASOLR_HIDDEN_PWD); +dash::TextInputCard<const char*> _ntpServer(dashboard, YASOLR_LBL_089); +dash::AsyncDropdownCard<const char*> _ntpTimezone(dashboard, YASOLR_LBL_090, "/timezones"); +dash::TimeSyncCard _ntpSync(dashboard, YASOLR_LBL_091); +dash::TextInputCard<const char*> _wifiSSID(dashboard, YASOLR_LBL_092); +dash::PasswordCard _wifiPwd(dashboard, YASOLR_LBL_093, YASOLR_HIDDEN_PWD); +dash::TextInputCard<const char*> _staticIP(dashboard, YASOLR_LBL_188); +dash::TextInputCard<const char*> _subnetMask(dashboard, YASOLR_LBL_189); +dash::TextInputCard<const char*> _gateway(dashboard, YASOLR_LBL_190); +dash::TextInputCard<const char*> _dnsServer(dashboard, YASOLR_LBL_191); +dash::SwitchCard _apMode(dashboard, YASOLR_LBL_094); + +dash::Tab _mqttConfigTab(dashboard, "\u2728 " YASOLR_LBL_095); +dash::TextInputCard<const char*> _mqttServer(dashboard, YASOLR_LBL_096); +dash::TextInputCard<uint16_t> _mqttPort(dashboard, YASOLR_LBL_097); +dash::TextInputCard<const char*> _mqttUser(dashboard, YASOLR_LBL_098); +dash::PasswordCard _mqttPwd(dashboard, YASOLR_LBL_099, YASOLR_HIDDEN_PWD); +dash::SwitchCard _mqttSecured(dashboard, YASOLR_LBL_100); +dash::FileUploadCard _mqttServerCert(dashboard, YASOLR_LBL_101, ".pem"); +dash::PushButtonCard _mqttServerCertDelete(dashboard, YASOLR_LBL_049); +dash::SliderCard<uint8_t> _mqttPublishInterval(dashboard, YASOLR_LBL_102, 1, 30, 1, "s"); +dash::TextInputCard<const char*> _mqttTopic(dashboard, YASOLR_LBL_103); +dash::SwitchCard _haDiscovery(dashboard, YASOLR_LBL_104); +dash::TextInputCard<const char*> _haDiscoveryTopic(dashboard, YASOLR_LBL_105); +dash::TextInputCard<const char*> _mqttGridVoltage(dashboard, YASOLR_LBL_106); +dash::TextInputCard<const char*> _mqttGridPower(dashboard, YASOLR_LBL_107); +dash::TextInputCard<const char*> _mqttTempO1(dashboard, YASOLR_LBL_181); +dash::TextInputCard<const char*> _mqttTempO2(dashboard, YASOLR_LBL_182); + +dash::Tab _pinConfigTab(dashboard, "\u21C6 " YASOLR_LBL_108); +dash::FeedbackTextInputCard<int32_t> _pinDisplayClock(dashboard, YASOLR_LBL_111); +dash::FeedbackTextInputCard<int32_t> _pinDisplayData(dashboard, YASOLR_LBL_112); +dash::FeedbackTextInputCard<int32_t> _pinJsyRX(dashboard, YASOLR_LBL_116); +dash::FeedbackTextInputCard<int32_t> _pinJsyTX(dashboard, YASOLR_LBL_117); +dash::FeedbackTextInputCard<int32_t> _pinLEDGreen(dashboard, YASOLR_LBL_118); +dash::FeedbackTextInputCard<int32_t> _pinLEDRed(dashboard, YASOLR_LBL_119); +dash::FeedbackTextInputCard<int32_t> _pinLEDYellow(dashboard, YASOLR_LBL_120); +dash::FeedbackTextInputCard<int32_t> _pinDimmerO1(dashboard, YASOLR_LBL_131); +dash::FeedbackTextInputCard<int32_t> _pinDS18O1(dashboard, YASOLR_LBL_132); +dash::FeedbackTextInputCard<int32_t> _pinRelayO1(dashboard, YASOLR_LBL_134); +dash::FeedbackTextInputCard<int32_t> _pinDimmerO2(dashboard, YASOLR_LBL_135); +dash::FeedbackTextInputCard<int32_t> _pinDS18O2(dashboard, YASOLR_LBL_136); +dash::FeedbackTextInputCard<int32_t> _pinRelayO2(dashboard, YASOLR_LBL_138); +dash::FeedbackTextInputCard<int32_t> _pinPZEMRX(dashboard, YASOLR_LBL_121); +dash::FeedbackTextInputCard<int32_t> _pinPZEMTX(dashboard, YASOLR_LBL_122); +dash::FeedbackTextInputCard<int32_t> _pinRelay1(dashboard, YASOLR_LBL_074); +dash::FeedbackTextInputCard<int32_t> _pinRelay2(dashboard, YASOLR_LBL_077); +dash::FeedbackTextInputCard<int32_t> _pinDS18Router(dashboard, YASOLR_LBL_139); +dash::FeedbackTextInputCard<int32_t> _pinZCD(dashboard, YASOLR_LBL_125); + +dash::Tab _hardwareEnableTab(dashboard, "\u2699 " YASOLR_LBL_126); +dash::FeedbackSwitchCard _display(dashboard, YASOLR_LBL_127); +dash::FeedbackSwitchCard _jsy(dashboard, YASOLR_LBL_128); +dash::FeedbackSwitchCard _led(dashboard, YASOLR_LBL_129); +dash::FeedbackSwitchCard _mqtt(dashboard, YASOLR_LBL_095); +dash::FeedbackSwitchCard _output1Dimmer(dashboard, YASOLR_LBL_131); +dash::FeedbackSwitchCard _output1DS18(dashboard, YASOLR_LBL_132); +dash::FeedbackSwitchCard _output1PZEM(dashboard, YASOLR_LBL_133); +dash::FeedbackSwitchCard _output1Relay(dashboard, YASOLR_LBL_134); +dash::FeedbackSwitchCard _output2Dimmer(dashboard, YASOLR_LBL_135); +dash::FeedbackSwitchCard _output2DS18(dashboard, YASOLR_LBL_136); +dash::FeedbackSwitchCard _output2PZEM(dashboard, YASOLR_LBL_137); +dash::FeedbackSwitchCard _output2Relay(dashboard, YASOLR_LBL_138); +dash::FeedbackSwitchCard _relay1(dashboard, YASOLR_LBL_074); +dash::FeedbackSwitchCard _relay2(dashboard, YASOLR_LBL_077); +dash::FeedbackSwitchCard _routerDS18(dashboard, YASOLR_LBL_139); +dash::FeedbackSwitchCard _zcd(dashboard, YASOLR_LBL_125); + +dash::Tab _hardwareConfigTab(dashboard, "\u2699 " YASOLR_LBL_140); +dash::DropdownCard<const char*> _gridFreq(dashboard, YASOLR_LBL_141, "Auto-detect,50 Hz,60 Hz"); +dash::SliderCard<uint8_t> _displaySpeed(dashboard, YASOLR_LBL_142, 1, 10, 1, "s"); +dash::DropdownCard<const char*> _displayType(dashboard, YASOLR_LBL_143, "SH1106,SH1107,SSD1306"); +dash::DropdownCard<uint16_t> _displayRotation(dashboard, YASOLR_LBL_144, "0,90,180,270"); +dash::DropdownCard<const char*> _relay1Type(dashboard, YASOLR_LBL_151, "NO,NC"); +dash::DropdownCard<const char*> _relay2Type(dashboard, YASOLR_LBL_152, "NO,NC"); +dash::TextInputCard<uint16_t> _relay1Load(dashboard, YASOLR_LBL_072); +dash::TextInputCard<uint16_t> _relay2Load(dashboard, YASOLR_LBL_075); +dash::DropdownCard<const char*> _output1RelayType(dashboard, YASOLR_LBL_149, "NO,NC"); +dash::DropdownCard<const char*> _output2RelayType(dashboard, YASOLR_LBL_150, "NO,NC"); +dash::RangeSliderCard<uint8_t> _output1DimmerMapper(dashboard, YASOLR_LBL_183, 0, 100, 1, "%"); +dash::RangeSliderCard<uint8_t> _output2DimmerMapper(dashboard, YASOLR_LBL_184, 0, 100, 1, "%"); +dash::SwitchCard _output1PZEMSync(dashboard, YASOLR_LBL_147); +dash::SwitchCard _output2PZEMSync(dashboard, YASOLR_LBL_148); +dash::FeedbackTextInputCard<float, 2> _output1ResistanceInput(dashboard, YASOLR_LBL_145); +dash::FeedbackTextInputCard<float, 2> _output2ResistanceInput(dashboard, YASOLR_LBL_146); +dash::SwitchCard _resistanceCalibration(dashboard, YASOLR_LBL_186); + +dash::Tab _pidTab(dashboard, "\u2699 " YASOLR_LBL_159); +dash::SwitchCard _pidView(dashboard, YASOLR_LBL_169); +dash::DropdownCard<const char*> _pidPMode(dashboard, YASOLR_LBL_160, YASOLR_PID_P_MODE_1 "," YASOLR_PID_P_MODE_2 "," YASOLR_PID_P_MODE_3); +dash::DropdownCard<const char*> _pidDMode(dashboard, YASOLR_LBL_161, YASOLR_PID_D_MODE_1 "," YASOLR_PID_D_MODE_2); +dash::DropdownCard<const char*> _pidICMode(dashboard, YASOLR_LBL_162, YASOLR_PID_IC_MODE_0 "," YASOLR_PID_IC_MODE_1 "," YASOLR_PID_IC_MODE_2); +dash::TextInputCard<int> _pidSetpoint(dashboard, YASOLR_LBL_163); +dash::TextInputCard<float, 4> _pidKp(dashboard, YASOLR_LBL_166); +dash::TextInputCard<float, 4> _pidKi(dashboard, YASOLR_LBL_167); +dash::TextInputCard<float, 4> _pidKd(dashboard, YASOLR_LBL_168); +dash::TextInputCard<int> _pidOutMin(dashboard, YASOLR_LBL_164); +dash::TextInputCard<int> _pidOutMax(dashboard, YASOLR_LBL_165); +dash::PushButtonCard _pidReset(dashboard, YASOLR_LBL_177); // input,output,error,pTerm,iTerm,dTerm,sum int _pidInputHistoryY[YASOLR_GRAPH_POINTS] = {0}; @@ -293,13 +292,13 @@ int _pidPTermHistoryY[YASOLR_GRAPH_POINTS] = {0}; int _pidITermHistoryY[YASOLR_GRAPH_POINTS] = {0}; int _pidDTermHistoryY[YASOLR_GRAPH_POINTS] = {0}; int _pidSumHistoryY[YASOLR_GRAPH_POINTS] = {0}; -Chart _pidInputHistory = Chart(&dashboard, LINE_CHART, YASOLR_LBL_170); -Chart _pidOutputHistory = Chart(&dashboard, LINE_CHART, YASOLR_LBL_171); -Chart _pidErrorHistory = Chart(&dashboard, LINE_CHART, YASOLR_LBL_172); -Chart _pidSumHistory = Chart(&dashboard, BAR_CHART, YASOLR_LBL_173); -Chart _pidPTermHistory = Chart(&dashboard, LINE_CHART, YASOLR_LBL_174); -Chart _pidITermHistory = Chart(&dashboard, LINE_CHART, YASOLR_LBL_175); -Chart _pidDTermHistory = Chart(&dashboard, LINE_CHART, YASOLR_LBL_176); +dash::LineChart<int, int> _pidInputHistory(dashboard, YASOLR_LBL_170); +dash::LineChart<int, int> _pidOutputHistory(dashboard, YASOLR_LBL_171); +dash::LineChart<int, int> _pidErrorHistory(dashboard, YASOLR_LBL_172); +dash::BarChart<int, int> _pidSumHistory(dashboard, YASOLR_LBL_173); +dash::LineChart<int, int> _pidPTermHistory(dashboard, YASOLR_LBL_174); +dash::LineChart<int, int> _pidITermHistory(dashboard, YASOLR_LBL_175); +dash::LineChart<int, int> _pidDTermHistory(dashboard, YASOLR_LBL_176); #endif void YaSolR::Website::initLayout() { @@ -310,9 +309,9 @@ void YaSolR::Website::initLayout() { // overview - _gridPowerHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _routedPowerHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _routerTHDiHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); + _gridPowerHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _routedPowerHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _routerTHDiHistory.setX(_historyX, YASOLR_GRAPH_POINTS); _outputBypassSwitch(_output1Bypass, output1); _outputDimmerSlider(_output1DimmerSlider, output1); @@ -323,19 +322,19 @@ void YaSolR::Website::initLayout() { _relaySwitch(_relay1Switch, routerRelay1); _relaySwitch(_relay2Switch, routerRelay2); - _output1PZEMSync.attachCallback([this](int32_t value) { + _output1PZEMSync.onChange([](bool value) { pzemO1PairingTask.resume(); - _output1PZEMSync.update(!pzemO1PairingTask.isPaused()); - dashboard.refreshCard(&_output1PZEMSync); + _output1PZEMSync.setValue(!pzemO1PairingTask.isPaused()); + dashboard.refresh(_output1PZEMSync); }); - _output2PZEMSync.attachCallback([this](int32_t value) { + _output2PZEMSync.onChange([](bool value) { pzemO2PairingTask.resume(); - _output2PZEMSync.update(!pzemO2PairingTask.isPaused()); - dashboard.refreshCard(&_output2PZEMSync); + _output2PZEMSync.setValue(!pzemO2PairingTask.isPaused()); + dashboard.refresh(_output2PZEMSync); }); - _resistanceCalibration.attachCallback([this](int32_t value) { + _resistanceCalibration.onChange([this](bool value) { config.set(KEY_ENABLE_OUTPUT1_AUTO_BYPASS, YASOLR_FALSE, false); config.set(KEY_ENABLE_OUTPUT1_AUTO_DIMMER, YASOLR_FALSE, false); config.set(KEY_OUTPUT1_DIMMER_LIMIT, "100", false); @@ -352,8 +351,8 @@ void YaSolR::Website::initLayout() { mqttPublishConfigTask.resume(); mqttPublishTask.requestEarlyRun(); - _resistanceCalibration.update(router.isCalibrationRunning()); - dashboard.refreshCard(&_resistanceCalibration); + _resistanceCalibration.setValue(router.isCalibrationRunning()); + dashboard.refresh(_resistanceCalibration); }); #ifdef APP_MODEL_PRO @@ -367,13 +366,13 @@ void YaSolR::Website::initLayout() { // PID - _pidInputHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _pidOutputHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _pidErrorHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _pidPTermHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _pidITermHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _pidDTermHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); - _pidSumHistory.updateX(_historyX, YASOLR_GRAPH_POINTS); + _pidInputHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _pidOutputHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _pidErrorHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _pidPTermHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _pidITermHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _pidDTermHistory.setX(_historyX, YASOLR_GRAPH_POINTS); + _pidSumHistory.setX(_historyX, YASOLR_GRAPH_POINTS); _pidInputHistory.setSize(chartSize); _pidOutputHistory.setSize(chartSize); @@ -385,33 +384,33 @@ void YaSolR::Website::initLayout() { // output 1 - _output1State.setTab(&_output1Tab); - _output1DS18State.setTab(&_output1Tab); - _output1DimmerSlider.setTab(&_output1Tab); - _output1DimmerSliderRO.setTab(&_output1Tab); - _output1Bypass.setTab(&_output1Tab); - _output1BypassRO.setTab(&_output1Tab); - - _output1Power.setTab(&_output1Tab); - _output1PowerFactor.setTab(&_output1Tab); - _output1THDi.setTab(&_output1Tab); - _output1Energy.setTab(&_output1Tab); - - _output1ApparentPower.setTab(&_output1Tab); - _output1Voltage.setTab(&_output1Tab); - _output1Current.setTab(&_output1Tab); - _output1Resistance.setTab(&_output1Tab); - - _output1BypassAuto.setTab(&_output1Tab); - _output1DimmerAuto.setTab(&_output1Tab); - _output1AutoStartTemp.setTab(&_output1Tab); - _output1AutoStartTime.setTab(&_output1Tab); - _output1AutoStartWDays.setTab(&_output1Tab); - _output1AutoStoptTemp.setTab(&_output1Tab); - _output1AutoStoptTime.setTab(&_output1Tab); - _output1DimmerReservedExcess.setTab(&_output1Tab); - _output1DimmerDutyLimiter.setTab(&_output1Tab); - _output1DimmerTempLimiter.setTab(&_output1Tab); + _output1State.setTab(_output1Tab); + _output1DS18State.setTab(_output1Tab); + _output1DimmerSlider.setTab(_output1Tab); + _output1DimmerSliderRO.setTab(_output1Tab); + _output1Bypass.setTab(_output1Tab); + _output1BypassRO.setTab(_output1Tab); + + _output1Power.setTab(_output1Tab); + _output1PowerFactor.setTab(_output1Tab); + _output1THDi.setTab(_output1Tab); + _output1Energy.setTab(_output1Tab); + + _output1ApparentPower.setTab(_output1Tab); + _output1Voltage.setTab(_output1Tab); + _output1Current.setTab(_output1Tab); + _output1Resistance.setTab(_output1Tab); + + _output1BypassAuto.setTab(_output1Tab); + _output1DimmerAuto.setTab(_output1Tab); + _output1AutoStartTemp.setTab(_output1Tab); + _output1AutoStartTime.setTab(_output1Tab); + _output1AutoStartWDays.setTab(_output1Tab); + _output1AutoStoptTemp.setTab(_output1Tab); + _output1AutoStoptTime.setTab(_output1Tab); + _output1DimmerReservedExcess.setTab(_output1Tab); + _output1DimmerDutyLimiter.setTab(_output1Tab); + _output1DimmerTempLimiter.setTab(_output1Tab); _boolConfig(_output1BypassAuto, KEY_ENABLE_OUTPUT1_AUTO_BYPASS); _boolConfig(_output1DimmerAuto, KEY_ENABLE_OUTPUT1_AUTO_DIMMER); @@ -419,40 +418,40 @@ void YaSolR::Website::initLayout() { _numConfig(_output1AutoStartTemp, KEY_OUTPUT1_TEMPERATURE_START); _numConfig(_output1AutoStoptTemp, KEY_OUTPUT1_TEMPERATURE_STOP); _numConfig(_output1DimmerTempLimiter, KEY_OUTPUT1_DIMMER_STOP_TEMP); - _percentageSlider(_output1DimmerDutyLimiter, KEY_OUTPUT1_DIMMER_LIMIT); - _percentageSlider(_output1DimmerReservedExcess, KEY_OUTPUT1_RESERVED_EXCESS); + _sliderConfig(_output1DimmerDutyLimiter, KEY_OUTPUT1_DIMMER_LIMIT); + _sliderConfig(_output1DimmerReservedExcess, KEY_OUTPUT1_RESERVED_EXCESS); _textConfig(_output1AutoStartTime, KEY_OUTPUT1_TIME_START); _textConfig(_output1AutoStoptTime, KEY_OUTPUT1_TIME_STOP); // output 2 - _output2State.setTab(&_output2Tab); - _output2DS18State.setTab(&_output2Tab); - _output2DimmerSlider.setTab(&_output2Tab); - _output2DimmerSliderRO.setTab(&_output2Tab); - _output2Bypass.setTab(&_output2Tab); - _output2BypassRO.setTab(&_output2Tab); - - _output2Power.setTab(&_output2Tab); - _output2PowerFactor.setTab(&_output2Tab); - _output2THDi.setTab(&_output2Tab); - _output2Energy.setTab(&_output2Tab); - - _output2ApparentPower.setTab(&_output2Tab); - _output2Voltage.setTab(&_output2Tab); - _output2Current.setTab(&_output2Tab); - _output2Resistance.setTab(&_output2Tab); - - _output2BypassAuto.setTab(&_output2Tab); - _output2DimmerAuto.setTab(&_output2Tab); - _output2AutoStartTemp.setTab(&_output2Tab); - _output2AutoStartTime.setTab(&_output2Tab); - _output2AutoStartWDays.setTab(&_output2Tab); - _output2AutoStoptTemp.setTab(&_output2Tab); - _output2AutoStoptTime.setTab(&_output2Tab); - _output2DimmerReservedExcess.setTab(&_output2Tab); - _output2DimmerDutyLimiter.setTab(&_output2Tab); - _output2DimmerTempLimiter.setTab(&_output2Tab); + _output2State.setTab(_output2Tab); + _output2DS18State.setTab(_output2Tab); + _output2DimmerSlider.setTab(_output2Tab); + _output2DimmerSliderRO.setTab(_output2Tab); + _output2Bypass.setTab(_output2Tab); + _output2BypassRO.setTab(_output2Tab); + + _output2Power.setTab(_output2Tab); + _output2PowerFactor.setTab(_output2Tab); + _output2THDi.setTab(_output2Tab); + _output2Energy.setTab(_output2Tab); + + _output2ApparentPower.setTab(_output2Tab); + _output2Voltage.setTab(_output2Tab); + _output2Current.setTab(_output2Tab); + _output2Resistance.setTab(_output2Tab); + + _output2BypassAuto.setTab(_output2Tab); + _output2DimmerAuto.setTab(_output2Tab); + _output2AutoStartTemp.setTab(_output2Tab); + _output2AutoStartTime.setTab(_output2Tab); + _output2AutoStartWDays.setTab(_output2Tab); + _output2AutoStoptTemp.setTab(_output2Tab); + _output2AutoStoptTime.setTab(_output2Tab); + _output2DimmerReservedExcess.setTab(_output2Tab); + _output2DimmerDutyLimiter.setTab(_output2Tab); + _output2DimmerTempLimiter.setTab(_output2Tab); _boolConfig(_output2BypassAuto, KEY_ENABLE_OUTPUT2_AUTO_BYPASS); _boolConfig(_output2DimmerAuto, KEY_ENABLE_OUTPUT2_AUTO_DIMMER); @@ -460,91 +459,92 @@ void YaSolR::Website::initLayout() { _numConfig(_output2AutoStartTemp, KEY_OUTPUT2_TEMPERATURE_START); _numConfig(_output2AutoStoptTemp, KEY_OUTPUT2_TEMPERATURE_STOP); _numConfig(_output2DimmerTempLimiter, KEY_OUTPUT2_DIMMER_STOP_TEMP); - _percentageSlider(_output2DimmerDutyLimiter, KEY_OUTPUT2_DIMMER_LIMIT); - _percentageSlider(_output2DimmerReservedExcess, KEY_OUTPUT2_RESERVED_EXCESS); + _sliderConfig(_output2DimmerDutyLimiter, KEY_OUTPUT2_DIMMER_LIMIT); + _sliderConfig(_output2DimmerReservedExcess, KEY_OUTPUT2_RESERVED_EXCESS); _textConfig(_output2AutoStartTime, KEY_OUTPUT2_TIME_START); _textConfig(_output2AutoStoptTime, KEY_OUTPUT2_TIME_STOP); // relays - _relay1Switch.setTab(&_relaysTab); - _relay1SwitchRO.setTab(&_relaysTab); - _relay2Switch.setTab(&_relaysTab); - _relay2SwitchRO.setTab(&_relaysTab); + _relay1Switch.setTab(_relaysTab); + _relay1SwitchRO.setTab(_relaysTab); + _relay2Switch.setTab(_relaysTab); + _relay2SwitchRO.setTab(_relaysTab); // management - _configBackup.setTab(&_managementTab); - _configRestore.setTab(&_managementTab); - _consoleLink.setTab(&_managementTab); - _debugInfo.setTab(&_managementTab); - _debugMode.setTab(&_managementTab); - _safeBoot.setTab(&_managementTab); - _reset.setTab(&_managementTab); - _restart.setTab(&_managementTab); - _energyReset.setTab(&_managementTab); + _configBackup.setTab(_managementTab); + _configRestore.setTab(_managementTab); + _consoleLink.setTab(_managementTab); + _debugInfo.setTab(_managementTab); + _debugMode.setTab(_managementTab); + _safeBoot.setTab(_managementTab); + _reset.setTab(_managementTab); + _restart.setTab(_managementTab); + _energyReset.setTab(_managementTab); _boolConfig(_debugMode, KEY_ENABLE_DEBUG); - _energyReset.attachCallback([]() { + _energyReset.onPush([]() { jsy.resetEnergy(); pzemO1.resetEnergy(); pzemO2.resetEnergy(); }); - _reset.attachCallback([]() { resetTask.resume(); }); - _restart.attachCallback([]() { restartTask.resume(); }); - _safeBoot.attachCallback([]() { safeBootTask.resume(); }); + _reset.onPush([]() { resetTask.resume(); }); + _restart.onPush([]() { restartTask.resume(); }); + _safeBoot.onPush([]() { safeBootTask.resume(); }); // network (config) - _adminPwd.setTab(&_networkConfigTab); - _apMode.setTab(&_networkConfigTab); - _ntpServer.setTab(&_networkConfigTab); - _ntpSync.setTab(&_networkConfigTab); - _ntpTimezone.setTab(&_networkConfigTab); - _wifiPwd.setTab(&_networkConfigTab); - _wifiSSID.setTab(&_networkConfigTab); - _staticIP.setTab(&_networkConfigTab); - _subnetMask.setTab(&_networkConfigTab); - _gateway.setTab(&_networkConfigTab); - _dnsServer.setTab(&_networkConfigTab); + _adminPwd.setTab(_networkConfigTab); + _apMode.setTab(_networkConfigTab); + _ntpServer.setTab(_networkConfigTab); + _ntpSync.setTab(_networkConfigTab); + _ntpTimezone.setTab(_networkConfigTab); + _wifiPwd.setTab(_networkConfigTab); + _wifiSSID.setTab(_networkConfigTab); + _staticIP.setTab(_networkConfigTab); + _subnetMask.setTab(_networkConfigTab); + _gateway.setTab(_networkConfigTab); + _dnsServer.setTab(_networkConfigTab); + + _ntpTimezone.onChange([](const char* value) { + config.set(KEY_NTP_TIMEZONE, value); + _ntpTimezone.setValue(value); + dashboard.refresh(_ntpTimezone); + }); _boolConfig(_apMode, KEY_ENABLE_AP_MODE); _passwordConfig(_adminPwd, KEY_ADMIN_PASSWORD); _passwordConfig(_wifiPwd, KEY_WIFI_PASSWORD); _textConfig(_ntpServer, KEY_NTP_SERVER); - _textConfig(_ntpTimezone, KEY_NTP_TIMEZONE); _textConfig(_wifiSSID, KEY_WIFI_SSID); _textConfig(_staticIP, KEY_NET_IP); _textConfig(_subnetMask, KEY_NET_SUBNET); _textConfig(_gateway, KEY_NET_GATEWAY); _textConfig(_dnsServer, KEY_NET_DNS); - _ntpSync.attachCallback([](const char* value) { - const size_t len = strlen(value); - timeval tv; - tv.tv_sec = std::stoul(std::string(value, len - 3)); - tv.tv_usec = atol(value + len - 3); + _ntpSync.onSync([](const timeval& tv) { Mycila::NTP.sync(tv); }); // mqtt (config) - _haDiscovery.setTab(&_mqttConfigTab); - _haDiscoveryTopic.setTab(&_mqttConfigTab); - _mqttGridPower.setTab(&_mqttConfigTab); - _mqttGridVoltage.setTab(&_mqttConfigTab); - _mqttPort.setTab(&_mqttConfigTab); - _mqttPublishInterval.setTab(&_mqttConfigTab); - _mqttPwd.setTab(&_mqttConfigTab); - _mqttSecured.setTab(&_mqttConfigTab); - _mqttServer.setTab(&_mqttConfigTab); - _mqttServerCert.setTab(&_mqttConfigTab); - _mqttServerCertDelete.setTab(&_mqttConfigTab); - _mqttTopic.setTab(&_mqttConfigTab); - _mqttUser.setTab(&_mqttConfigTab); - _mqttTempO1.setTab(&_mqttConfigTab); - _mqttTempO2.setTab(&_mqttConfigTab); + _haDiscovery.setTab(_mqttConfigTab); + _haDiscoveryTopic.setTab(_mqttConfigTab); + _mqttGridPower.setTab(_mqttConfigTab); + _mqttGridVoltage.setTab(_mqttConfigTab); + _mqttPort.setTab(_mqttConfigTab); + _mqttPublishInterval.setTab(_mqttConfigTab); + _mqttPwd.setTab(_mqttConfigTab); + _mqttSecured.setTab(_mqttConfigTab); + _mqttServer.setTab(_mqttConfigTab); + _mqttServerCert.setTab(_mqttConfigTab); + _mqttServerCertDelete.setTab(_mqttConfigTab); + _mqttTopic.setTab(_mqttConfigTab); + _mqttUser.setTab(_mqttConfigTab); + _mqttTempO1.setTab(_mqttConfigTab); + _mqttTempO2.setTab(_mqttConfigTab); _boolConfig(_haDiscovery, KEY_ENABLE_HA_DISCOVERY); _boolConfig(_mqttSecured, KEY_MQTT_SECURED); @@ -560,7 +560,7 @@ void YaSolR::Website::initLayout() { _textConfig(_mqttTopic, KEY_MQTT_TOPIC); _textConfig(_mqttUser, KEY_MQTT_USERNAME); - _mqttServerCertDelete.attachCallback([this]() { + _mqttServerCertDelete.onPush([this]() { if (LittleFS.exists(YASOLR_MQTT_SERVER_CERT_FILE) && LittleFS.remove(YASOLR_MQTT_SERVER_CERT_FILE)) { logger.warn(TAG, "MQTT server certificate deleted successfully!"); dashboardInitTask.resume(); @@ -569,25 +569,25 @@ void YaSolR::Website::initLayout() { // GPIO (configuration) - _pinDimmerO1.setTab(&_pinConfigTab); - _pinDimmerO2.setTab(&_pinConfigTab); - _pinDisplayClock.setTab(&_pinConfigTab); - _pinDisplayData.setTab(&_pinConfigTab); - _pinDS18O1.setTab(&_pinConfigTab); - _pinDS18O2.setTab(&_pinConfigTab); - _pinDS18Router.setTab(&_pinConfigTab); - _pinJsyRX.setTab(&_pinConfigTab); - _pinJsyTX.setTab(&_pinConfigTab); - _pinLEDGreen.setTab(&_pinConfigTab); - _pinLEDRed.setTab(&_pinConfigTab); - _pinLEDYellow.setTab(&_pinConfigTab); - _pinPZEMRX.setTab(&_pinConfigTab); - _pinPZEMTX.setTab(&_pinConfigTab); - _pinRelay1.setTab(&_pinConfigTab); - _pinRelay2.setTab(&_pinConfigTab); - _pinRelayO1.setTab(&_pinConfigTab); - _pinRelayO2.setTab(&_pinConfigTab); - _pinZCD.setTab(&_pinConfigTab); + _pinDimmerO1.setTab(_pinConfigTab); + _pinDimmerO2.setTab(_pinConfigTab); + _pinDisplayClock.setTab(_pinConfigTab); + _pinDisplayData.setTab(_pinConfigTab); + _pinDS18O1.setTab(_pinConfigTab); + _pinDS18O2.setTab(_pinConfigTab); + _pinDS18Router.setTab(_pinConfigTab); + _pinJsyRX.setTab(_pinConfigTab); + _pinJsyTX.setTab(_pinConfigTab); + _pinLEDGreen.setTab(_pinConfigTab); + _pinLEDRed.setTab(_pinConfigTab); + _pinLEDYellow.setTab(_pinConfigTab); + _pinPZEMRX.setTab(_pinConfigTab); + _pinPZEMTX.setTab(_pinConfigTab); + _pinRelay1.setTab(_pinConfigTab); + _pinRelay2.setTab(_pinConfigTab); + _pinRelayO1.setTab(_pinConfigTab); + _pinRelayO2.setTab(_pinConfigTab); + _pinZCD.setTab(_pinConfigTab); _pinConfig(_pinDimmerO1, KEY_PIN_OUTPUT1_DIMMER); _pinConfig(_pinDimmerO2, KEY_PIN_OUTPUT2_DIMMER); @@ -611,22 +611,22 @@ void YaSolR::Website::initLayout() { // Hardware - _display.setTab(&_hardwareEnableTab); - _jsy.setTab(&_hardwareEnableTab); - _led.setTab(&_hardwareEnableTab); - _mqtt.setTab(&_hardwareEnableTab); - _output1Dimmer.setTab(&_hardwareEnableTab); - _output1PZEM.setTab(&_hardwareEnableTab); - _output1Relay.setTab(&_hardwareEnableTab); - _output1DS18.setTab(&_hardwareEnableTab); - _output2Dimmer.setTab(&_hardwareEnableTab); - _output2PZEM.setTab(&_hardwareEnableTab); - _output2Relay.setTab(&_hardwareEnableTab); - _output2DS18.setTab(&_hardwareEnableTab); - _relay1.setTab(&_hardwareEnableTab); - _relay2.setTab(&_hardwareEnableTab); - _routerDS18.setTab(&_hardwareEnableTab); - _zcd.setTab(&_hardwareEnableTab); + _display.setTab(_hardwareEnableTab); + _jsy.setTab(_hardwareEnableTab); + _led.setTab(_hardwareEnableTab); + _mqtt.setTab(_hardwareEnableTab); + _output1Dimmer.setTab(_hardwareEnableTab); + _output1PZEM.setTab(_hardwareEnableTab); + _output1Relay.setTab(_hardwareEnableTab); + _output1DS18.setTab(_hardwareEnableTab); + _output2Dimmer.setTab(_hardwareEnableTab); + _output2PZEM.setTab(_hardwareEnableTab); + _output2Relay.setTab(_hardwareEnableTab); + _output2DS18.setTab(_hardwareEnableTab); + _relay1.setTab(_hardwareEnableTab); + _relay2.setTab(_hardwareEnableTab); + _routerDS18.setTab(_hardwareEnableTab); + _zcd.setTab(_hardwareEnableTab); _boolConfig(_display, KEY_ENABLE_DISPLAY); _boolConfig(_jsy, KEY_ENABLE_JSY); @@ -647,93 +647,172 @@ void YaSolR::Website::initLayout() { // Hardware (config) - _gridFreq.setTab(&_hardwareConfigTab); - _displayRotation.setTab(&_hardwareConfigTab); - _displayType.setTab(&_hardwareConfigTab); - _displaySpeed.setTab(&_hardwareConfigTab); - _output1PZEMSync.setTab(&_hardwareConfigTab); - _output2PZEMSync.setTab(&_hardwareConfigTab); - _output1RelayType.setTab(&_hardwareConfigTab); - _output2RelayType.setTab(&_hardwareConfigTab); - _relay1Type.setTab(&_hardwareConfigTab); - _relay2Type.setTab(&_hardwareConfigTab); - _relay1Load.setTab(&_hardwareConfigTab); - _relay2Load.setTab(&_hardwareConfigTab); - _output1ResistanceInput.setTab(&_hardwareConfigTab); - _output2ResistanceInput.setTab(&_hardwareConfigTab); - _output1DimmerMapper.setTab(&_hardwareConfigTab); - _output2DimmerMapper.setTab(&_hardwareConfigTab); - _resistanceCalibration.setTab(&_hardwareConfigTab); - - _numConfig(_gridFreq, KEY_GRID_FREQUENCY); + _gridFreq.setTab(_hardwareConfigTab); + _displayRotation.setTab(_hardwareConfigTab); + _displayType.setTab(_hardwareConfigTab); + _displaySpeed.setTab(_hardwareConfigTab); + _output1PZEMSync.setTab(_hardwareConfigTab); + _output2PZEMSync.setTab(_hardwareConfigTab); + _output1RelayType.setTab(_hardwareConfigTab); + _output2RelayType.setTab(_hardwareConfigTab); + _relay1Type.setTab(_hardwareConfigTab); + _relay2Type.setTab(_hardwareConfigTab); + _relay1Load.setTab(_hardwareConfigTab); + _relay2Load.setTab(_hardwareConfigTab); + _output1ResistanceInput.setTab(_hardwareConfigTab); + _output2ResistanceInput.setTab(_hardwareConfigTab); + _output1DimmerMapper.setTab(_hardwareConfigTab); + _output2DimmerMapper.setTab(_hardwareConfigTab); + _resistanceCalibration.setTab(_hardwareConfigTab); + + _gridFreq.onChange([](const char* value) { + if (strcmp(value, "50 Hz") == 0) + config.set(KEY_GRID_FREQUENCY, "50"); + else if (strcmp(value, "60 Hz") == 0) + config.set(KEY_GRID_FREQUENCY, "60"); + else + config.unset(KEY_GRID_FREQUENCY); + _gridFreq.setValue(config.get(KEY_GRID_FREQUENCY)); + dashboard.refresh(_gridFreq); + }); + _numConfig(_displayRotation, KEY_DISPLAY_ROTATION); _numConfig(_relay1Load, KEY_RELAY1_LOAD); _numConfig(_relay2Load, KEY_RELAY2_LOAD); _textConfig(_displayType, KEY_DISPLAY_TYPE); - _floatConfig(_output1ResistanceInput, KEY_OUTPUT1_RESISTANCE); - _floatConfig(_output2ResistanceInput, KEY_OUTPUT2_RESISTANCE); _textConfig(_output1RelayType, KEY_OUTPUT1_RELAY_TYPE); _textConfig(_output2RelayType, KEY_OUTPUT2_RELAY_TYPE); _textConfig(_relay1Type, KEY_RELAY1_TYPE); _textConfig(_relay2Type, KEY_RELAY2_TYPE); _sliderConfig(_displaySpeed, KEY_DISPLAY_SPEED); - _output1DimmerMapper.attachCallback([this](const char* value) { - const char* comma = strchr(value, ','); - if (comma != nullptr) { - config.set(KEY_OUTPUT1_DIMMER_MIN, std::string(value, comma - value)); - config.set(KEY_OUTPUT1_DIMMER_MAX, comma + 1); - } - _output1DimmerMapper.update(value); - dashboard.refreshCard(&_output1DimmerMapper); + _output1ResistanceInput.onChange([](const std::optional<float> value) { + if (value.has_value()) + config.set(KEY_OUTPUT1_RESISTANCE, dash::to_string<float, 2>(value.value())); + else + config.unset(KEY_OUTPUT1_RESISTANCE); + _output1ResistanceInput.setValue(config.getFloat(KEY_OUTPUT1_RESISTANCE)); + dashboard.refresh(_output1ResistanceInput); }); - _output2DimmerMapper.attachCallback([this](const char* value) { - const char* comma = strchr(value, ','); - if (comma != nullptr) { - config.set(KEY_OUTPUT2_DIMMER_MIN, std::string(value, comma - value)); - config.set(KEY_OUTPUT2_DIMMER_MAX, comma + 1); - } - _output2DimmerMapper.update(value); - dashboard.refreshCard(&_output2DimmerMapper); + _output2ResistanceInput.onChange([](const std::optional<float> value) { + if (value.has_value()) + config.set(KEY_OUTPUT2_RESISTANCE, dash::to_string<float, 2>(value.value())); + else + config.unset(KEY_OUTPUT2_RESISTANCE); + _output2ResistanceInput.setValue(config.getFloat(KEY_OUTPUT2_RESISTANCE)); + dashboard.refresh(_output2ResistanceInput); + }); + + _output1DimmerMapper.onChange([](const dash::Range<uint8_t>& range) { + config.set(KEY_OUTPUT1_DIMMER_MIN, std::to_string(range.low())); + config.set(KEY_OUTPUT1_DIMMER_MAX, std::to_string(range.high())); + _output1DimmerMapper.setValue({static_cast<uint8_t>(config.getInt(KEY_OUTPUT1_DIMMER_MIN)), + static_cast<uint8_t>(config.getInt(KEY_OUTPUT1_DIMMER_MAX))}); + dashboard.refresh(_output1DimmerMapper); + }); + + _output2DimmerMapper.onChange([](const dash::Range<uint8_t>& range) { + config.set(KEY_OUTPUT2_DIMMER_MIN, std::to_string(range.low())); + config.set(KEY_OUTPUT2_DIMMER_MAX, std::to_string(range.high())); + _output2DimmerMapper.setValue({static_cast<uint8_t>(config.getInt(KEY_OUTPUT2_DIMMER_MIN)), + static_cast<uint8_t>(config.getInt(KEY_OUTPUT2_DIMMER_MAX))}); + dashboard.refresh(_output2DimmerMapper); }); // PID - _pidView.setTab(&_pidTab); - _pidPMode.setTab(&_pidTab); - _pidDMode.setTab(&_pidTab); - _pidICMode.setTab(&_pidTab); - _pidSetpoint.setTab(&_pidTab); - _pidKp.setTab(&_pidTab); - _pidKi.setTab(&_pidTab); - _pidKd.setTab(&_pidTab); - _pidOutMin.setTab(&_pidTab); - _pidOutMax.setTab(&_pidTab); - - _pidInputHistory.setTab(&_pidTab); - _pidOutputHistory.setTab(&_pidTab); - _pidErrorHistory.setTab(&_pidTab); - _pidSumHistory.setTab(&_pidTab); - _pidPTermHistory.setTab(&_pidTab); - _pidITermHistory.setTab(&_pidTab); - _pidDTermHistory.setTab(&_pidTab); - _pidReset.setTab(&_pidTab); - - _pidReset.attachCallback([this]() { + _pidView.setTab(_pidTab); + _pidPMode.setTab(_pidTab); + _pidDMode.setTab(_pidTab); + _pidICMode.setTab(_pidTab); + _pidSetpoint.setTab(_pidTab); + _pidKp.setTab(_pidTab); + _pidKi.setTab(_pidTab); + _pidKd.setTab(_pidTab); + _pidOutMin.setTab(_pidTab); + _pidOutMax.setTab(_pidTab); + + _pidInputHistory.setTab(_pidTab); + _pidOutputHistory.setTab(_pidTab); + _pidErrorHistory.setTab(_pidTab); + _pidSumHistory.setTab(_pidTab); + _pidPTermHistory.setTab(_pidTab); + _pidITermHistory.setTab(_pidTab); + _pidDTermHistory.setTab(_pidTab); + _pidReset.setTab(_pidTab); + + _pidReset.onPush([this]() { resetPID(); updatePID(); }); + _pidPMode.onChange([](const char* value) { + if (strcmp(value, YASOLR_PID_P_MODE_1) == 0) + config.set(KEY_PID_P_MODE, "1"); + else if (strcmp(value, YASOLR_PID_P_MODE_2) == 0) + config.set(KEY_PID_P_MODE, "2"); + else if (strcmp(value, YASOLR_PID_P_MODE_3) == 0) + config.set(KEY_PID_P_MODE, "3"); + else + config.unset(KEY_PID_P_MODE); + _pidPMode.setValue(config.get(KEY_PID_P_MODE)); + dashboard.refresh(_pidPMode); + }); + + _pidDMode.onChange([](const char* value) { + if (strcmp(value, YASOLR_PID_D_MODE_1) == 0) + config.set(KEY_PID_D_MODE, "1"); + else if (strcmp(value, YASOLR_PID_D_MODE_2) == 0) + config.set(KEY_PID_D_MODE, "2"); + else + config.unset(KEY_PID_D_MODE); + _pidDMode.setValue(config.get(KEY_PID_D_MODE)); + dashboard.refresh(_pidDMode); + }); + + _pidICMode.onChange([](const char* value) { + if (strcmp(value, YASOLR_PID_IC_MODE_0) == 0) + config.set(KEY_PID_IC_MODE, "0"); + else if (strcmp(value, YASOLR_PID_IC_MODE_1) == 0) + config.set(KEY_PID_IC_MODE, "1"); + else if (strcmp(value, YASOLR_PID_IC_MODE_2) == 0) + config.set(KEY_PID_IC_MODE, "2"); + else + config.unset(KEY_PID_IC_MODE); + _pidICMode.setValue(config.get(KEY_PID_IC_MODE)); + dashboard.refresh(_pidICMode); + }); + _boolConfig(_pidView, KEY_ENABLE_PID_VIEW); - _numConfig(_pidPMode, KEY_PID_P_MODE); - _numConfig(_pidDMode, KEY_PID_D_MODE); - _numConfig(_pidICMode, KEY_PID_IC_MODE); _numConfig(_pidSetpoint, KEY_PID_SETPOINT); - _floatConfig(_pidKp, KEY_PID_KP); - _floatConfig(_pidKi, KEY_PID_KI); - _floatConfig(_pidKd, KEY_PID_KD); _numConfig(_pidOutMin, KEY_PID_OUT_MIN); _numConfig(_pidOutMax, KEY_PID_OUT_MAX); + + _pidKp.onChange([](const std::optional<float> value) { + if (value.has_value()) + config.set(KEY_PID_KP, dash::to_string<float, 4>(value.value())); + else + config.unset(KEY_PID_KP); + _pidKp.setValue(config.getFloat(KEY_PID_KP)); + dashboard.refresh(_pidKp); + }); + _pidKi.onChange([](const std::optional<float> value) { + if (value.has_value()) + config.set(KEY_PID_KI, dash::to_string<float, 4>(value.value())); + else + config.unset(KEY_PID_KI); + _pidKi.setValue(config.getFloat(KEY_PID_KI)); + dashboard.refresh(_pidKi); + }); + _pidKd.onChange([](const std::optional<float> value) { + if (value.has_value()) + config.set(KEY_PID_KD, dash::to_string<float, 4>(value.value())); + else + config.unset(KEY_PID_KD); + _pidKd.setValue(config.getFloat(KEY_PID_KD)); + dashboard.refresh(_pidKd); + }); + #endif } @@ -742,28 +821,34 @@ void YaSolR::Website::initCards() { // Statistics - _appManufacturer.set(Mycila::AppInfo.manufacturer); - _appModel.set(Mycila::AppInfo.model); - _appName.set(Mycila::AppInfo.name); - _appVersion.set(Mycila::AppInfo.version); - _deviceBootCount.set(std::to_string(Mycila::System::getBootCount())); - _deviceBootReason.set(Mycila::System::getLastRebootReason()); - _deviceCores.set(std::to_string(ESP.getChipCores())); - _deviceModel.set(ESP.getChipModel()); - _deviceRev.set(std::to_string(ESP.getChipRevision())); - _deviceID.set(Mycila::AppInfo.id); - _firmwareBuildHash.set(Mycila::AppInfo.buildHash); - _firmwareBuildTimestamp.set(Mycila::AppInfo.buildDate); - _firmwareFilename.set(Mycila::AppInfo.firmware); - _networkAPMAC.set(espConnect.getMACAddress(Mycila::ESPConnect::Mode::AP)); - _networkEthMAC.set(espConnect.getMACAddress(Mycila::ESPConnect::Mode::ETH).empty() ? std::string("N/A") : espConnect.getMACAddress(Mycila::ESPConnect::Mode::ETH)); - _networkHostname.set(Mycila::AppInfo.defaultHostname); - _networkWiFiMAC.set(espConnect.getMACAddress(Mycila::ESPConnect::Mode::STA)); + Mycila::ESPConnect::Mode mode = espConnect.getMode(); + _appManufacturer.setValue(Mycila::AppInfo.manufacturer.c_str()); + _appModel.setValue(Mycila::AppInfo.model.c_str()); + _appName.setValue(Mycila::AppInfo.name.c_str()); + _appVersion.setValue(Mycila::AppInfo.version.c_str()); + _deviceBootCount.setValue(Mycila::System::getBootCount()); + _deviceBootReason.setValue(Mycila::System::getLastRebootReason()); + _deviceCores.setValue(ESP.getChipCores()); + _deviceID.setValue(Mycila::AppInfo.id.c_str()); + _deviceModel.setValue(ESP.getChipModel()); + _deviceRev.setValue(ESP.getChipRevision()); + _firmwareBuildHash.setValue(Mycila::AppInfo.buildHash.c_str()); + _firmwareBuildTimestamp.setValue(Mycila::AppInfo.buildDate.c_str()); + _firmwareFilename.setValue(Mycila::AppInfo.firmware.c_str()); + _networkAPIP.setValue(espConnect.getIPAddress(Mycila::ESPConnect::Mode::AP).toString().c_str()); + _networkAPMAC.setValue(espConnect.getMACAddress(Mycila::ESPConnect::Mode::AP)); + _networkEthIP.setValue(espConnect.getIPAddress(Mycila::ESPConnect::Mode::ETH).toString().c_str()); + _networkEthMAC.setValue(espConnect.getMACAddress(Mycila::ESPConnect::Mode::ETH).empty() ? std::string("N/A") : espConnect.getMACAddress(Mycila::ESPConnect::Mode::ETH)); + _networkHostname.setValue(Mycila::AppInfo.defaultHostname.c_str()); + _networkInterface.setValue(mode == Mycila::ESPConnect::Mode::AP ? "AP" : (mode == Mycila::ESPConnect::Mode::STA ? "WiFi" : (mode == Mycila::ESPConnect::Mode::ETH ? "Ethernet" : ""))); + _networkWiFiIP.setValue(espConnect.getIPAddress(Mycila::ESPConnect::Mode::STA).toString().c_str()); + _networkWiFiMAC.setValue(espConnect.getMACAddress(Mycila::ESPConnect::Mode::STA)); + _networkWiFiSSID.setValue(espConnect.getWiFiSSID()); #ifdef APP_MODEL_PRO const bool jsyEnabled = config.getBool(KEY_ENABLE_JSY); - // output 1 (control) + // output 1 const bool dimmer1Enabled = config.getBool(KEY_ENABLE_OUTPUT1_DIMMER); const bool output1RelayEnabled = config.getBool(KEY_ENABLE_OUTPUT1_RELAY); @@ -772,17 +857,18 @@ void YaSolR::Website::initCards() { const bool autoBypass1Activated = config.getBool(KEY_ENABLE_OUTPUT1_AUTO_BYPASS); const bool output1TempEnabled = config.getBool(KEY_ENABLE_OUTPUT1_DS18) || config.isEmpty(KEY_OUTPUT1_TEMPERATURE_MQTT_TOPIC); const bool pzem1Enabled = config.getBool(KEY_ENABLE_OUTPUT1_PZEM); - - _output1DimmerAuto.update(autoDimmer1Activated); - _output1DimmerReservedExcess.update(config.getInt(KEY_OUTPUT1_RESERVED_EXCESS)); - _output1DimmerDutyLimiter.update(config.getInt(KEY_OUTPUT1_DIMMER_LIMIT)); - _output1DimmerTempLimiter.update(config.get(KEY_OUTPUT1_DIMMER_STOP_TEMP)); - _output1BypassAuto.update(autoBypass1Activated); - _output1AutoStartWDays.update(config.get(KEY_OUTPUT1_DAYS)); - _output1AutoStartTemp.update(config.get(KEY_OUTPUT1_TEMPERATURE_START)); - _output1AutoStartTime.update(config.get(KEY_OUTPUT1_TIME_START)); - _output1AutoStoptTemp.update(config.get(KEY_OUTPUT1_TEMPERATURE_STOP)); - _output1AutoStoptTime.update(config.get(KEY_OUTPUT1_TIME_STOP)); + const char* output1Days = config.get(KEY_OUTPUT1_DAYS); + + _output1DimmerAuto.setValue(autoDimmer1Activated); + _output1DimmerReservedExcess.setValue(config.getInt(KEY_OUTPUT1_RESERVED_EXCESS)); + _output1DimmerDutyLimiter.setValue(config.getInt(KEY_OUTPUT1_DIMMER_LIMIT)); + _output1DimmerTempLimiter.setValue(config.getInt(KEY_OUTPUT1_DIMMER_STOP_TEMP)); + _output1BypassAuto.setValue(autoBypass1Activated); + _output1AutoStartWDays.setValue(strcmp(output1Days, YASOLR_WEEK_DAYS_EMPTY) == 0 ? "" : output1Days); + _output1AutoStartTemp.setValue(config.getInt(KEY_OUTPUT1_TEMPERATURE_START)); + _output1AutoStartTime.setValue(config.get(KEY_OUTPUT1_TIME_START)); + _output1AutoStoptTemp.setValue(config.getInt(KEY_OUTPUT1_TEMPERATURE_STOP)); + _output1AutoStoptTime.setValue(config.get(KEY_OUTPUT1_TIME_STOP)); _output1Tab.setDisplay(dimmer1Enabled || output1TempEnabled || output1RelayEnabled); _output1DimmerSlider.setDisplay(dimmer1Enabled && !autoDimmer1Activated); @@ -808,7 +894,7 @@ void YaSolR::Website::initCards() { _output1AutoStartTemp.setDisplay(bypass1Possible && autoBypass1Activated && output1TempEnabled); _output1AutoStoptTemp.setDisplay(bypass1Possible && autoBypass1Activated && output1TempEnabled); - // output 2 (control) + // output 2 const bool dimmer2Enabled = config.getBool(KEY_ENABLE_OUTPUT2_DIMMER); const bool output2RelayEnabled = config.getBool(KEY_ENABLE_OUTPUT2_RELAY); @@ -817,17 +903,18 @@ void YaSolR::Website::initCards() { const bool autoBypass2Activated = config.getBool(KEY_ENABLE_OUTPUT2_AUTO_BYPASS); const bool output2TempEnabled = config.getBool(KEY_ENABLE_OUTPUT2_DS18) || !config.isEmpty(KEY_OUTPUT2_TEMPERATURE_MQTT_TOPIC); const bool pzem2Enabled = config.getBool(KEY_ENABLE_OUTPUT2_PZEM); - - _output2DimmerAuto.update(autoDimmer2Activated); - _output2DimmerReservedExcess.update(config.getInt(KEY_OUTPUT2_RESERVED_EXCESS)); - _output2DimmerDutyLimiter.update(config.getInt(KEY_OUTPUT2_DIMMER_LIMIT)); - _output2DimmerTempLimiter.update(config.get(KEY_OUTPUT2_DIMMER_STOP_TEMP)); - _output2BypassAuto.update(autoBypass2Activated); - _output2AutoStartWDays.update(config.get(KEY_OUTPUT2_DAYS)); - _output2AutoStartTemp.update(config.get(KEY_OUTPUT2_TEMPERATURE_START)); - _output2AutoStartTime.update(config.get(KEY_OUTPUT2_TIME_START)); - _output2AutoStoptTemp.update(config.get(KEY_OUTPUT2_TEMPERATURE_STOP)); - _output2AutoStoptTime.update(config.get(KEY_OUTPUT2_TIME_STOP)); + const char* output2Days = config.get(KEY_OUTPUT2_DAYS); + + _output2DimmerAuto.setValue(autoDimmer2Activated); + _output2DimmerReservedExcess.setValue(config.getInt(KEY_OUTPUT2_RESERVED_EXCESS)); + _output2DimmerDutyLimiter.setValue(config.getInt(KEY_OUTPUT2_DIMMER_LIMIT)); + _output2DimmerTempLimiter.setValue(config.getInt(KEY_OUTPUT2_DIMMER_STOP_TEMP)); + _output2BypassAuto.setValue(autoBypass2Activated); + _output2AutoStartWDays.setValue(strcmp(output2Days, YASOLR_WEEK_DAYS_EMPTY) == 0 ? "" : output2Days); + _output2AutoStartTemp.setValue(config.getInt(KEY_OUTPUT2_TEMPERATURE_START)); + _output2AutoStartTime.setValue(config.get(KEY_OUTPUT2_TIME_START)); + _output2AutoStoptTemp.setValue(config.getInt(KEY_OUTPUT2_TEMPERATURE_STOP)); + _output2AutoStoptTime.setValue(config.get(KEY_OUTPUT2_TIME_STOP)); _output2Tab.setDisplay(dimmer2Enabled || output2TempEnabled || output2RelayEnabled); _output2DimmerSlider.setDisplay(dimmer2Enabled && !autoDimmer2Activated); @@ -853,10 +940,10 @@ void YaSolR::Website::initCards() { _output2AutoStartTemp.setDisplay(bypass2Possible && autoBypass2Activated && output2TempEnabled); _output2AutoStoptTemp.setDisplay(bypass2Possible && autoBypass2Activated && output2TempEnabled); - // relays (control) + // relays - const int load1 = config.getInt(KEY_RELAY1_LOAD); - const int load2 = config.getInt(KEY_RELAY2_LOAD); + const uint16_t load1 = config.getInt(KEY_RELAY1_LOAD); + const uint16_t load2 = config.getInt(KEY_RELAY2_LOAD); const bool relay1Enabled = config.getBool(KEY_ENABLE_RELAY1); const bool relay2Enabled = config.getBool(KEY_ENABLE_RELAY2); _relaysTab.setDisplay(relay1Enabled || relay2Enabled); @@ -867,43 +954,43 @@ void YaSolR::Website::initCards() { // management - _configBackup.update("/api/config/backup"); - _configRestore.update("/api/config/restore"); - _consoleLink.update("/console"); - _debugInfo.update("/api/debug"); - _debugMode.update(config.getBool(KEY_ENABLE_DEBUG)); + _configBackup.setValue("/api/config/backup"); + _configRestore.setValue("/api/config/restore"); + _consoleLink.setValue("/console"); + _debugInfo.setValue("/api/debug"); + _debugMode.setValue(config.getBool(KEY_ENABLE_DEBUG)); _energyReset.setDisplay(jsyEnabled || pzem1Enabled || pzem2Enabled); _debugInfo.setDisplay(config.getBool(KEY_ENABLE_DEBUG)); - // network (config) - - _adminPwd.update(config.isEmpty(KEY_ADMIN_PASSWORD) ? "" : HIDDEN_PWD); - _apMode.update(config.getBool(KEY_ENABLE_AP_MODE)); - _ntpServer.update(config.get(KEY_NTP_SERVER)); - _ntpTimezone.update(config.get(KEY_NTP_TIMEZONE), "/timezones"); - _wifiPwd.update(config.isEmpty(KEY_WIFI_PASSWORD) ? "" : HIDDEN_PWD); - _wifiSSID.update(config.get(KEY_WIFI_SSID)); - _staticIP.update(config.get(KEY_NET_IP)); - _subnetMask.update(config.get(KEY_NET_SUBNET)); - _gateway.update(config.get(KEY_NET_GATEWAY)); - _dnsServer.update(config.get(KEY_NET_DNS)); - - // mqtt (config) - - _haDiscovery.update(config.getBool(KEY_ENABLE_HA_DISCOVERY)); - _haDiscoveryTopic.update(config.get(KEY_HA_DISCOVERY_TOPIC)); - _mqttGridPower.update(config.get(KEY_GRID_POWER_MQTT_TOPIC)); - _mqttGridVoltage.update(config.get(KEY_GRID_VOLTAGE_MQTT_TOPIC)); - _mqttTempO1.update(config.get(KEY_OUTPUT1_TEMPERATURE_MQTT_TOPIC)); - _mqttTempO2.update(config.get(KEY_OUTPUT2_TEMPERATURE_MQTT_TOPIC)); - _mqttPort.update(config.get(KEY_MQTT_PORT)); - _mqttPublishInterval.update(config.get(KEY_MQTT_PUBLISH_INTERVAL)); - _mqttPwd.update(config.isEmpty(KEY_MQTT_PASSWORD) ? "" : HIDDEN_PWD); - _mqttSecured.update(config.getBool(KEY_MQTT_SECURED)); - _mqttServer.update(config.get(KEY_MQTT_SERVER)); - _mqttServerCert.update("/api/config/mqttServerCertificate"); - _mqttTopic.update(config.get(KEY_MQTT_TOPIC)); - _mqttUser.update(config.get(KEY_MQTT_USERNAME)); + // network + + _adminPwd.setValue(config.get(KEY_ADMIN_PASSWORD)); + _apMode.setValue(config.getBool(KEY_ENABLE_AP_MODE)); + _ntpServer.setValue(config.get(KEY_NTP_SERVER)); + _ntpTimezone.setValue(config.get(KEY_NTP_TIMEZONE)); + _wifiPwd.setValue(config.get(KEY_WIFI_PASSWORD)); + _wifiSSID.setValue(config.get(KEY_WIFI_SSID)); + _staticIP.setValue(config.get(KEY_NET_IP)); + _subnetMask.setValue(config.get(KEY_NET_SUBNET)); + _gateway.setValue(config.get(KEY_NET_GATEWAY)); + _dnsServer.setValue(config.get(KEY_NET_DNS)); + + // mqtt + + _haDiscovery.setValue(config.getBool(KEY_ENABLE_HA_DISCOVERY)); + _haDiscoveryTopic.setValue(config.get(KEY_HA_DISCOVERY_TOPIC)); + _mqttGridPower.setValue(config.get(KEY_GRID_POWER_MQTT_TOPIC)); + _mqttGridVoltage.setValue(config.get(KEY_GRID_VOLTAGE_MQTT_TOPIC)); + _mqttTempO1.setValue(config.get(KEY_OUTPUT1_TEMPERATURE_MQTT_TOPIC)); + _mqttTempO2.setValue(config.get(KEY_OUTPUT2_TEMPERATURE_MQTT_TOPIC)); + _mqttPort.setValue(config.getInt(KEY_MQTT_PORT)); + _mqttPublishInterval.setValue(config.getInt(KEY_MQTT_PUBLISH_INTERVAL)); + _mqttPwd.setValue(config.get(KEY_MQTT_PASSWORD)); + _mqttSecured.setValue(config.getBool(KEY_MQTT_SECURED)); + _mqttServer.setValue(config.get(KEY_MQTT_SERVER)); + _mqttServerCert.setValue("/api/config/mqttServerCertificate"); + _mqttTopic.setValue(config.get(KEY_MQTT_TOPIC)); + _mqttUser.setValue(config.get(KEY_MQTT_USERNAME)); const bool serverCertExists = LittleFS.exists(YASOLR_MQTT_SERVER_CERT_FILE); _mqttConfigTab.setDisplay(config.getBool(KEY_ENABLE_MQTT)); @@ -912,26 +999,26 @@ void YaSolR::Website::initCards() { // GPIO - std::unordered_map<int32_t, Card*> pinout = {}; - _pinout(_pinDimmerO1, config.getLong(KEY_PIN_OUTPUT1_DIMMER), pinout); - _pinout(_pinDimmerO2, config.getLong(KEY_PIN_OUTPUT2_DIMMER), pinout); - _pinout(_pinDisplayClock, config.getLong(KEY_PIN_DISPLAY_SCL), pinout); - _pinout(_pinDisplayData, config.getLong(KEY_PIN_DISPLAY_SDA), pinout); - _pinout(_pinDS18O1, config.getLong(KEY_PIN_OUTPUT1_DS18), pinout); - _pinout(_pinDS18O2, config.getLong(KEY_PIN_OUTPUT2_DS18), pinout); - _pinout(_pinDS18Router, config.getLong(KEY_PIN_ROUTER_DS18), pinout); - _pinout(_pinJsyRX, config.getLong(KEY_PIN_JSY_RX), pinout); - _pinout(_pinJsyTX, config.getLong(KEY_PIN_JSY_TX), pinout); - _pinout(_pinLEDGreen, config.getLong(KEY_PIN_LIGHTS_GREEN), pinout); - _pinout(_pinLEDRed, config.getLong(KEY_PIN_LIGHTS_RED), pinout); - _pinout(_pinLEDYellow, config.getLong(KEY_PIN_LIGHTS_YELLOW), pinout); - _pinout(_pinPZEMRX, config.getLong(KEY_PIN_PZEM_RX), pinout); - _pinout(_pinPZEMTX, config.getLong(KEY_PIN_PZEM_TX), pinout); - _pinout(_pinRelay1, config.getLong(KEY_PIN_RELAY1), pinout); - _pinout(_pinRelay2, config.getLong(KEY_PIN_RELAY2), pinout); - _pinout(_pinRelayO1, config.getLong(KEY_PIN_OUTPUT1_RELAY), pinout); - _pinout(_pinRelayO2, config.getLong(KEY_PIN_OUTPUT2_RELAY), pinout); - _pinout(_pinZCD, config.getLong(KEY_PIN_ZCD), pinout); + std::unordered_map<int32_t, dash::FeedbackTextInputCard<int32_t>*> pinout = {}; + _pinout(_pinDimmerO1, KEY_PIN_OUTPUT1_DIMMER, pinout); + _pinout(_pinDimmerO2, KEY_PIN_OUTPUT2_DIMMER, pinout); + _pinout(_pinDisplayClock, KEY_PIN_DISPLAY_SCL, pinout); + _pinout(_pinDisplayData, KEY_PIN_DISPLAY_SDA, pinout); + _pinout(_pinDS18O1, KEY_PIN_OUTPUT1_DS18, pinout); + _pinout(_pinDS18O2, KEY_PIN_OUTPUT2_DS18, pinout); + _pinout(_pinDS18Router, KEY_PIN_ROUTER_DS18, pinout); + _pinout(_pinJsyRX, KEY_PIN_JSY_RX, pinout); + _pinout(_pinJsyTX, KEY_PIN_JSY_TX, pinout); + _pinout(_pinLEDGreen, KEY_PIN_LIGHTS_GREEN, pinout); + _pinout(_pinLEDRed, KEY_PIN_LIGHTS_RED, pinout); + _pinout(_pinLEDYellow, KEY_PIN_LIGHTS_YELLOW, pinout); + _pinout(_pinPZEMRX, KEY_PIN_PZEM_RX, pinout); + _pinout(_pinPZEMTX, KEY_PIN_PZEM_TX, pinout); + _pinout(_pinRelay1, KEY_PIN_RELAY1, pinout); + _pinout(_pinRelay2, KEY_PIN_RELAY2, pinout); + _pinout(_pinRelayO1, KEY_PIN_OUTPUT1_RELAY, pinout); + _pinout(_pinRelayO2, KEY_PIN_OUTPUT2_RELAY, pinout); + _pinout(_pinZCD, KEY_PIN_ZCD, pinout); pinout.clear(); // Hardware @@ -943,34 +1030,37 @@ void YaSolR::Website::initCards() { _status(_relay1, KEY_ENABLE_RELAY1, relay1.isEnabled()); _status(_relay2, KEY_ENABLE_RELAY2, relay2.isEnabled()); - // Hardware (config) + // Hardware Config - switch (config.getLong(KEY_GRID_FREQUENCY)) { + switch (config.getInt(KEY_GRID_FREQUENCY)) { case 50: - _gridFreq.update("50 Hz", "Auto-detect,50 Hz,60 Hz"); + _gridFreq.setValue("50 Hz"); break; case 60: - _gridFreq.update("60 Hz", "Auto-detect,50 Hz,60 Hz"); + _gridFreq.setValue("60 Hz"); break; default: - _gridFreq.update("Auto-detect", "Auto-detect,50 Hz,60 Hz"); + _gridFreq.setValue("Auto-detect"); break; } - _displayType.update(config.get(KEY_DISPLAY_TYPE), "SH1106,SH1107,SSD1306"); - _displaySpeed.update(config.getInt(KEY_DISPLAY_SPEED)); - _displayRotation.update(config.getString(KEY_DISPLAY_ROTATION) + "°", "0°,90°,180°,270°"); - _output1RelayType.update(config.get(KEY_OUTPUT1_RELAY_TYPE), "NO,NC"); - _output2RelayType.update(config.get(KEY_OUTPUT2_RELAY_TYPE), "NO,NC"); - _relay1Type.update(config.get(KEY_RELAY1_TYPE), "NO,NC"); - _relay2Type.update(config.get(KEY_RELAY2_TYPE), "NO,NC"); - _relay1Load.update(load1); - _relay2Load.update(load2); - _output1ResistanceInput.update(config.get(KEY_OUTPUT1_RESISTANCE), config.getFloat(KEY_OUTPUT1_RESISTANCE) == 0 ? DASH_STATUS_DANGER : DASH_STATUS_SUCCESS); - _output2ResistanceInput.update(config.get(KEY_OUTPUT2_RESISTANCE), config.getFloat(KEY_OUTPUT2_RESISTANCE) == 0 ? DASH_STATUS_DANGER : DASH_STATUS_SUCCESS); - _output1DimmerMapper.update(config.getString(KEY_OUTPUT1_DIMMER_MIN) + "," + config.get(KEY_OUTPUT1_DIMMER_MAX)); - _output2DimmerMapper.update(config.getString(KEY_OUTPUT2_DIMMER_MIN) + "," + config.get(KEY_OUTPUT2_DIMMER_MAX)); - + _displayType.setValue(config.get(KEY_DISPLAY_TYPE)); + _displaySpeed.setValue(config.getInt(KEY_DISPLAY_SPEED)); + _displayRotation.setValue(config.getInt(KEY_DISPLAY_ROTATION)); + _output1RelayType.setValue(config.get(KEY_OUTPUT1_RELAY_TYPE)); + _output2RelayType.setValue(config.get(KEY_OUTPUT2_RELAY_TYPE)); + _relay1Type.setValue(config.get(KEY_RELAY1_TYPE)); + _relay2Type.setValue(config.get(KEY_RELAY2_TYPE)); + _relay1Load.setValue(load1); + _relay2Load.setValue(load2); + _output1ResistanceInput.setValue(config.getFloat(KEY_OUTPUT1_RESISTANCE)); + _output1ResistanceInput.setStatus(_output1ResistanceInput.value() ? dash::Status::SUCCESS : dash::Status::DANGER); + _output2ResistanceInput.setValue(config.getFloat(KEY_OUTPUT2_RESISTANCE)); + _output2ResistanceInput.setStatus(_output2ResistanceInput.value() ? dash::Status::SUCCESS : dash::Status::DANGER); + _output1DimmerMapper.setValue({static_cast<uint8_t>(config.getInt(KEY_OUTPUT1_DIMMER_MIN)), + static_cast<uint8_t>(config.getInt(KEY_OUTPUT1_DIMMER_MAX))}); + _output2DimmerMapper.setValue({static_cast<uint8_t>(config.getInt(KEY_OUTPUT2_DIMMER_MIN)), + static_cast<uint8_t>(config.getInt(KEY_OUTPUT2_DIMMER_MAX))}); _displayType.setDisplay(config.getBool(KEY_ENABLE_DISPLAY)); _displaySpeed.setDisplay(config.getBool(KEY_ENABLE_DISPLAY)); _displayRotation.setDisplay(config.getBool(KEY_ENABLE_DISPLAY)); @@ -994,52 +1084,52 @@ void YaSolR::Website::initCards() { // PID const bool pidViewEnabled = config.getBool(KEY_ENABLE_PID_VIEW); - _pidView.update(pidViewEnabled); - switch (config.getLong(KEY_PID_P_MODE)) { + _pidView.setValue(pidViewEnabled); + switch (config.getInt(KEY_PID_P_MODE)) { case 1: - _pidPMode.update(YASOLR_PID_P_MODE_1, YASOLR_PID_P_MODE_1 "," YASOLR_PID_P_MODE_2 "," YASOLR_PID_P_MODE_3); + _pidPMode.setValue(YASOLR_PID_P_MODE_1); break; case 2: - _pidPMode.update(YASOLR_PID_P_MODE_2, YASOLR_PID_P_MODE_1 "," YASOLR_PID_P_MODE_2 "," YASOLR_PID_P_MODE_3); + _pidPMode.setValue(YASOLR_PID_P_MODE_2); break; case 3: - _pidPMode.update(YASOLR_PID_P_MODE_3, YASOLR_PID_P_MODE_1 "," YASOLR_PID_P_MODE_2 "," YASOLR_PID_P_MODE_3); + _pidPMode.setValue(YASOLR_PID_P_MODE_3); break; default: - _pidPMode.update("", YASOLR_PID_P_MODE_1 "," YASOLR_PID_P_MODE_2 "," YASOLR_PID_P_MODE_3); + _pidPMode.setValue(""); break; } - switch (config.getLong(KEY_PID_D_MODE)) { + switch (config.getInt(KEY_PID_D_MODE)) { case 1: - _pidDMode.update(YASOLR_PID_D_MODE_1, YASOLR_PID_D_MODE_1 "," YASOLR_PID_D_MODE_2); + _pidDMode.setValue(YASOLR_PID_D_MODE_1); break; case 2: - _pidDMode.update(YASOLR_PID_D_MODE_2, YASOLR_PID_D_MODE_1 "," YASOLR_PID_D_MODE_2); + _pidDMode.setValue(YASOLR_PID_D_MODE_2); break; default: - _pidDMode.update("", YASOLR_PID_D_MODE_1 "," YASOLR_PID_D_MODE_2); + _pidDMode.setValue(""); break; } - switch (config.getLong(KEY_PID_IC_MODE)) { + switch (config.getInt(KEY_PID_IC_MODE)) { case 0: - _pidICMode.update(YASOLR_PID_IC_MODE_0, YASOLR_PID_IC_MODE_0 "," YASOLR_PID_IC_MODE_1 "," YASOLR_PID_IC_MODE_2); + _pidICMode.setValue(YASOLR_PID_IC_MODE_0); break; case 1: - _pidICMode.update(YASOLR_PID_IC_MODE_1, YASOLR_PID_IC_MODE_0 "," YASOLR_PID_IC_MODE_1 "," YASOLR_PID_IC_MODE_2); + _pidICMode.setValue(YASOLR_PID_IC_MODE_1); break; case 2: - _pidICMode.update(YASOLR_PID_IC_MODE_2, YASOLR_PID_IC_MODE_0 "," YASOLR_PID_IC_MODE_1 "," YASOLR_PID_IC_MODE_2); + _pidICMode.setValue(YASOLR_PID_IC_MODE_2); break; default: - _pidICMode.update("", YASOLR_PID_IC_MODE_0 "," YASOLR_PID_IC_MODE_1 "," YASOLR_PID_IC_MODE_2); + _pidICMode.setValue(""); break; } - _pidSetpoint.update(config.get(KEY_PID_SETPOINT)); - _pidKp.update(config.get(KEY_PID_KP)); - _pidKi.update(config.get(KEY_PID_KI)); - _pidKd.update(config.get(KEY_PID_KD)); - _pidOutMin.update(config.get(KEY_PID_OUT_MIN)); - _pidOutMax.update(config.get(KEY_PID_OUT_MAX)); + _pidSetpoint.setValue(config.getInt(KEY_PID_SETPOINT)); + _pidKp.setValue(config.getFloat(KEY_PID_KP)); + _pidKi.setValue(config.getFloat(KEY_PID_KI)); + _pidKd.setValue(config.getFloat(KEY_PID_KD)); + _pidOutMin.setValue(config.getInt(KEY_PID_OUT_MIN)); + _pidOutMax.setValue(config.getInt(KEY_PID_OUT_MAX)); _pidInputHistory.setDisplay(pidViewEnabled); _pidOutputHistory.setDisplay(pidViewEnabled); @@ -1067,133 +1157,125 @@ void YaSolR::Website::updateCards() { // stats Mycila::System::Memory memory; Mycila::System::getMemory(memory); - Mycila::ESPConnect::Mode mode = espConnect.getMode(); - _output1RelaySwitchCount.set(std::to_string(bypassRelayO1.getSwitchCount())); - _output2RelaySwitchCount.set(std::to_string(bypassRelayO2.getSwitchCount())); - _deviceHeapTotal.set(std::to_string(memory.total) + " bytes"); - _deviceHeapUsed.set(std::to_string(memory.used) + " bytes"); - _deviceHeapUsage.set(Mycila::string::to_string(memory.usage, 2) + " %"); - _gridEnergy.set(Mycila::string::to_string(gridMetrics.energy, 3) + " kWh"); - _gridEnergyReturned.set(Mycila::string::to_string(gridMetrics.energyReturned, 3) + " kWh"); - _gridFrequency.set(Mycila::string::to_string(detectGridFrequency(), 0) + " Hz"); - _networkAPIP.set(espConnect.getIPAddress(Mycila::ESPConnect::Mode::AP).toString().c_str()); - _networkEthIP.set(espConnect.getIPAddress(Mycila::ESPConnect::Mode::ETH).toString().c_str()); - _networkInterface.set(mode == Mycila::ESPConnect::Mode::AP ? "AP" : (mode == Mycila::ESPConnect::Mode::STA ? "WiFi" : (mode == Mycila::ESPConnect::Mode::ETH ? "Ethernet" : ""))); - _networkWiFiIP.set(espConnect.getIPAddress(Mycila::ESPConnect::Mode::STA).toString().c_str()); - _networkWiFiRSSI.set(std::to_string(espConnect.getWiFiRSSI()) + " dBm"); - _networkWiFiSignal.set(std::to_string(espConnect.getWiFiSignalQuality()) + " %"); - _networkWiFiSSID.set(espConnect.getWiFiSSID()); - _relay1SwitchCount.set(std::to_string(relay1.getSwitchCount())); - _relay2SwitchCount.set(std::to_string(relay2.getSwitchCount())); - _udpMessageRateBuffer.set(Mycila::string::to_string(udpMessageRateBuffer.rate(), 2) + " msg/s"); - _time.set(Mycila::Time::getLocalStr()); - _uptime.set(Mycila::Time::toDHHMMSS(Mycila::System::getUptime())); + _output1RelaySwitchCount.setValue(bypassRelayO1.getSwitchCount()); + _output2RelaySwitchCount.setValue(bypassRelayO2.getSwitchCount()); + _deviceHeapTotal.setValue(memory.total); + _deviceHeapUsed.setValue(memory.used); + _deviceHeapUsage.setValue(memory.usage); + _gridEnergy.setValue(gridMetrics.energy); + _gridEnergyReturned.setValue(gridMetrics.energyReturned); + _gridFrequency.setValue(detectGridFrequency()); + _networkWiFiRSSI.setValue(espConnect.getWiFiRSSI()); + _networkWiFiSignal.setValue(espConnect.getWiFiSignalQuality()); + _relay1SwitchCount.setValue(relay1.getSwitchCount()); + _relay2SwitchCount.setValue(relay2.getSwitchCount()); + _udpMessageRateBuffer.setValue(udpMessageRateBuffer.rate()); + _time.setValue(Mycila::Time::getLocalStr()); + _uptime.setValue(Mycila::Time::toDHHMMSS(Mycila::System::getUptime())); #ifdef APP_MODEL_TRIAL - _trialRemainingTime.set(Mycila::Time::toDHHMMSS(Mycila::Trial.getRemaining())); + _trialRemainingTime.setValue(Mycila::Time::toDHHMMSS(Mycila::Trial.getRemaining())); #endif // home - _routerPower.update(routerMetrics.power); - _routerApparentPower.update(routerMetrics.apparentPower); - _routerPowerFactor.update(routerMetrics.powerFactor); - _routerTHDi.update(routerMetrics.thdi * 100); - _routerVoltage.update(gridMetrics.voltage); - _routerCurrent.update(routerMetrics.current); - _routerResistance.update(routerMetrics.resistance); - _routerEnergy.update(routerMetrics.energy); - - _gridPower.update(gridMetrics.power); - _temperature(_routerDS18State, ds18Sys); + _routerPower.setValue(routerMetrics.power); + _routerApparentPower.setValue(routerMetrics.apparentPower); + _routerPowerFactor.setValue(routerMetrics.powerFactor); + _routerTHDi.setValue(routerMetrics.thdi * 100); + _routerVoltage.setValue(gridMetrics.voltage); + _routerCurrent.setValue(routerMetrics.current); + _routerResistance.setValue(routerMetrics.resistance); + _routerEnergy.setValue(routerMetrics.energy); + _gridPower.setValue(gridMetrics.power); + _routerDS18State.setValue(ds18Sys.getTemperature().value_or(0.0f)); // output 1 switch (output1.getState()) { case Mycila::RouterOutput::State::OUTPUT_DISABLED: case Mycila::RouterOutput::State::OUTPUT_IDLE: - _output1State.update(output1.getStateName(), DASH_STATUS_IDLE); + _output1State.setFeedback(output1.getStateName(), dash::Status::IDLE); break; case Mycila::RouterOutput::State::OUTPUT_BYPASS_AUTO: case Mycila::RouterOutput::State::OUTPUT_BYPASS_MANUAL: - _output1State.update(output1.getStateName(), DASH_STATUS_WARNING); + _output1State.setFeedback(output1.getStateName(), dash::Status::WARNING); break; case Mycila::RouterOutput::State::OUTPUT_ROUTING: - _output1State.update(output1.getStateName(), DASH_STATUS_SUCCESS); + _output1State.setFeedback(output1.getStateName(), dash::Status::SUCCESS); break; default: - _output1State.update(YASOLR_LBL_109, DASH_STATUS_DANGER); + _output1State.setFeedback(YASOLR_LBL_109, dash::Status::DANGER); break; } - _temperature(_output1DS18State, output1); - _output1DimmerSlider.update(dimmerO1.getDutyCycle() * 100); - _output1Bypass.update(output1.isBypassOn()); + _output1DS18State.setValue(output1.temperature().orElse(0.0f)); + _output1DimmerSlider.setValue(dimmerO1.getDutyCycle() * 100); + _output1Bypass.setValue(output1.isBypassOn()); // output 2 switch (output2.getState()) { case Mycila::RouterOutput::State::OUTPUT_DISABLED: case Mycila::RouterOutput::State::OUTPUT_IDLE: - _output2State.update(output2.getStateName(), DASH_STATUS_IDLE); + _output2State.setFeedback(output2.getStateName(), dash::Status::IDLE); break; case Mycila::RouterOutput::State::OUTPUT_BYPASS_AUTO: case Mycila::RouterOutput::State::OUTPUT_BYPASS_MANUAL: - _output2State.update(output2.getStateName(), DASH_STATUS_WARNING); + _output2State.setFeedback(output2.getStateName(), dash::Status::WARNING); break; case Mycila::RouterOutput::State::OUTPUT_ROUTING: - _output2State.update(output2.getStateName(), DASH_STATUS_SUCCESS); + _output2State.setFeedback(output2.getStateName(), dash::Status::SUCCESS); break; default: - _output2State.update(YASOLR_LBL_109, DASH_STATUS_DANGER); + _output2State.setFeedback(YASOLR_LBL_109, dash::Status::DANGER); break; } - _temperature(_output2DS18State, output2); - _output2DimmerSlider.update(dimmerO2.getDutyCycle() * 100); - _output2Bypass.update(output2.isBypassOn()); + _output2DS18State.setValue(output2.temperature().orElse(0.0f)); + _output2DimmerSlider.setValue(dimmerO2.getDutyCycle() * 100); + _output2Bypass.setValue(output2.isBypassOn()); // relay - _relay1Switch.update(relay1.isOn()); - _relay2Switch.update(relay2.isOn()); + _relay1Switch.setValue(relay1.isOn()); + _relay2Switch.setValue(relay2.isOn()); // Hardware (config) - _output1PZEMSync.update(!pzemO1PairingTask.isPaused()); - _output2PZEMSync.update(!pzemO2PairingTask.isPaused()); - _resistanceCalibration.update(router.isCalibrationRunning()); + _output1PZEMSync.setValue(!pzemO1PairingTask.isPaused()); + _output2PZEMSync.setValue(!pzemO2PairingTask.isPaused()); + _resistanceCalibration.setValue(router.isCalibrationRunning()); #ifdef APP_MODEL_PRO // Output 1 - _output1DimmerSliderRO.update(dimmerO1.getDutyCycle() * 100); - _output1BypassRO.update(YASOLR_STATE(output1.isBypassOn()), output1.isBypassOn() ? DASH_STATUS_SUCCESS : DASH_STATUS_IDLE); - _output1Power.update(output1Measurements.power); - _output1ApparentPower.update(output1Measurements.apparentPower); - _output1PowerFactor.update(output1Measurements.powerFactor); - _output1THDi.update(output1Measurements.thdi * 100); - _output1Voltage.update(output1Measurements.dimmedVoltage); - _output1Current.update(output1Measurements.current); - _output1Resistance.update(output1Measurements.resistance); - _output1Energy.update(output1Measurements.energy); + _output1DimmerSliderRO.setValue(dimmerO1.getDutyCycle() * 100); + _output1BypassRO.setFeedback(YASOLR_STATE(output1.isBypassOn()), output1.isBypassOn() ? dash::Status::SUCCESS : dash::Status::IDLE); + _output1Power.setValue(output1Measurements.power); + _output1ApparentPower.setValue(output1Measurements.apparentPower); + _output1PowerFactor.setValue(output1Measurements.powerFactor); + _output1THDi.setValue(output1Measurements.thdi * 100); + _output1Voltage.setValue(output1Measurements.dimmedVoltage); + _output1Current.setValue(output1Measurements.current); + _output1Resistance.setValue(output1Measurements.resistance); + _output1Energy.setValue(output1Measurements.energy); // output 2 - _output2DimmerSliderRO.update(dimmerO2.getDutyCycle() * 100); - _output2BypassRO.update(YASOLR_STATE(output2.isBypassOn()), output2.isBypassOn() ? DASH_STATUS_SUCCESS : DASH_STATUS_IDLE); - _output2Power.update(output2Measurements.power); - _output2ApparentPower.update(output2Measurements.apparentPower); - _output2PowerFactor.update(output2Measurements.powerFactor); - _output2THDi.update(output2Measurements.thdi * 100); - _output2Voltage.update(output2Measurements.dimmedVoltage); - _output2Current.update(output2Measurements.current); - _output2Resistance.update(output2Measurements.resistance); - _output2Energy.update(output2Measurements.energy); + _output2DimmerSliderRO.setValue(dimmerO2.getDutyCycle() * 100); + _output2BypassRO.setFeedback(YASOLR_STATE(output2.isBypassOn()), output2.isBypassOn() ? dash::Status::SUCCESS : dash::Status::IDLE); + _output2Power.setValue(output2Measurements.power); + _output2ApparentPower.setValue(output2Measurements.apparentPower); + _output2PowerFactor.setValue(output2Measurements.powerFactor); + _output2THDi.setValue(output2Measurements.thdi * 100); + _output2Voltage.setValue(output2Measurements.dimmedVoltage); + _output2Current.setValue(output2Measurements.current); + _output2Resistance.setValue(output2Measurements.resistance); + _output2Energy.setValue(output2Measurements.energy); // relays - _relay1SwitchRO.update(YASOLR_STATE(relay1.isOn()), relay1.isOn() ? DASH_STATUS_SUCCESS : DASH_STATUS_IDLE); - _relay2SwitchRO.update(YASOLR_STATE(relay2.isOn()), relay2.isOn() ? DASH_STATUS_SUCCESS : DASH_STATUS_IDLE); + _relay1SwitchRO.setFeedback(YASOLR_STATE(relay1.isOn()), relay1.isOn() ? dash::Status::SUCCESS : dash::Status::IDLE); - // Hardware (status) + // Hardware _status(_jsy, KEY_ENABLE_JSY, jsy.isEnabled(), jsy.isConnected(), YASOLR_LBL_110); _status(_mqtt, KEY_ENABLE_MQTT, mqtt.isEnabled(), mqtt.isConnected(), mqtt.getLastError() ? mqtt.getLastError() : YASOLR_LBL_113); @@ -1228,9 +1310,9 @@ void YaSolR::Website::updateCharts() { _routerTHDiHistoryY[YASOLR_GRAPH_POINTS - 1] = round(routerMetrics.thdi * 100); // update charts - _gridPowerHistory.updateY(_gridPowerHistoryY, YASOLR_GRAPH_POINTS); - _routedPowerHistory.updateY(_routedPowerHistoryY, YASOLR_GRAPH_POINTS); - _routerTHDiHistory.updateY(_routerTHDiHistoryY, YASOLR_GRAPH_POINTS); + _gridPowerHistory.setY(_gridPowerHistoryY, YASOLR_GRAPH_POINTS); + _routedPowerHistory.setY(_routedPowerHistoryY, YASOLR_GRAPH_POINTS); + _routerTHDiHistory.setY(_routerTHDiHistoryY, YASOLR_GRAPH_POINTS); } void YaSolR::Website::updatePID() { @@ -1255,13 +1337,13 @@ void YaSolR::Website::updatePID() { _pidDTermHistoryY[YASOLR_GRAPH_POINTS - 1] = round(pidController.getDTerm()); // update charts - _pidInputHistory.updateY(_pidInputHistoryY, YASOLR_GRAPH_POINTS); - _pidOutputHistory.updateY(_pidOutputHistoryY, YASOLR_GRAPH_POINTS); - _pidErrorHistory.updateY(_pidErrorHistoryY, YASOLR_GRAPH_POINTS); - _pidSumHistory.updateY(_pidSumHistoryY, YASOLR_GRAPH_POINTS); - _pidPTermHistory.updateY(_pidPTermHistoryY, YASOLR_GRAPH_POINTS); - _pidITermHistory.updateY(_pidITermHistoryY, YASOLR_GRAPH_POINTS); - _pidDTermHistory.updateY(_pidDTermHistoryY, YASOLR_GRAPH_POINTS); + _pidInputHistory.setY(_pidInputHistoryY, YASOLR_GRAPH_POINTS); + _pidOutputHistory.setY(_pidOutputHistoryY, YASOLR_GRAPH_POINTS); + _pidErrorHistory.setY(_pidErrorHistoryY, YASOLR_GRAPH_POINTS); + _pidSumHistory.setY(_pidSumHistoryY, YASOLR_GRAPH_POINTS); + _pidPTermHistory.setY(_pidPTermHistoryY, YASOLR_GRAPH_POINTS); + _pidITermHistory.setY(_pidITermHistoryY, YASOLR_GRAPH_POINTS); + _pidDTermHistory.setY(_pidDTermHistoryY, YASOLR_GRAPH_POINTS); #endif } @@ -1276,183 +1358,3 @@ void YaSolR::Website::resetPID() { memset(_pidDTermHistoryY, 0, sizeof(_pidDTermHistoryY)); #endif } - -void YaSolR::Website::_sliderConfig(Card& card, const char* key) { - card.attachCallback([key, &card](int value) { - config.set(key, std::to_string(value)); - card.update(config.getInt(key)); - dashboard.refreshCard(&card); - }); -} - -void YaSolR::Website::_percentageSlider(Card& card, const char* key) { - card.attachCallback([key, &card](int value) { - config.set(key, std::to_string(value)); - card.update(value); - dashboard.refreshCard(&card); - }); -} - -void YaSolR::Website::_floatConfig(Card& card, const char* key) { -#ifdef APP_MODEL_PRO - card.attachCallback([key, &card](const char* value) { - if (value[0]) { - config.set(key, value); - } else { - config.unset(key); - } - card.update(config.get(key)); - dashboard.refreshCard(&card); - }); -#endif -} - -void YaSolR::Website::_numConfig(Card& card, const char* key) { -#ifdef APP_MODEL_PRO - card.attachCallback([key, &card](const char* value) { - if (value[0]) { - config.set(key, std::to_string(strtol(value, nullptr, 10))); - } else { - config.unset(key); - } - card.update(config.getInt(key)); - dashboard.refreshCard(&card); - }); -#endif -} - -void YaSolR::Website::_pinConfig(Card& card, const char* key) { -#ifdef APP_MODEL_PRO - card.attachCallback([key, &card, this](const char* value) { - if (value[0]) { - config.set(key, std::to_string(strtol(value, nullptr, 10))); - } else { - config.unset(key); - } - dashboard.refreshCard(&card); - }); -#endif -} - -void YaSolR::Website::_boolConfig(Card& card, const char* key) { - card.attachCallback([key, &card, this](int value) { - config.setBool(key, value); - card.update(config.getBool(key) ? 1 : 0); - dashboard.refreshCard(&card); - }); -} - -void YaSolR::Website::_textConfig(Card& card, const char* key) { -#ifdef APP_MODEL_PRO - card.attachCallback([key, &card](const char* value) { - config.set(key, value); - card.update(config.get(key)); - dashboard.refreshCard(&card); - }); -#endif -} - -void YaSolR::Website::_daysConfig(Card& card, const char* key) { -#ifdef APP_MODEL_PRO - card.attachCallback([key, &card, this](const char* value) { - config.set(key, value[0] ? value : "none"); - card.update(config.get(key)); - dashboard.refreshCard(&card); - }); -#endif -} - -void YaSolR::Website::_passwordConfig(Card& card, const char* key) { -#ifdef APP_MODEL_PRO - card.attachCallback([key, &card, this](const char* value) { - if (value[0]) { - config.set(key, value); - } else { - config.unset(key); - } - card.update(config.isEmpty(key) ? "" : HIDDEN_PWD); - dashboard.refreshCard(&card); - }); -#endif -} - -void YaSolR::Website::_relaySwitch(Card& card, Mycila::RouterRelay& relay) { - card.attachCallback([&card, &relay, this](int value) { - relay.tryRelayState(value); - card.update(relay.isOn()); - dashboard.refreshCard(&card); - }); -} - -void YaSolR::Website::_outputBypassSwitch(Card& card, Mycila::RouterOutput& output) { - card.attachCallback([&card, &output, this](int value) { - if (output.isBypassEnabled()) { - output.setBypass(value); - } - card.update(output.isBypassOn()); - dashboard.refreshCard(&card); - dashboardInitTask.resume(); - }); -} - -void YaSolR::Website::_outputDimmerSlider(Card& card, Mycila::RouterOutput& output) { - card.attachCallbackF([&card, &output, this](float value) { - if (output.isDimmerEnabled()) { - output.setDimmerDutyCycle(value / 100); - } - card.update(output.getDimmerDutyCycle() * 100); - dashboard.refreshCard(&card); - dashboardUpdateTask.requestEarlyRun(); - }); -} - -void YaSolR::Website::_temperature(Card& card, Mycila::DS18& sensor) { - if (!sensor.isEnabled()) { - card.update(YASOLR_LBL_115, ""); - } else if (!sensor.isValid()) { - card.update(YASOLR_LBL_123, ""); - } else { - card.update(sensor.getTemperature().value_or(0), "°C"); - } -} - -void YaSolR::Website::_temperature(Card& card, Mycila::RouterOutput& output) { - if (output.temperature().neverUpdated()) { - card.update(YASOLR_LBL_115, ""); - } else if (output.temperature().isAbsent()) { - card.update(YASOLR_LBL_123, ""); - } else { - card.update(output.temperature().get(), "°C"); - } -} - -void YaSolR::Website::_status(Card& card, const char* key, bool enabled, bool active, const char* err) { - const bool configEnabled = config.getBool(key); - if (!configEnabled) - card.update(config.getBool(key), DASH_STATUS_IDLE "," YASOLR_LBL_115); - else if (!enabled) - card.update(config.getBool(key), DASH_STATUS_DANGER "," YASOLR_LBL_124); - else if (!active) - card.update(config.getBool(key), (std::string(DASH_STATUS_WARNING) + "," + err).c_str()); - else - card.update(config.getBool(key), DASH_STATUS_SUCCESS "," YASOLR_LBL_130); -} - -void YaSolR::Website::_pinout(Card& card, int32_t pin, std::unordered_map<int32_t, Card*>& pinout) { - if (pin == GPIO_NUM_NC) { - card.update(YASOLR_LBL_115, DASH_STATUS_IDLE); - } else if (pinout.find(pin) != pinout.end()) { - std::string v = std::to_string(pin) + " (" YASOLR_LBL_153 ")"; - pinout[pin]->update(v, DASH_STATUS_DANGER); - card.update(v, DASH_STATUS_DANGER); - } else if (!GPIO_IS_VALID_GPIO(pin)) { - pinout[pin] = &card; - card.update(std::to_string(pin) + " (" YASOLR_LBL_154 ")", DASH_STATUS_DANGER); - } else if (!GPIO_IS_VALID_OUTPUT_GPIO(pin)) { - pinout[pin] = &card; - card.update(std::to_string(pin) + " (" YASOLR_LBL_155 ")", DASH_STATUS_WARNING); - } else { - pinout[pin] = &card; - card.update(std::to_string(pin) + " (" YASOLR_LBL_156 ")", DASH_STATUS_SUCCESS); - } -} diff --git a/src/main.cpp b/src/main.cpp index a4a5fd9d..d591e64c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -52,7 +52,7 @@ AsyncWebServer webServer(80); AsyncWebSocket wsDebugPID("/ws/pid/csv"); AuthenticationMiddleware authMiddleware; LoggingMiddleware loggingMiddleware; -ESPDash dashboard = ESPDash(&webServer, "/dashboard", false); +ESPDash dashboard = ESPDash(webServer, "/dashboard", false); Mycila::ESPConnect espConnect(webServer); void setup() {